@chainberry/trust-wallet-core 1.0.2 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/{TrustWalletCoreModule.podspec → ChainberryTrustWalletCoreModule.podspec} +2 -2
  2. package/README.md +38 -30
  3. package/android/build.gradle +31 -6
  4. package/android/libs/README.md +34 -0
  5. package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.aar +0 -0
  6. package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.aar.md5 +1 -0
  7. package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.aar.sha1 +1 -0
  8. package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.pom +22 -0
  9. package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.pom.md5 +1 -0
  10. package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.pom.sha1 +1 -0
  11. package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar +0 -0
  12. package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar.md5 +1 -0
  13. package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar.sha1 +1 -0
  14. package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom +21 -0
  15. package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom.md5 +1 -0
  16. package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom.sha1 +1 -0
  17. package/android/libs/download.sh +52 -0
  18. package/android/src/androidTest/java/com/chainberry/trustwalletcore/AddressDerivationConformanceTest.kt +106 -0
  19. package/android/src/androidTest/java/com/chainberry/trustwalletcore/SigningConformanceTest.kt +186 -0
  20. package/android/src/main/java/com/chainberry/trustwalletcore/AmountParsing.kt +45 -0
  21. package/android/src/main/java/com/chainberry/trustwalletcore/Bech32.kt +68 -0
  22. package/android/src/main/java/com/chainberry/trustwalletcore/ChainSigning.kt +526 -0
  23. package/android/src/main/java/com/chainberry/trustwalletcore/ChainberryTrustWalletCoreModule.kt +147 -0
  24. package/android/src/main/java/com/chainberry/trustwalletcore/NativeWalletStore.kt +796 -0
  25. package/android/src/test/java/com/chainberry/trustwalletcore/AmountParsingConformanceTest.kt +57 -0
  26. package/android/src/test/java/com/chainberry/trustwalletcore/Bech32Test.kt +35 -0
  27. package/android/src/test/java/com/chainberry/trustwalletcore/NativeWalletStoreTest.kt +274 -0
  28. package/expo-module.config.json +3 -2
  29. package/ios/AmountParsing.swift +62 -0
  30. package/ios/Bech32.swift +66 -0
  31. package/ios/ChainSigning.swift +602 -0
  32. package/ios/ChainberryTrustWalletCoreModule.swift +231 -0
  33. package/ios/NativeWalletStore.swift +232 -0
  34. package/package.json +5 -4
  35. package/src/index.ts +70 -60
  36. package/android/src/main/java/expo/modules/trustwalletcore/TrustWalletCoreModule.kt +0 -143
  37. package/ios/TrustWalletCoreModule.swift +0 -145
