├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── trustwallet
│ │ │ │ └── walletconnect
│ │ │ │ └── sample
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ └── test
│ │ └── java
│ │ └── com
│ │ └── trustwallet
│ │ └── walletconnect
│ │ └── sample
│ │ └── ExampleUnitTest.kt
├── proguard-rules.pro
└── build.gradle
├── walletconnect
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── trustwallet
│ │ │ └── walletconnect
│ │ │ ├── models
│ │ │ ├── WCAccount.kt
│ │ │ ├── WCSignTransaction.kt
│ │ │ ├── WCEncryptionPayload.kt
│ │ │ ├── WCSocketMessage.kt
│ │ │ ├── session
│ │ │ │ ├── WCSessionUpdate.kt
│ │ │ │ ├── WCSessionRequest.kt
│ │ │ │ ├── WCApproveSessionResponse.kt
│ │ │ │ └── WCSession.kt
│ │ │ ├── MessageType.kt
│ │ │ ├── WCPeerMeta.kt
│ │ │ ├── ethereum
│ │ │ │ ├── WCEthereumTransaction.kt
│ │ │ │ └── WCEthereumSignMessage.kt
│ │ │ ├── okexchain
│ │ │ │ └── WCOKExChainTransaction.kt
│ │ │ ├── binance
│ │ │ │ ├── WCBinanceOrder.kt
│ │ │ │ ├── WCBinanceTradePair.kt
│ │ │ │ ├── WCBinanceCancelOrder.kt
│ │ │ │ ├── WCBinanceTransferOrder.kt
│ │ │ │ └── WCBinanceTradeOrder.kt
│ │ │ └── WCMethod.kt
│ │ │ ├── exceptions
│ │ │ ├── InvalidMessageException.kt
│ │ │ ├── InvalidSessionException.kt
│ │ │ ├── InvalidUriException.kt
│ │ │ ├── InvalidPayloadException.kt
│ │ │ ├── InvalidHmacException.kt
│ │ │ ├── InvalidJsonRpcParamsException.kt
│ │ │ └── RequiredFieldException.kt
│ │ │ ├── jsonrpc
│ │ │ ├── JsonRpcRequest.kt
│ │ │ ├── JsonRpcResponse.kt
│ │ │ └── JsonRpcError.kt
│ │ │ ├── extensions
│ │ │ ├── ByteArray.kt
│ │ │ └── String.kt
│ │ │ ├── WCSessionStore.kt
│ │ │ ├── WCSessionStoreType.kt
│ │ │ ├── WCCipher.kt
│ │ │ └── WCClient.kt
│ └── test
│ │ └── java
│ │ └── com
│ │ └── trustwallet
│ │ └── walletconnect
│ │ ├── models
│ │ ├── binance
│ │ │ ├── WCBinanceTradePairTests.kt
│ │ │ └── WCBinanceOrderTests.kt
│ │ └── WCSessionTests.kt
│ │ ├── WCSessionStoreTests.kt
│ │ └── WCCipherTests.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── runConfigurations.xml
└── gradle.xml
├── gradle.properties
├── gradlew.bat
├── .gitignore
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/walletconnect/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':walletconnect'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WalletConnect
3 |
4 |
--------------------------------------------------------------------------------
/walletconnect/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WalletConnect
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/walletconnect/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WalletConnect/wallet-connect-kotlin/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/WCAccount.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | data class WCAccount(
4 | val network: Int,
5 | val address: String
6 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/WCSignTransaction.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | data class WCSignTransaction(
4 | val network: Int,
5 | val transaction: String
6 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/InvalidMessageException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import java.lang.Exception
4 |
5 | class InvalidMessageException : Exception("Invalid message")
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/InvalidSessionException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import java.lang.Exception
4 |
5 | class InvalidSessionException : Exception("Invalid session")
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/InvalidUriException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import java.lang.Exception
4 |
5 | class InvalidUriException : Exception("Invalid Wallet Connect URI")
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/WCEncryptionPayload.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | data class WCEncryptionPayload(
4 | val data: String,
5 | val hmac: String,
6 | val iv: String
7 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/WCSocketMessage.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | data class WCSocketMessage(
4 | val topic: String,
5 | val type: MessageType,
6 | val payload: String
7 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/InvalidPayloadException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import java.lang.Exception
4 |
5 | class InvalidPayloadException : Exception("Invalid WCEncryptionPayload")
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/InvalidHmacException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import java.lang.Exception
4 |
5 | class InvalidHmacException : Exception("Received and computed HMAC doesn't mach")
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/session/WCSessionUpdate.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.session
2 |
3 | data class WCSessionUpdate(
4 | val approved: Boolean,
5 | val chainId: Int?,
6 | val accounts: List?
7 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/MessageType.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | enum class MessageType {
6 | @SerializedName("pub") PUB,
7 | @SerializedName("sub") SUB
8 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Nov 11 12:09:22 BRT 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/InvalidJsonRpcParamsException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import java.lang.Exception
4 |
5 | class InvalidJsonRpcParamsException(val requestId: Long) : Exception("Invalid JSON RPC Request")
6 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/WCPeerMeta.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | data class WCPeerMeta (
4 | val name: String,
5 | val url: String,
6 | val description: String? = null,
7 | val icons: List = listOf("")
8 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/exceptions/RequiredFieldException.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.exceptions
2 |
3 | import com.google.gson.JsonParseException
4 |
5 | class RequiredFieldException(val field: String = "") : JsonParseException("'$field' is required")
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/session/WCSessionRequest.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.session
2 |
3 | import com.trustwallet.walletconnect.models.WCPeerMeta
4 |
5 | data class WCSessionRequest(
6 | val peerId: String,
7 | val peerMeta: WCPeerMeta,
8 | val chainId: String?
9 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/ethereum/WCEthereumTransaction.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.ethereum
2 |
3 | data class WCEthereumTransaction(
4 | val from: String,
5 | val to: String?,
6 | val nonce: String?,
7 | val gasPrice: String?,
8 | val gasLimit: String?,
9 | val value: String?,
10 | val data: String
11 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/jsonrpc/JsonRpcRequest.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.jsonrpc
2 |
3 | import com.trustwallet.walletconnect.JSONRPC_VERSION
4 | import com.trustwallet.walletconnect.models.WCMethod
5 |
6 | data class JsonRpcRequest(
7 | val id: Long,
8 | val jsonrpc: String = JSONRPC_VERSION,
9 | val method: WCMethod?,
10 | val params: T
11 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/session/WCApproveSessionResponse.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.session
2 |
3 | import com.trustwallet.walletconnect.models.WCPeerMeta
4 |
5 | data class WCApproveSessionResponse(
6 | val approved: Boolean = true,
7 | val chainId: Int,
8 | val accounts: List,
9 | val peerId: String?,
10 | val peerMeta: WCPeerMeta?
11 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/trustwallet/walletconnect/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.sample
2 |
3 | import android.support.v7.app.AppCompatActivity
4 | import android.os.Bundle
5 |
6 | class MainActivity : AppCompatActivity() {
7 |
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setContentView(R.layout.activity_main)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/jsonrpc/JsonRpcResponse.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.jsonrpc
2 |
3 | import com.trustwallet.walletconnect.JSONRPC_VERSION
4 |
5 | data class JsonRpcResponse (
6 | val jsonrpc: String = JSONRPC_VERSION,
7 | val id: Long,
8 | val result: T
9 | )
10 |
11 | data class JsonRpcErrorResponse (
12 | val jsonrpc: String = JSONRPC_VERSION,
13 | val id: Long,
14 | val error: JsonRpcError
15 | )
--------------------------------------------------------------------------------
/app/src/test/java/com/trustwallet/walletconnect/sample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.sample
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/okexchain/WCOKExChainTransaction.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.okexchain
2 |
3 | data class WCOKExChainTransaction(
4 | val from: String,
5 | val to: String?,
6 | val value: String?,
7 | val gasLimit: String?,
8 | val gasPrice: String?,
9 | val accountNumber: String?,
10 | val sequenceNumber: String?,
11 | val symbol: String?,
12 | val contractAddress: String?,
13 | val data: String?
14 | )
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/extensions/ByteArray.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.extensions
2 |
3 | private val HEX_CHARS = "0123456789abcdef".toCharArray()
4 |
5 | fun ByteArray.toHex() : String{
6 | val result = StringBuffer()
7 |
8 | forEach {
9 | val octet = it.toInt()
10 | val firstIndex = (octet and 0xF0).ushr(4)
11 | val secondIndex = octet and 0x0F
12 | result.append(HEX_CHARS[firstIndex])
13 | result.append(HEX_CHARS[secondIndex])
14 | }
15 |
16 | return result.toString()
17 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/WCSessionStore.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect
2 |
3 | import com.trustwallet.walletconnect.models.WCPeerMeta
4 | import com.trustwallet.walletconnect.models.session.WCSession
5 | import java.util.*
6 |
7 | data class WCSessionStoreItem(
8 | val session: WCSession,
9 | val peerId: String,
10 | val remotePeerId: String,
11 | val remotePeerMeta: WCPeerMeta,
12 | val isAutoSign: Boolean = false,
13 | val date: Date = Date()
14 | )
15 |
16 | interface WCSessionStore {
17 | var session: WCSessionStoreItem?
18 | }
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/extensions/String.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.extensions
2 |
3 | private val HEX_CHARS = "0123456789abcdef"
4 |
5 | fun String.hexStringToByteArray() : ByteArray {
6 | val hex = toLowerCase()
7 | val result = ByteArray(length / 2)
8 |
9 | for (i in 0 until hex.length step 2) {
10 | val firstIndex = HEX_CHARS.indexOf(hex[i])
11 | val secondIndex = HEX_CHARS.indexOf(hex[i + 1])
12 |
13 | val octet = firstIndex.shl(4).or(secondIndex)
14 | result.set(i.shr(1), octet.toByte())
15 | }
16 |
17 | return result
18 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/binance/WCBinanceOrder.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | open class WCBinanceOrder(
6 | @SerializedName("account_number")
7 | val accountNumber: String,
8 | @SerializedName("chain_id")
9 | val chainId: String,
10 | val data: String?,
11 | val memo: String?,
12 | val sequence: String,
13 | val source: String,
14 | val msgs: List
15 | )
16 |
17 | data class WCBinanceTxConfirmParam(
18 | val ok: Boolean,
19 | val errorMsg: String?
20 | )
21 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/jsonrpc/JsonRpcError.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.jsonrpc
2 |
3 | data class JsonRpcError (
4 | val code: Int,
5 | val message: String
6 | ) {
7 | companion object {
8 | fun serverError(message: String) = JsonRpcError(-32000, message)
9 | fun invalidParams(message: String) = JsonRpcError(-32602, message)
10 | fun invalidRequest(message: String) = JsonRpcError(-32600, message)
11 | fun parseError(message: String) = JsonRpcError(-32700, message)
12 | fun methodNotFound(message: String) = JsonRpcError(-32601, message)
13 | }
14 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/binance/WCBinanceTradePair.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | data class WCBinanceTradePair(val from: String, val to: String) {
4 | companion object {
5 | fun from(symbol: String): WCBinanceTradePair? {
6 | val pair = symbol.split("_")
7 |
8 | return if (pair.size > 1) {
9 | val firstParts = pair[0].split("-")
10 | val secondParts = pair[1].split("-")
11 | WCBinanceTradePair(firstParts[0], secondParts[0])
12 | } else {
13 | null
14 | }
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/walletconnect/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # Kotlin code style for this project: "official" or "obsolete":
15 | kotlin.code.style=official
16 |
--------------------------------------------------------------------------------
/walletconnect/src/test/java/com/trustwallet/walletconnect/models/binance/WCBinanceTradePairTests.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | class WCBinanceTradePairTests {
7 | @Test
8 | fun test_parse() {
9 | val symbol = "BNB_ETH.B-261"
10 | val pair = WCBinanceTradePair.from(symbol)
11 |
12 | assertEquals(pair?.from, "BNB")
13 | assertEquals(pair?.to, "ETH.B")
14 |
15 | val symbol2 = "000-0E1_BNB"
16 | val pair2 = WCBinanceTradePair.from(symbol2)
17 |
18 | assertEquals(pair2?.from, "000")
19 | assertEquals(pair2?.to, "BNB")
20 |
21 | val symbol3 = "CRYPRICE-150_BTC.B-918"
22 | val pair3 = WCBinanceTradePair.from(symbol3)
23 |
24 | assertEquals(pair3?.from, "CRYPRICE")
25 | assertEquals(pair3?.to, "BTC.B")
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/ethereum/WCEthereumSignMessage.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.ethereum
2 |
3 | data class WCEthereumSignMessage (
4 | val raw: List,
5 | val type: WCSignType
6 | ) {
7 | enum class WCSignType {
8 | MESSAGE, PERSONAL_MESSAGE, TYPED_MESSAGE
9 | }
10 |
11 | /**
12 | * Raw parameters will always be the message and the addess. Depending on the WCSignType,
13 | * those parameters can be swapped as description below:
14 | *
15 | * - MESSAGE: `[address, data ]`
16 | * - TYPED_MESSAGE: `[address, data]`
17 | * - PERSONAL_MESSAGE: `[data, address]`
18 | *
19 | * reference: https://docs.walletconnect.org/json-rpc/ethereum#eth_signtypeddata
20 | */
21 | val data get() = when (type) {
22 | WCSignType.MESSAGE -> raw[1]
23 | WCSignType.TYPED_MESSAGE -> raw[1]
24 | WCSignType.PERSONAL_MESSAGE -> raw[0]
25 | }
26 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/session/WCSession.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.session
2 |
3 | import android.net.Uri
4 |
5 | data class WCSession (
6 | val topic: String,
7 | val version: String,
8 | val bridge: String,
9 | val key: String
10 | ) {
11 | fun toUri(): String = "wc:${topic}@${version}?bridge=${bridge}&key=${key}"
12 |
13 | companion object {
14 | fun from(from: String): WCSession? {
15 | if (!from.startsWith("wc:")) {
16 | return null
17 | }
18 |
19 | val uriString = from.replace("wc:", "wc://")
20 | val uri = Uri.parse(uriString)
21 | val bridge = uri.getQueryParameter("bridge")
22 | val key = uri.getQueryParameter("key")
23 | val topic = uri.userInfo
24 | val version = uri.host
25 |
26 | if (bridge == null || key == null || topic == null || version == null) {
27 | return null
28 | }
29 |
30 | return WCSession(topic, version, bridge, key)
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/walletconnect/src/test/java/com/trustwallet/walletconnect/models/WCSessionTests.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | import android.os.Build
4 | import com.trustwallet.walletconnect.models.session.WCSession
5 | import org.junit.Test
6 |
7 | import org.junit.Assert.*
8 | import org.junit.runner.RunWith
9 | import org.robolectric.RobolectricTestRunner
10 | import org.robolectric.annotation.Config
11 |
12 | @RunWith(RobolectricTestRunner::class)
13 | @Config(sdk = [Build.VERSION_CODES.O_MR1])
14 | class WCSessionTests {
15 |
16 | @Test
17 | fun test_from() {
18 | val uri = "wc:217374f6-8735-472d-a743-23bd7d26d106@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=d565a3e6cc792fa789bbea26b3f257fb436cfba2de48d2490b3e0248168d4b6b"
19 | val session = WCSession.from(uri)
20 |
21 | assertEquals("217374f6-8735-472d-a743-23bd7d26d106", session?.topic)
22 | assertEquals("1", session?.version)
23 | assertEquals("https://bridge.walletconnect.org", session?.bridge)
24 | assertEquals("d565a3e6cc792fa789bbea26b3f257fb436cfba2de48d2490b3e0248168d4b6b", session?.key)
25 | }
26 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/WCMethod.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | enum class WCMethod {
6 | @SerializedName("wc_sessionRequest")
7 | SESSION_REQUEST,
8 |
9 | @SerializedName("wc_sessionUpdate")
10 | SESSION_UPDATE,
11 |
12 | @SerializedName("eth_sign")
13 | ETH_SIGN,
14 |
15 | @SerializedName("personal_sign")
16 | ETH_PERSONAL_SIGN,
17 |
18 | @SerializedName("eth_signTypedData")
19 | ETH_SIGN_TYPE_DATA,
20 |
21 | @SerializedName("eth_signTransaction")
22 | ETH_SIGN_TRANSACTION,
23 |
24 | @SerializedName("eth_sendTransaction")
25 | ETH_SEND_TRANSACTION,
26 |
27 | @SerializedName("bnb_sign")
28 | BNB_SIGN,
29 |
30 | @SerializedName("bnb_tx_confirmation")
31 | BNB_TRANSACTION_CONFIRM,
32 |
33 | @SerializedName("get_accounts")
34 | GET_ACCOUNTS,
35 |
36 | @SerializedName("trust_signTransaction")
37 | SIGN_TRANSACTION,
38 |
39 | @SerializedName("okt_signTransaction")
40 | OKT_SIGN_TRANSACTION,
41 |
42 | @SerializedName("okt_sendTransaction")
43 | OKT_SEND_TRANSACTION;
44 |
45 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/WCSessionStoreType.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect
2 |
3 | import android.content.SharedPreferences
4 | import com.github.salomonbrys.kotson.*
5 | import com.google.gson.GsonBuilder
6 |
7 | class WCSessionStoreType(
8 | private val sharedPreferences: SharedPreferences,
9 | builder: GsonBuilder = GsonBuilder()
10 | ): WCSessionStore {
11 | private val gson = builder
12 | .serializeNulls()
13 | .create()
14 |
15 | private fun store(item: WCSessionStoreItem?) {
16 | if (item != null) {
17 | sharedPreferences.edit().putString(SESSION_KEY, gson.toJson(item)).apply()
18 | } else {
19 | sharedPreferences.edit().remove(SESSION_KEY).apply()
20 | }
21 | }
22 |
23 | private fun load(): WCSessionStoreItem? {
24 | val json = sharedPreferences.getString(SESSION_KEY, null) ?: return null
25 | return gson.fromJson(json)
26 | }
27 |
28 | override var session: WCSessionStoreItem?
29 | set(item) = store(item)
30 | get() = load()
31 |
32 | companion object {
33 | private const val SESSION_KEY = "org.walletconnect.session"
34 | }
35 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 28
9 | defaultConfig {
10 | applicationId "com.trustwallet.walletconnect.sample"
11 | minSdkVersion 21
12 | targetSdkVersion 28
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
28 | implementation 'com.android.support:appcompat-v7:28.0.0'
29 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
30 | testImplementation 'junit:junit:4.12'
31 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
32 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
33 | }
34 |
--------------------------------------------------------------------------------
/walletconnect/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | group='com.github.TrustWallet'
6 |
7 | android {
8 | compileSdkVersion 28
9 |
10 |
11 | defaultConfig {
12 | minSdkVersion 21
13 | targetSdkVersion 28
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
18 |
19 | }
20 |
21 | buildTypes {
22 | release {
23 | minifyEnabled false
24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
25 | }
26 | }
27 |
28 | testOptions {
29 | unitTests {
30 | includeAndroidResources = true
31 | }
32 | }
33 | compileOptions {
34 | sourceCompatibility = "1.8"
35 | targetCompatibility = 1.8
36 | }
37 | buildToolsVersion = '28.0.3'
38 | }
39 |
40 | dependencies {
41 | implementation fileTree(dir: 'libs', include: ['*.jar'])
42 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
43 | implementation 'com.squareup.okhttp3:okhttp:4.0.1'
44 | implementation 'com.google.code.gson:gson:2.8.5'
45 | implementation 'com.github.salomonbrys.kotson:kotson:2.5.0'
46 | implementation 'com.android.support:appcompat-v7:28.0.0'
47 | testImplementation 'junit:junit:4.12'
48 | testImplementation 'org.robolectric:robolectric:4.3'
49 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
51 | }
52 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/binance/WCBinanceCancelOrder.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | import com.github.salomonbrys.kotson.get
4 | import com.github.salomonbrys.kotson.jsonDeserializer
5 | import com.github.salomonbrys.kotson.jsonSerializer
6 | import com.github.salomonbrys.kotson.string
7 | import com.google.gson.JsonObject
8 |
9 | class WCBinanceCancelOrder(
10 | account_number: String,
11 | chain_id: String,
12 | data: String?,
13 | memo: String?,
14 | sequence: String,
15 | source: String,
16 | msgs: List
17 | ): WCBinanceOrder(account_number, chain_id, data, memo, sequence, source, msgs) {
18 |
19 | enum class MessageKey(val key: String) {
20 | REFID("refid"),
21 | SENDER("sender"),
22 | SYMBOL("symbol")
23 | }
24 |
25 | data class Message(
26 | val refid: String,
27 | val sender: String,
28 | val symbol: String
29 | )
30 | }
31 |
32 | val cancelOrderDeserializer = jsonDeserializer {
33 | WCBinanceCancelOrder.Message(
34 | refid = it.json[WCBinanceCancelOrder.MessageKey.REFID.key].string,
35 | sender = it.json[WCBinanceCancelOrder.MessageKey.SENDER.key].string,
36 | symbol = it.json[WCBinanceCancelOrder.MessageKey.SYMBOL.key].string
37 | )
38 | }
39 |
40 | val cancelOrderSerializer = jsonSerializer {
41 | val jsonObject = JsonObject()
42 | jsonObject.addProperty("refid", it.src.refid)
43 | jsonObject.addProperty("sender", it.src.sender)
44 | jsonObject.addProperty("symbol", it.src.symbol)
45 | jsonObject
46 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/binance/WCBinanceTransferOrder.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | import com.github.salomonbrys.kotson.*
4 | import com.google.gson.JsonObject
5 |
6 | class WCBinanceTransferOrder(
7 | account_number: String,
8 | chain_id: String,
9 | data: String?,
10 | memo: String?,
11 | sequence: String,
12 | source: String,
13 | msgs: List
14 | ): WCBinanceOrder(account_number, chain_id, data, memo, sequence, source, msgs) {
15 |
16 | enum class MessageKey(val key: String) {
17 | INPUTS("inputs"),
18 | OUTPUTS("outputs")
19 | }
20 |
21 | data class Message(
22 | val inputs: List- ,
23 | val outputs: List
-
24 | ) {
25 |
26 | data class Item(
27 | val address: String,
28 | val coins: List
29 | ) {
30 |
31 | data class Coin(
32 | val amount: Long,
33 | val denom: String
34 | )
35 | }
36 | }
37 | }
38 |
39 | val transferOrderDeserializer = jsonDeserializer {
40 | WCBinanceTransferOrder.Message(
41 | inputs = it.context.deserialize(it.json[WCBinanceTransferOrder.MessageKey.INPUTS.key].array),
42 | outputs = it.context.deserialize(it.json[WCBinanceTransferOrder.MessageKey.OUTPUTS.key].array)
43 | )
44 | }
45 |
46 | val transferOrderSerializer = jsonSerializer {
47 | val jsonObject = JsonObject()
48 | jsonObject.addProperty(WCBinanceTransferOrder.MessageKey.INPUTS.key, it.context.serialize(it.src.inputs))
49 | jsonObject.addProperty(WCBinanceTransferOrder.MessageKey.OUTPUTS.key, it.context.serialize(it.src.outputs))
50 | jsonObject
51 | }
--------------------------------------------------------------------------------
/walletconnect/src/test/java/com/trustwallet/walletconnect/WCSessionStoreTests.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import com.trustwallet.walletconnect.models.WCPeerMeta
6 | import com.trustwallet.walletconnect.models.session.WCSession
7 | import org.junit.Assert
8 | import org.junit.Before
9 | import org.junit.Test
10 | import org.junit.runner.RunWith
11 | import org.robolectric.RobolectricTestRunner
12 | import org.robolectric.RuntimeEnvironment
13 | import org.robolectric.annotation.Config
14 |
15 | @RunWith(RobolectricTestRunner::class)
16 | @Config(sdk = [Build.VERSION_CODES.M])
17 | class WCSessionStoreTests {
18 | private val context = RuntimeEnvironment.systemContext
19 | private val sharedPreferences = context.getSharedPreferences("tests", Context.MODE_PRIVATE)
20 | private val storage = WCSessionStoreType(sharedPreferences)
21 |
22 | companion object {
23 | const val SESSION_KEY = "org.walletconnect.session"
24 | }
25 |
26 | @Before
27 | fun before() {
28 | sharedPreferences.edit().clear().commit()
29 | }
30 |
31 | @Test
32 | fun test_store() {
33 | val topic = "topic_1"
34 | val session = WCSession.from("wc:$topic@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=some_key")!!
35 | val item = WCSessionStoreItem(session, "peerId", "remotePeerId", WCPeerMeta(name = "Some DApp", url = "https://dapp.com"))
36 |
37 | storage.session = item
38 | Assert.assertNotNull(sharedPreferences.getString(SESSION_KEY, null))
39 | }
40 |
41 | @Test
42 | fun test_remove() {
43 | val topic = "topic_1"
44 | val session = WCSession.from("wc:$topic@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=some_key")!!
45 | val item = WCSessionStoreItem(session, "peerId","remotePeerId", WCPeerMeta(name = "Some DApp", url = "https://dapp.com"))
46 |
47 | storage.session = item
48 | storage.session = null
49 | Assert.assertFalse(sharedPreferences.contains(SESSION_KEY))
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/walletconnect/src/test/java/com/trustwallet/walletconnect/WCCipherTests.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect
2 |
3 | import android.os.Build
4 | import com.trustwallet.walletconnect.extensions.hexStringToByteArray
5 | import com.trustwallet.walletconnect.models.WCEncryptionPayload
6 | import org.junit.Assert
7 | import org.junit.Test
8 | import org.junit.runner.RunWith
9 | import org.robolectric.RobolectricTestRunner
10 | import org.robolectric.annotation.Config
11 |
12 | @RunWith(RobolectricTestRunner::class)
13 | @Config(sdk = [Build.VERSION_CODES.O_MR1])
14 | class WCCipherTests {
15 | @Test
16 | fun test_decrypt() {
17 | val data = "1b3db3674de082d65455eba0ae61cfe7e681c8ef1132e60c8dbd8e52daf18f4fea42cc76366c83351dab6dca52682ff81f828753f89a21e1cc46587ca51ccd353914ffdd3b0394acfee392be6c22b3db9237d3f717a3777e3577dd70408c089a4c9c85130a68c43b0a8aadb00f1b8a8558798104e67aa4ff027b35d4b989e7fd3988d5dcdd563105767670be735b21c4"
18 | val hmac = "a33f868e793ca4fcca964bcb64430f65e2f1ca7a779febeaf94c5373d6df48b3"
19 | val iv = "89ef1d6728bac2f1dcde2ef9330d2bb8"
20 | val key = "5caa3a74154cee16bd1b570a1330be46e086474ac2f4720530662ef1a469662c".hexStringToByteArray()
21 | val payload = WCEncryptionPayload(
22 | data = data,
23 | iv = iv,
24 | hmac = hmac
25 | )
26 |
27 | val decrypted = String(WCCipher.decrypt(payload, key), Charsets.UTF_8)
28 | val expected = "{\"id\":1554098597199736,\"jsonrpc\":\"2.0\",\"method\":\"wc_sessionUpdate\",\"params\":[{\"approved\":false,\"chainId\":null,\"accounts\":null}]}"
29 | Assert.assertEquals(expected, decrypted)
30 | }
31 |
32 | @Test
33 | fun test_encrypt() {
34 | val expected = "{\"id\":1554098597199736,\"jsonrpc\":\"2.0\",\"method\":\"wc_sessionUpdate\",\"params\":[{\"approved\":false,\"chainId\":null,\"accounts\":null}]}".hexStringToByteArray()
35 | val key = "5caa3a74154cee16bd1b570a1330be46e086474ac2f4720530662ef1a469662c".hexStringToByteArray()
36 | val payload = WCCipher.encrypt(data = expected, key = key)
37 | val decrypted = WCCipher.decrypt(payload, key)
38 | Assert.assertArrayEquals(expected, decrypted)
39 | }
40 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/WCCipher.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect
2 |
3 | import com.trustwallet.walletconnect.exceptions.InvalidHmacException
4 | import com.trustwallet.walletconnect.extensions.hexStringToByteArray
5 | import com.trustwallet.walletconnect.extensions.toHex
6 | import com.trustwallet.walletconnect.models.WCEncryptionPayload
7 | import java.security.SecureRandom
8 | import javax.crypto.Cipher
9 | import javax.crypto.Mac
10 | import javax.crypto.spec.IvParameterSpec
11 | import javax.crypto.spec.SecretKeySpec
12 |
13 | private val CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding"
14 | private val MAC_ALGORITHM = "HmacSHA256"
15 |
16 | object WCCipher {
17 | fun encrypt(data: ByteArray, key: ByteArray): WCEncryptionPayload {
18 | val iv = randomBytes(16)
19 | val keySpec = SecretKeySpec(key, "AES")
20 | val ivSpec = IvParameterSpec(iv)
21 | val cipher = Cipher.getInstance(CIPHER_ALGORITHM)
22 | cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
23 |
24 | val encryptedData = cipher.doFinal(data)
25 | val hmac = computeHmac(
26 | data = encryptedData,
27 | iv = iv,
28 | key = key
29 | )
30 |
31 | return WCEncryptionPayload(
32 | data = encryptedData.toHex(),
33 | iv = iv.toHex(),
34 | hmac = hmac
35 | )
36 | }
37 |
38 | fun decrypt(payload: WCEncryptionPayload, key: ByteArray): ByteArray {
39 | val data = payload.data.hexStringToByteArray()
40 | val iv = payload.iv.hexStringToByteArray()
41 | val computedHmac = computeHmac(
42 | data = data,
43 | iv = iv,
44 | key = key
45 | )
46 |
47 | if (computedHmac != payload.hmac.toLowerCase()) {
48 | throw InvalidHmacException()
49 | }
50 |
51 | val keySpec = SecretKeySpec(key, "AES")
52 | val ivSpec = IvParameterSpec(iv)
53 | val cipher = Cipher.getInstance(CIPHER_ALGORITHM)
54 | cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
55 |
56 | return cipher.doFinal(data)
57 | }
58 |
59 | private fun computeHmac(data: ByteArray, iv: ByteArray, key: ByteArray): String {
60 | val mac = Mac.getInstance(MAC_ALGORITHM)
61 | val payload = data + iv
62 | mac.init(SecretKeySpec(key, MAC_ALGORITHM))
63 | return mac.doFinal(payload).toHex()
64 | }
65 |
66 | private fun randomBytes(size: Int): ByteArray {
67 | val secureRandom = SecureRandom()
68 | val bytes = ByteArray(size)
69 | secureRandom.nextBytes(bytes)
70 |
71 | return bytes
72 | }
73 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/models/binance/WCBinanceTradeOrder.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | import com.github.salomonbrys.kotson.*
4 | import com.google.gson.JsonObject
5 |
6 | class WCBinanceTradeOrder(
7 | account_number: String,
8 | chain_id: String,
9 | data: String?,
10 | memo: String?,
11 | sequence: String,
12 | source: String,
13 | msgs: List
14 | ) : WCBinanceOrder (account_number, chain_id, data, memo, sequence, source, msgs) {
15 |
16 | enum class MessageKey(val key: String) {
17 | ID("id"),
18 | ORDER_TYPE("ordertype"),
19 | PRICE("price"),
20 | QUANTITY("quantity"),
21 | SENDER("sender"),
22 | SIDE("side"),
23 | SYMBOL("symbol"),
24 | TIME_INFORCE("timeinforce")
25 | }
26 |
27 | data class Message(
28 | val id: String,
29 | val orderType: Int,
30 | val price: Long,
31 | val quantity: Long,
32 | val sender: String,
33 | val side: Int,
34 | val symbol: String,
35 | val timeInforce: Int
36 | )
37 | }
38 |
39 | val tradeOrderDeserializer = jsonDeserializer {
40 | WCBinanceTradeOrder.Message(
41 | id = it.json[WCBinanceTradeOrder.MessageKey.ID.key].string,
42 | orderType = it.json[WCBinanceTradeOrder.MessageKey.ORDER_TYPE.key].int,
43 | price = it.json[WCBinanceTradeOrder.MessageKey.PRICE.key].long,
44 | quantity = it.json[WCBinanceTradeOrder.MessageKey.QUANTITY.key].long,
45 | sender = it.json[WCBinanceTradeOrder.MessageKey.SENDER.key].string,
46 | side = it.json[WCBinanceTradeOrder.MessageKey.SIDE.key].int,
47 | symbol = it.json[WCBinanceTradeOrder.MessageKey.SYMBOL.key].string,
48 | timeInforce = it.json[WCBinanceTradeOrder.MessageKey.TIME_INFORCE.key].int
49 | )
50 | }
51 |
52 | val tradeOrderSerializer = jsonSerializer {
53 | val jsonObject = JsonObject()
54 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.ID.key, it.src.id)
55 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.ORDER_TYPE.key, it.src.orderType)
56 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.PRICE.key, it.src.price)
57 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.QUANTITY.key, it.src.quantity)
58 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.SENDER.key, it.src.sender)
59 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.SIDE.key, it.src.side)
60 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.SYMBOL.key, it.src.symbol)
61 | jsonObject.addProperty(WCBinanceTradeOrder.MessageKey.TIME_INFORCE.key, it.src.timeInforce)
62 |
63 | jsonObject
64 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/androidstudio
3 | # Edit at https://www.gitignore.io/?templates=androidstudio
4 |
5 | ### AndroidStudio ###
6 | # Covers files to be ignored for android development using Android Studio.
7 |
8 | # Built application files
9 | *.apk
10 | *.ap_
11 |
12 | # Files for the ART/Dalvik VM
13 | *.dex
14 |
15 | # Java class files
16 | *.class
17 |
18 | # Generated files
19 | bin/
20 | gen/
21 | out/
22 |
23 | # Gradle files
24 | .gradle
25 | .gradle/
26 | build/
27 |
28 | # Signing files
29 | .signing/
30 |
31 | # Local configuration file (sdk path, etc)
32 | local.properties
33 |
34 | # Proguard folder generated by Eclipse
35 | proguard/
36 |
37 | # Log Files
38 | *.log
39 |
40 | # Android Studio
41 | /*/build/
42 | /*/local.properties
43 | /*/out
44 | /*/*/build
45 | /*/*/production
46 | captures/
47 | .navigation/
48 | *.ipr
49 | *~
50 | *.swp
51 |
52 | # Android Patch
53 | gen-external-apklibs
54 |
55 | # External native build folder generated in Android Studio 2.2 and later
56 | .externalNativeBuild
57 |
58 | # NDK
59 | obj/
60 |
61 | # IntelliJ IDEA
62 | *.iml
63 | *.iws
64 | /out/
65 |
66 | # User-specific configurations
67 | .idea/caches/
68 | .idea/libraries/
69 | .idea/shelf/
70 | .idea/workspace.xml
71 | .idea/tasks.xml
72 | .idea/.name
73 | .idea/compiler.xml
74 | .idea/copyright/profiles_settings.xml
75 | .idea/encodings.xml
76 | .idea/misc.xml
77 | .idea/modules.xml
78 | .idea/scopes/scope_settings.xml
79 | .idea/dictionaries
80 | .idea/vcs.xml
81 | .idea/jsLibraryMappings.xml
82 | .idea/datasources.xml
83 | .idea/dataSources.ids
84 | .idea/sqlDataSources.xml
85 | .idea/dynamic.xml
86 | .idea/uiDesigner.xml
87 | .idea/assetWizardSettings.xml
88 |
89 | # OS-specific files
90 | .DS_Store
91 | .DS_Store?
92 | ._*
93 | .Spotlight-V100
94 | .Trashes
95 | ehthumbs.db
96 | Thumbs.db
97 |
98 | # Legacy Eclipse project files
99 | .classpath
100 | .project
101 | .cproject
102 | .settings/
103 |
104 | # Mobile Tools for Java (J2ME)
105 | .mtj.tmp/
106 |
107 | # Package Files #
108 | *.war
109 | *.ear
110 |
111 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
112 | hs_err_pid*
113 |
114 | ## Plugin-specific files:
115 |
116 | # mpeltonen/sbt-idea plugin
117 | .idea_modules/
118 |
119 | # JIRA plugin
120 | atlassian-ide-plugin.xml
121 |
122 | # Mongo Explorer plugin
123 | .idea/mongoSettings.xml
124 |
125 | # Crashlytics plugin (for Android Studio and IntelliJ)
126 | com_crashlytics_export_strings.xml
127 | crashlytics.properties
128 | crashlytics-build.properties
129 | fabric.properties
130 |
131 | ### AndroidStudio Patch ###
132 |
133 | !/gradle/wrapper/gradle-wrapper.jar
134 |
135 | # End of https://www.gitignore.io/api/androidstudio
136 | tests.xml
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | xmlns:android
17 |
18 | ^$
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | xmlns:.*
28 |
29 | ^$
30 |
31 |
32 | BY_NAME
33 |
34 |
35 |
36 |
37 |
38 |
39 | .*:id
40 |
41 | http://schemas.android.com/apk/res/android
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | .*:name
51 |
52 | http://schemas.android.com/apk/res/android
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | name
62 |
63 | ^$
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | style
73 |
74 | ^$
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | .*
84 |
85 | ^$
86 |
87 |
88 | BY_NAME
89 |
90 |
91 |
92 |
93 |
94 |
95 | .*
96 |
97 | http://schemas.android.com/apk/res/android
98 |
99 |
100 | ANDROID_ATTRIBUTE_ORDER
101 |
102 |
103 |
104 |
105 |
106 |
107 | .*
108 |
109 | .*
110 |
111 |
112 | BY_NAME
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/walletconnect/src/test/java/com/trustwallet/walletconnect/models/binance/WCBinanceOrderTests.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect.models.binance
2 |
3 | import com.github.salomonbrys.kotson.fromJson
4 | import com.github.salomonbrys.kotson.registerTypeAdapter
5 | import com.google.gson.GsonBuilder
6 | import com.google.gson.JsonArray
7 | import com.trustwallet.walletconnect.jsonrpc.JsonRpcRequest
8 | import org.junit.Assert.assertEquals
9 | import org.junit.Assert.assertNotNull
10 | import org.junit.Test
11 | import java.util.*
12 |
13 | class WCBinanceOrderTests {
14 | val gson = GsonBuilder()
15 | .registerTypeAdapter(cancelOrderDeserializer)
16 | .registerTypeAdapter(cancelOrderSerializer)
17 | .registerTypeAdapter(tradeOrderDeserializer)
18 | .registerTypeAdapter(tradeOrderSerializer)
19 | .registerTypeAdapter(transferOrderDeserializer)
20 | .registerTypeAdapter(transferOrderSerializer)
21 | .create()
22 |
23 | @Test
24 | fun test_parseCancelOrder() {
25 | val json = """
26 | {
27 | "id": 1,
28 | "jsonrpc": "2.0",
29 | "method": "bnb_sign",
30 | "params": [
31 | {
32 | "account_number": "29",
33 | "chain_id": "Binance-Chain-Tigris",
34 | "data": null,
35 | "memo": "",
36 | "msgs": [
37 | {
38 | "refid": "33BBF307B98146F13D20693CF946C2D77A4CAF28-300",
39 | "sender": "bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl",
40 | "symbol": "PVT-554_BNB"
41 | }
42 | ],
43 | "sequence": "300",
44 | "source": "1"
45 | }
46 | ]
47 | }"""
48 |
49 |
50 | val request = gson.fromJson>(json)
51 | val cancelOrder = gson.fromJson>(request.params).first()
52 | assertNotNull(cancelOrder)
53 | val cancelOrderJson = gson.toJson(cancelOrder)
54 | assertEquals(cancelOrderJson, """{"account_number":"29","chain_id":"Binance-Chain-Tigris","memo":"","sequence":"300","source":"1","msgs":[{"refid":"33BBF307B98146F13D20693CF946C2D77A4CAF28-300","sender":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","symbol":"PVT-554_BNB"}]}""")
55 | }
56 |
57 | @Test
58 | fun test_parseTradeOrder() {
59 | val json = """
60 | {
61 | "id": 1,
62 | "jsonrpc": "2.0",
63 | "method": "bnb_sign",
64 | "params": [
65 | {
66 | "account_number": "29",
67 | "chain_id": "Binance-Chain-Tigris",
68 | "data": null,
69 | "memo": "",
70 | "msgs": [
71 | {
72 | "id": "33BBF307B98146F13D20693CF946C2D77A4CAF28-300",
73 | "ordertype": 2,
74 | "price": 7800,
75 | "quantity": 10000000000,
76 | "sender": "bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl",
77 | "side": 1,
78 | "symbol": "PVT-554_BNB",
79 | "timeinforce": 1
80 | }
81 | ],
82 | "sequence": "299",
83 | "source": "1"
84 | }
85 | ]
86 | }"""
87 |
88 |
89 | val request = gson.fromJson>(json)
90 | val tradeOrder = gson.fromJson>(request.params).first()
91 | assertNotNull(tradeOrder)
92 | val cancelOrderJson = gson.toJson(tradeOrder)
93 | assertEquals(cancelOrderJson, """{"account_number":"29","chain_id":"Binance-Chain-Tigris","memo":"","sequence":"299","source":"1","msgs":[{"id":"33BBF307B98146F13D20693CF946C2D77A4CAF28-300","ordertype":2,"price":7800,"quantity":10000000000,"sender":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","side":1,"symbol":"PVT-554_BNB","timeinforce":1}]}""")
94 | }
95 |
96 | @Test
97 | fun test_parseTransferOrder() {
98 | val json = """
99 | {
100 | "id": 1,
101 | "jsonrpc": "2.0",
102 | "method": "bnb_sign",
103 | "params": [
104 | {
105 | "account_number": "29",
106 | "chain_id": "Binance-Chain-Tigris",
107 | "data": null,
108 | "memo": "Testing",
109 | "msgs": [
110 | {
111 | "inputs": [
112 | {
113 | "address": "bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl",
114 | "coins": [
115 | {
116 | "amount": 1000000,
117 | "denom": "BNB"
118 | }
119 | ]
120 | }
121 | ],
122 | "outputs": [
123 | {
124 | "address": "bnb14u7newkxwdhcuhddvtg2n8n96m9tqxejsjuuhn",
125 | "coins": [
126 | {
127 | "amount": 1000000,
128 | "denom": "BNB"
129 | }
130 | ]
131 | }
132 | ]
133 | }
134 | ],
135 | "sequence": "301",
136 | "source": "1"
137 | }
138 | ]
139 | }
140 | """
141 |
142 | val request = gson.fromJson>(json)
143 | val order = gson.fromJson>(request.params).first()
144 | assertNotNull(order)
145 | assertEquals(gson.toJson(order), """{"account_number":"29","chain_id":"Binance-Chain-Tigris","memo":"Testing","sequence":"301","source":"1","msgs":[{"inputs":[{"address":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","coins":[{"amount":1000000,"denom":"BNB"}]}],"outputs":[{"address":"bnb14u7newkxwdhcuhddvtg2n8n96m9tqxejsjuuhn","coins":[{"amount":1000000,"denom":"BNB"}]}]}]}""")
146 | }
147 |
148 | @Test(expected = NoSuchElementException::class)
149 | fun test_parseInvalidTradeOrder() {
150 | val json = """
151 | {
152 | "id": 1,
153 | "jsonrpc": "2.0",
154 | "method": "bnb_sign",
155 | "params": [
156 | {
157 | "account_number": "29",
158 | "chain_id": "Binance-Chain-Tigris",
159 | "data": null,
160 | "memo": "",
161 | "msgs": [
162 | {
163 | "refid": "33BBF307B98146F13D20693CF946C2D77A4CAF28-300",
164 | "sender": "bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl",
165 | "symbol": "PVT-554_BNB"
166 | }
167 | ],
168 | "sequence": "300",
169 | "source": "1"
170 | }
171 | ]
172 | }"""
173 |
174 |
175 | val request = gson.fromJson>(json)
176 | gson.fromJson>(request.params).first()
177 | }
178 | }
--------------------------------------------------------------------------------
/walletconnect/src/main/java/com/trustwallet/walletconnect/WCClient.kt:
--------------------------------------------------------------------------------
1 | package com.trustwallet.walletconnect
2 |
3 | import android.util.Log
4 | import com.github.salomonbrys.kotson.fromJson
5 | import com.github.salomonbrys.kotson.registerTypeAdapter
6 | import com.github.salomonbrys.kotson.typeToken
7 | import com.google.gson.GsonBuilder
8 | import com.google.gson.JsonArray
9 | import com.trustwallet.walletconnect.exceptions.InvalidJsonRpcParamsException
10 | import com.trustwallet.walletconnect.extensions.hexStringToByteArray
11 | import com.trustwallet.walletconnect.jsonrpc.JsonRpcError
12 | import com.trustwallet.walletconnect.jsonrpc.JsonRpcErrorResponse
13 | import com.trustwallet.walletconnect.jsonrpc.JsonRpcRequest
14 | import com.trustwallet.walletconnect.jsonrpc.JsonRpcResponse
15 | import com.trustwallet.walletconnect.models.*
16 | import com.trustwallet.walletconnect.models.binance.*
17 | import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
18 | import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
19 | import com.trustwallet.walletconnect.models.okexchain.WCOKExChainTransaction
20 | import com.trustwallet.walletconnect.models.session.WCApproveSessionResponse
21 | import com.trustwallet.walletconnect.models.session.WCSession
22 | import com.trustwallet.walletconnect.models.session.WCSessionRequest
23 | import com.trustwallet.walletconnect.models.session.WCSessionUpdate
24 | import okhttp3.*
25 | import okio.ByteString
26 | import java.util.*
27 |
28 | const val JSONRPC_VERSION = "2.0"
29 | const val WS_CLOSE_NORMAL = 1000
30 |
31 | open class WCClient (
32 | builder: GsonBuilder = GsonBuilder(),
33 | private val httpClient: OkHttpClient
34 | ): WebSocketListener() {
35 | private val TAG = "WCClient"
36 |
37 | private val gson = builder
38 | .serializeNulls()
39 | .registerTypeAdapter(cancelOrderSerializer)
40 | .registerTypeAdapter(cancelOrderDeserializer)
41 | .registerTypeAdapter(tradeOrderSerializer)
42 | .registerTypeAdapter(tradeOrderDeserializer)
43 | .registerTypeAdapter(transferOrderSerializer)
44 | .registerTypeAdapter(transferOrderDeserializer)
45 | .create()
46 |
47 | private var socket: WebSocket? = null
48 |
49 | private val listeners: MutableSet = mutableSetOf()
50 |
51 | var session: WCSession? = null
52 | private set
53 |
54 | var peerMeta: WCPeerMeta? = null
55 | private set
56 |
57 | var peerId: String? = null
58 | private set
59 |
60 | var remotePeerId: String? = null
61 | private set
62 |
63 | var isConnected: Boolean = false
64 | private set
65 |
66 | private var handshakeId: Long = -1
67 |
68 | var onFailure: (Throwable) -> Unit = { _ -> Unit}
69 | var onDisconnect: (code: Int, reason: String) -> Unit = { _, _ -> Unit }
70 | var onSessionRequest: (id: Long, peer: WCPeerMeta) -> Unit = { _, _ -> Unit }
71 | var onEthSign: (id: Long, message: WCEthereumSignMessage) -> Unit = { _, _ -> Unit }
72 | var onEthSignTransaction: (id: Long, transaction: WCEthereumTransaction) -> Unit = { _, _ -> Unit }
73 | var onEthSendTransaction: (id: Long, transaction: WCEthereumTransaction) -> Unit = { _, _ -> Unit }
74 | var onCustomRequest: (id: Long, payload: String) -> Unit = { _, _ -> Unit }
75 | var onBnbTrade: (id: Long, order: WCBinanceTradeOrder) -> Unit = { _, _ -> Unit }
76 | var onBnbCancel: (id: Long, order: WCBinanceCancelOrder) -> Unit = { _, _ -> Unit }
77 | var onBnbTransfer: (id: Long, order: WCBinanceTransferOrder) -> Unit = { _, _ -> Unit }
78 | var onBnbTxConfirm: (id: Long, order: WCBinanceTxConfirmParam) -> Unit = { _, _ -> Unit }
79 | var onGetAccounts: (id: Long) -> Unit = { _ -> Unit }
80 | var onSignTransaction: (id: Long, transaction: WCSignTransaction) -> Unit = {_, _ -> Unit }
81 | var onOktSignTransaction:(id:Long, transaction: WCOKExChainTransaction) -> Unit = {_,_->Unit }
82 | var onOktSendTransaction:(id:Long, transaction: WCOKExChainTransaction) -> Unit = { _, _->Unit }
83 |
84 | override fun onOpen(webSocket: WebSocket, response: Response) {
85 | Log.d(TAG, "<< websocket opened >>")
86 | isConnected = true
87 |
88 | listeners.forEach { it.onOpen(webSocket, response) }
89 |
90 | val session = this.session ?: throw IllegalStateException("session can't be null on connection open")
91 | val peerId = this.peerId ?: throw IllegalStateException("peerId can't be null on connection open")
92 | // The Session.topic channel is used to listen session request messages only.
93 | subscribe(session.topic)
94 | // The peerId channel is used to listen to all messages sent to this httpClient.
95 | subscribe(peerId)
96 | }
97 |
98 | override fun onMessage(webSocket: WebSocket, text: String) {
99 | var decrypted: String? = null
100 | try {
101 | Log.d(TAG, "<== message $text")
102 | decrypted = decryptMessage(text)
103 | Log.d(TAG, "<== decrypted $decrypted")
104 | handleMessage(decrypted)
105 | } catch (e: Exception) {
106 | onFailure(e)
107 | } finally {
108 | listeners.forEach { it.onMessage(webSocket, decrypted ?: text) }
109 | }
110 | }
111 |
112 | override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
113 | resetState()
114 | onFailure(t)
115 |
116 | listeners.forEach { it.onFailure(webSocket, t, response) }
117 | }
118 |
119 | override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
120 | Log.d(TAG,"<< websocket closed >>")
121 |
122 | listeners.forEach { it.onClosed(webSocket, code, reason) }
123 | }
124 |
125 | override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
126 | Log.d(TAG,"<== pong")
127 |
128 | listeners.forEach { it.onMessage(webSocket, bytes) }
129 | }
130 |
131 | override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
132 | Log.d(TAG,"<< closing socket >>")
133 |
134 | resetState()
135 | onDisconnect(code, reason)
136 |
137 | listeners.forEach { it.onClosing(webSocket, code, reason) }
138 | }
139 |
140 | fun connect(session: WCSession, peerMeta: WCPeerMeta, peerId: String = UUID.randomUUID().toString(), remotePeerId: String? = null) {
141 | if (this.session != null && this.session?.topic != session.topic) {
142 | killSession()
143 | }
144 |
145 | this.session = session
146 | this.peerMeta = peerMeta
147 | this.peerId = peerId
148 | this.remotePeerId = remotePeerId
149 |
150 | val request = Request.Builder()
151 | .url(session.bridge)
152 | .build()
153 |
154 | socket = httpClient.newWebSocket(request, this)
155 | }
156 |
157 | fun approveSession(accounts: List, chainId: Int): Boolean {
158 | check(handshakeId > 0) { "handshakeId must be greater than 0 on session approve" }
159 |
160 | val result = WCApproveSessionResponse(
161 | chainId = chainId,
162 | accounts = accounts,
163 | peerId = peerId,
164 | peerMeta = peerMeta
165 | )
166 | val response = JsonRpcResponse(
167 | id = handshakeId,
168 | result = result
169 | )
170 |
171 | return encryptAndSend(gson.toJson(response))
172 | }
173 |
174 | fun updateSession(accounts: List? = null, chainId: Int? = null, approved: Boolean = true): Boolean {
175 | val request = JsonRpcRequest(
176 | id = generateId(),
177 | method = WCMethod.SESSION_UPDATE,
178 | params = listOf(
179 | WCSessionUpdate(
180 | approved = approved,
181 | chainId = chainId,
182 | accounts = accounts
183 | )
184 | )
185 | )
186 | return encryptAndSend(gson.toJson(request))
187 | }
188 |
189 | fun rejectSession(message: String = "Session rejected"): Boolean {
190 | check(handshakeId > 0) { "handshakeId must be greater than 0 on session reject" }
191 |
192 | val response = JsonRpcErrorResponse(
193 | id = handshakeId,
194 | error = JsonRpcError.serverError(
195 | message = message
196 | )
197 | )
198 | return encryptAndSend(gson.toJson(response))
199 | }
200 |
201 | fun killSession(): Boolean {
202 | updateSession(approved = false)
203 | return disconnect()
204 | }
205 |
206 | fun approveRequest(id: Long, result: T): Boolean {
207 | val response = JsonRpcResponse(
208 | id = id,
209 | result = result
210 | )
211 | return encryptAndSend(gson.toJson(response))
212 | }
213 |
214 | fun rejectRequest(id: Long, message: String = "Reject by the user"): Boolean {
215 | val response = JsonRpcErrorResponse(
216 | id = id,
217 | error = JsonRpcError.serverError(
218 | message = message
219 | )
220 | )
221 | return encryptAndSend(gson.toJson(response))
222 | }
223 |
224 | private fun decryptMessage(text: String): String {
225 | val message = gson.fromJson(text)
226 | val encrypted = gson.fromJson(message.payload)
227 | val session = this.session ?: throw IllegalStateException("session can't be null on message receive")
228 | return String(WCCipher.decrypt(encrypted, session.key.hexStringToByteArray()), Charsets.UTF_8)
229 | }
230 |
231 | private fun invalidParams(id: Long): Boolean {
232 | val response = JsonRpcErrorResponse(
233 | id = id,
234 | error = JsonRpcError.invalidParams(
235 | message = "Invalid parameters"
236 | )
237 | )
238 |
239 | return encryptAndSend(gson.toJson(response))
240 | }
241 |
242 | private fun handleMessage(payload: String) {
243 | try {
244 | val request = gson.fromJson>(payload, typeToken>())
245 | val method = request.method
246 | if (method != null) {
247 | handleRequest(request)
248 | } else {
249 | onCustomRequest(request.id, payload)
250 | }
251 | } catch (e: InvalidJsonRpcParamsException) {
252 | invalidParams(e.requestId)
253 | }
254 | }
255 |
256 | private fun handleRequest(request: JsonRpcRequest) {
257 | when (request.method) {
258 | WCMethod.SESSION_REQUEST -> {
259 | val param = gson.fromJson>(request.params)
260 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
261 | handshakeId = request.id
262 | remotePeerId = param.peerId
263 | onSessionRequest(request.id, param.peerMeta)
264 | }
265 | WCMethod.SESSION_UPDATE -> {
266 | val param = gson.fromJson>(request.params)
267 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
268 | if (!param.approved) {
269 | killSession()
270 | }
271 | }
272 | WCMethod.ETH_SIGN -> {
273 | val params = gson.fromJson>(request.params)
274 | if (params.size < 2)
275 | throw InvalidJsonRpcParamsException(request.id)
276 | onEthSign(request.id, WCEthereumSignMessage(params, WCEthereumSignMessage.WCSignType.MESSAGE))
277 | }
278 | WCMethod.ETH_PERSONAL_SIGN -> {
279 | val params = gson.fromJson>(request.params)
280 | if (params.size < 2)
281 | throw InvalidJsonRpcParamsException(request.id)
282 | onEthSign(request.id, WCEthereumSignMessage(params, WCEthereumSignMessage.WCSignType.PERSONAL_MESSAGE))
283 | }
284 | WCMethod.ETH_SIGN_TYPE_DATA -> {
285 | val params = gson.fromJson>(request.params)
286 | if (params.size < 2)
287 | throw InvalidJsonRpcParamsException(request.id)
288 | onEthSign(request.id, WCEthereumSignMessage(params, WCEthereumSignMessage.WCSignType.TYPED_MESSAGE))
289 | }
290 | WCMethod.ETH_SIGN_TRANSACTION -> {
291 | val param = gson.fromJson>(request.params)
292 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
293 | onEthSignTransaction(request.id, param)
294 | }
295 | WCMethod.ETH_SEND_TRANSACTION ->{
296 | val param = gson.fromJson>(request.params)
297 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
298 | onEthSendTransaction(request.id, param)
299 | }
300 | WCMethod.BNB_SIGN -> {
301 | try {
302 | val order = gson.fromJson>(request.params)
303 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
304 | onBnbCancel(request.id, order)
305 | } catch (e: NoSuchElementException) { }
306 |
307 | try {
308 | val order = gson.fromJson>(request.params)
309 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
310 | onBnbTrade(request.id, order)
311 | } catch (e: NoSuchElementException) { }
312 |
313 | try {
314 | val order = gson.fromJson>(request.params)
315 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
316 | onBnbTransfer(request.id, order)
317 | } catch (e: NoSuchElementException) { }
318 | }
319 | WCMethod.OKT_SEND_TRANSACTION -> {
320 | val param = gson.fromJson>(request.params)
321 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
322 | onOktSendTransaction(request.id,param)
323 | }
324 | WCMethod.OKT_SIGN_TRANSACTION -> {
325 | val param = gson.fromJson>(request.params)
326 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
327 | onOktSignTransaction(request.id,param)
328 |
329 | }
330 | WCMethod.BNB_TRANSACTION_CONFIRM -> {
331 | val param = gson.fromJson>(request.params)
332 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
333 | onBnbTxConfirm(request.id, param)
334 | }
335 | WCMethod.GET_ACCOUNTS -> {
336 | onGetAccounts(request.id)
337 | }
338 | WCMethod.SIGN_TRANSACTION -> {
339 | val param = gson.fromJson>(request.params)
340 | .firstOrNull() ?: throw InvalidJsonRpcParamsException(request.id)
341 | onSignTransaction(request.id, param)
342 | }
343 | }
344 | }
345 |
346 | private fun subscribe(topic: String): Boolean {
347 | val message = WCSocketMessage(
348 | topic = topic,
349 | type = MessageType.SUB,
350 | payload = ""
351 | )
352 | val json = gson.toJson(message)
353 | Log.d(TAG,"==> subscribe $json")
354 |
355 | return socket?.send(gson.toJson(message)) ?: false
356 | }
357 |
358 | private fun encryptAndSend(result: String): Boolean {
359 | Log.d(TAG,"==> message $result")
360 | val session = this.session ?: throw IllegalStateException("session can't be null on message send")
361 | val payload = gson.toJson(WCCipher.encrypt(result.toByteArray(Charsets.UTF_8), session.key.hexStringToByteArray()))
362 | val message = WCSocketMessage(
363 | // Once the remotePeerId is defined, all messages must be sent to this channel. The session.topic channel
364 | // will be used only to respond the session request message.
365 | topic = remotePeerId ?: session.topic,
366 | type = MessageType.PUB,
367 | payload = payload
368 | )
369 | val json = gson.toJson(message)
370 | Log.d(TAG,"==> encrypted $json")
371 |
372 | return socket?.send(json) ?: false
373 | }
374 |
375 |
376 | fun disconnect(): Boolean {
377 | return socket?.close(WS_CLOSE_NORMAL, null) ?: false
378 | }
379 |
380 | fun addSocketListener(listener: WebSocketListener) {
381 | listeners.add(listener)
382 | }
383 |
384 | fun removeSocketListener(listener: WebSocketListener) {
385 | listeners.remove(listener)
386 | }
387 |
388 | private fun resetState() {
389 | handshakeId = -1
390 | isConnected = false
391 | session = null
392 | peerId = null
393 | remotePeerId = null
394 | peerMeta = null
395 | }
396 | }
397 |
398 | private fun generateId(): Long {
399 | return Date().time
400 | }
401 |
--------------------------------------------------------------------------------