@@ -1,143 +0,0 @@
1
- package expo.modules.trustwalletcore
2
-
3
- import com.google.protobuf.ByteString
4
- import expo.modules.kotlin.modules.Module
5
- import expo.modules.kotlin.modules.ModuleDefinition
6
- import wallet.core.java.AnySigner
7
- import wallet.core.jni.CoinType
8
- import wallet.core.jni.HDWallet
9
- import wallet.core.jni.PrivateKey
10
- import wallet.core.jni.proto.Common
11
- import wallet.core.jni.proto.Ethereum
12
- import wallet.core.jni.proto.Solana
13
- import java.math.BigInteger
14
-
15
- class TrustWalletCoreModule : Module() {
16
- companion object {
17
- init {
18
- // Must be loaded once before any JNI calls
19
- System.loadLibrary("TrustWalletCore")
20
- }
21
- }
22
-
23
- override fun definition() = ModuleDefinition {
24
- Name("TrustWalletCore")
25
-
26
- // Returns { mnemonic } — strength 128 = 12 words, 256 = 24 words
27
- AsyncFunction("generateWallet") { strength: Int, passphrase: String ->
28
- mapOf("mnemonic" to HDWallet(strength, passphrase).mnemonic())
29
- }
30
-
31
- // Validates mnemonic and returns { mnemonic }
32
- AsyncFunction("restoreWallet") { mnemonic: String, passphrase: String ->
33
- HDWallet(mnemonic, passphrase) // throws on invalid mnemonic
34
- mapOf("mnemonic" to mnemonic)
35
- }
36
-
37
- // Derives address and private key for a named coin
38
- // coin: "ethereum" | "solana"
39
- AsyncFunction("getAddressForCoin") { mnemonic: String, coin: String, passphrase: String ->
40
- val wallet = HDWallet(mnemonic, passphrase)
41
- val coinType = resolveCoinType(coin)
42
- mapOf(
43
- "address" to wallet.getAddressForCoin(coinType),
44
- "privateKey" to wallet.getKeyForCoin(coinType).data().toHex(),
45
- )
46
- }
47
-
48
- // Signs an Ethereum transaction; returns 0x-prefixed RLP-encoded signed tx hex
49
- // txParams: { to, valueHex, nonce, gasLimitHex, chainId, dataHex?,
50
- // gasPriceHex? (legacy) | maxFeePerGasHex + maxPriorityFeePerGasHex (EIP-1559) }
51
- AsyncFunction("signEthereumTransaction") { privateKeyHex: String, txParams: Map<String, Any> ->
52
- val privateKey = PrivateKey(privateKeyHex.hexToBytes())
53
- val to = txParams["to"] as String
54
- val valueHex = (txParams["valueHex"] as? String)?.ifEmpty { "0" } ?: "0"
55
- val nonce = (txParams["nonce"] as Number).toInt()
56
- val gasLimHex = txParams["gasLimitHex"] as String
57
- val chainId = (txParams["chainId"] as Number).toInt()
58
- val dataHex = (txParams["dataHex"] as? String) ?: ""
59
-
60
- val input = Ethereum.SigningInput.newBuilder().apply {
61
- this.chainId = BigInteger.valueOf(chainId.toLong()).toMinimalByteString()
62
- this.nonce = BigInteger.valueOf(nonce.toLong()).toMinimalByteString()
63
- this.gasLimit = BigInteger(gasLimHex, 16).toMinimalByteString()
64
- this.toAddress = to
65
- this.privateKey = ByteString.copyFrom(privateKey.data())
66
-
67
- this.transaction = Ethereum.Transaction.newBuilder().apply {
68
- this.transfer = Ethereum.Transaction.Transfer.newBuilder().apply {
69
- this.amount = BigInteger(valueHex, 16).toMinimalByteString()
70
- if (dataHex.isNotEmpty()) this.data = ByteString.copyFrom(dataHex.hexToBytes())
71
- }.build()
72
- }.build()
73
-
74
- val gasPriceHex = txParams["gasPriceHex"] as? String
75
- if (gasPriceHex != null) {
76
- this.gasPrice = BigInteger(gasPriceHex, 16).toMinimalByteString()
77
- } else {
78
- val mfHex = txParams["maxFeePerGasHex"] as? String
79
- val pfHex = txParams["maxPriorityFeePerGasHex"] as? String
80
- if (mfHex != null && pfHex != null) {
81
- this.maxFeePerGas = BigInteger(mfHex, 16).toMinimalByteString()
82
- this.maxInclusionFeePerGas = BigInteger(pfHex, 16).toMinimalByteString()
83
- }
84
- }
85
- }.build()
86
-
87
- val output = AnySigner.sign(input, CoinType.ETHEREUM, Ethereum.SigningOutput.parser())
88
- if (output.error != Common.SigningError.OK) {
89
- throw Exception("Signing failed: ${output.errorMessage}")
90
- }
91
- "0x" + output.encoded.toByteArray().toHex()
92
- }
93
-
94
- // Signs a Solana transfer; returns base64-encoded signed transaction
95
- // txParams: { to, lamports (string, lamports amount), recentBlockhash }
96
- AsyncFunction("signSolanaTransaction") { privateKeyHex: String, txParams: Map<String, Any> ->
97
- val privateKey = PrivateKey(privateKeyHex.hexToBytes())
98
- val to = txParams["to"] as String
99
- val lamports = (txParams["lamports"] as String).toLong()
100
- val recentBlockhash = txParams["recentBlockhash"] as String
101
-
102
- val input = Solana.SigningInput.newBuilder().apply {
103
- this.recentBlockhash = recentBlockhash
104
- this.privateKey = ByteString.copyFrom(privateKey.data())
105
- this.transferTransaction = Solana.Transfer.newBuilder().apply {
106
- this.recipient = to
107
- this.value = lamports
108
- }.build()
109
- }.build()
110
-
111
- val output = AnySigner.sign(input, CoinType.SOLANA, Solana.SigningOutput.parser())
112
- if (output.error != Common.SigningError.OK) {
113
- throw Exception("Signing failed: ${output.errorMessage}")
114
- }
115
- output.encoded
116
- }
117
- }
118
- }
119
-
120
- // Helpers
121
- private fun resolveCoinType(coin: String): CoinType = when (coin.lowercase()) {
122
- "ethereum" -> CoinType.ETHEREUM
123
- "solana" -> CoinType.SOLANA
124
- "bnb" -> CoinType.SMARTCHAIN
125
- else -> throw IllegalArgumentException("Unsupported coin: $coin")
126
- }
127
-
128
- private fun ByteArray.toHex(): String = joinToString("") { "%02x".format(it) }
129
-
130
- private fun String.hexToBytes(): ByteArray {
131
- val s = removePrefix("0x").let { if (it.length % 2 == 0) it else "0$it" }
132
- return ByteArray(s.length / 2) { s.substring(it * 2, it * 2 + 2).toInt(16).toByte() }
133
- }
134
-
135
- // BigInteger → minimal big-endian ByteString (strips Java's leading sign byte)
136
- private fun BigInteger.toMinimalByteString(): ByteString {
137
- val raw = toByteArray()
138
- return if (raw.size > 1 && raw[0] == 0.toByte()) {
139
- ByteString.copyFrom(raw, 1, raw.size - 1)
140
- } else {
141
- ByteString.copyFrom(raw)
142
- }
143
- }
@@ -1,145 +0,0 @@
1
- import ExpoModulesCore
2
- import WalletCore
3
-
4
- // All numeric transaction fields are bare hex strings (no 0x prefix) to avoid JS number precision loss.
5
- public class TrustWalletCoreModule: Module {
6
- public func definition() -> ModuleDefinition {
7
- Name("TrustWalletCore")
8
-
9
- // Returns { mnemonic } — strength 128 = 12 words, 256 = 24 words
10
- AsyncFunction("generateWallet") { (strength: Int, passphrase: String) throws -> [String: String] in
11
- guard let wallet = HDWallet(strength: UInt32(strength), passphrase: passphrase) else {
12
- throw Exception(name: "WalletError", description: "Failed to generate wallet")
13
- }
14
- return ["mnemonic": wallet.mnemonic]
15
- }
16
-
17
- // Validates mnemonic and returns { mnemonic }
18
- AsyncFunction("restoreWallet") { (mnemonic: String, passphrase: String) throws -> [String: String] in
19
- guard HDWallet(mnemonic: mnemonic, passphrase: passphrase) != nil else {
20
- throw Exception(name: "InvalidMnemonic", description: "Invalid mnemonic phrase")
21
- }
22
- return ["mnemonic": mnemonic]
23
- }
24
-
25
- // Derives address and private key for a named coin
26
- // coin: "ethereum" | "solana"
27
- AsyncFunction("getAddressForCoin") { (mnemonic: String, coin: String, passphrase: String) throws -> [String: String] in
28
- guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: passphrase) else {
29
- throw Exception(name: "InvalidMnemonic", description: "Invalid mnemonic phrase")
30
- }
31
- let coinType = try Self.resolveCoinType(coin)
32
- return [
33
- "address": wallet.getAddressForCoin(coin: coinType),
34
- "privateKey": wallet.getKeyForCoin(coin: coinType).data.hexString,
35
- ]
36
- }
37
-
38
- // Signs an Ethereum transaction; returns 0x-prefixed RLP-encoded signed tx hex
39
- // txParams: { to, valueHex, nonce, gasLimitHex, chainId, dataHex?,
40
- // gasPriceHex? (legacy) | maxFeePerGasHex + maxPriorityFeePerGasHex (EIP-1559) }
41
- AsyncFunction("signEthereumTransaction") { (privateKeyHex: String, txParams: [String: Any]) throws -> String in
42
- guard let pkData = Data(hexString: privateKeyHex),
43
- let privateKey = PrivateKey(data: pkData) else {
44
- throw Exception(name: "InvalidKey", description: "Invalid private key hex")
45
- }
46
- guard let to = txParams["to"] as? String,
47
- let nonce = txParams["nonce"] as? Int,
48
- let gasLimHex = txParams["gasLimitHex"] as? String,
49
- let chainId = txParams["chainId"] as? Int else {
50
- throw Exception(name: "InvalidParams", description: "Missing required tx params")
51
- }
52
- let valueHex = (txParams["valueHex"] as? String) ?? "0"
53
- let dataHex = (txParams["dataHex"] as? String) ?? ""
54
-
55
- var input = EthereumSigningInput()
56
- input.chainID = Self.intToData(chainId)
57
- input.nonce = Self.intToData(nonce)
58
- input.gasLimit = Self.hexData(gasLimHex) ?? Data()
59
- input.toAddress = to
60
- input.privateKey = privateKey.data
61
- if !dataHex.isEmpty { input.txData = Self.hexData(dataHex) ?? Data() }
62
-
63
- var transfer = EthereumTransaction.Transfer()
64
- transfer.amount = Self.hexData(valueHex) ?? Data([0])
65
- var tx = EthereumTransaction()
66
- tx.transfer = transfer
67
- input.transaction = tx
68
-
69
- if let gasPriceHex = txParams["gasPriceHex"] as? String {
70
- input.gasPrice = Self.hexData(gasPriceHex) ?? Data()
71
- } else if let mfHex = txParams["maxFeePerGasHex"] as? String,
72
- let pfHex = txParams["maxPriorityFeePerGasHex"] as? String {
73
- input.maxFeePerGas = Self.hexData(mfHex) ?? Data()
74
- input.maxInclusionFeePerGas = Self.hexData(pfHex) ?? Data()
75
- }
76
-
77
- let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum)
78
- guard output.error == .ok else {
79
- throw Exception(name: "SigningFailed", description: output.errorMessage)
80
- }
81
- return "0x" + output.encoded.hexString
82
- }
83
-
84
- // Signs a Solana transfer; returns base64-encoded signed transaction
85
- // txParams: { to, lamports (string), recentBlockhash }
86
- AsyncFunction("signSolanaTransaction") { (privateKeyHex: String, txParams: [String: Any]) throws -> String in
87
- guard let pkData = Data(hexString: privateKeyHex),
88
- let privateKey = PrivateKey(data: pkData) else {
89
- throw Exception(name: "InvalidKey", description: "Invalid private key hex")
90
- }
91
- guard let to = txParams["to"] as? String,
92
- let lamportsStr = txParams["lamports"] as? String,
93
- let lamports = UInt64(lamportsStr),
94
- let recentBlockhash = txParams["recentBlockhash"] as? String else {
95
- throw Exception(name: "InvalidParams", description: "Missing required Solana tx params (to, lamports, recentBlockhash)")
96
- }
97
-
98
- var transfer = SolanaTransfer()
99
- transfer.recipient = to
100
- transfer.value = lamports
101
-
102
- var input = SolanaSigningInput()
103
- input.recentBlockhash = recentBlockhash
104
- input.privateKey = privateKey.data
105
- input.transferTransaction = transfer
106
-
107
- let output: SolanaSigningOutput = AnySigner.sign(input: input, coin: .solana)
108
- guard output.error == .ok else {
109
- throw Exception(name: "SigningFailed", description: output.errorMessage)
110
- }
111
- return output.encoded
112
- }
113
- }
114
-
115
- // MARK: - Helpers
116
-
117
- private static func resolveCoinType(_ coin: String) throws -> CoinType {
118
- switch coin.lowercased() {
119
- case "ethereum": return .ethereum
120
- case "solana": return .solana
121
- case "bnb": return .smartChain
122
- default:
123
- throw Exception(name: "UnsupportedCoin", description: "Unsupported coin: \(coin)")
124
- }
125
- }
126
-
127
- // Parses a hex string (with or without 0x, odd or even length) into Data
128
- private static func hexData(_ hex: String) -> Data? {
129
- let s = hex.hasPrefix("0x") ? String(hex.dropFirst(2)) : hex
130
- let padded = s.count % 2 == 0 ? s : "0" + s
131
- return padded.isEmpty ? Data([0]) : Data(hexString: padded)
132
- }
133
-
134
- // Encodes a non-negative integer as minimal big-endian Data
135
- private static func intToData(_ value: Int) -> Data {
136
- guard value > 0 else { return Data([0]) }
137
- var v = value
138
- var bytes: [UInt8] = []
139
- while v > 0 {
140
- bytes.insert(UInt8(v & 0xFF), at: 0)
141
- v >>= 8
142
- }
143
- return Data(bytes)
144
- }
145
- }