@vultisig/walletcore-native 0.1.1 → 0.2.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.
- package/CHANGELOG.md +17 -0
- package/android/build.gradle +3 -2
- package/android/src/main/java/expo/modules/walletcore/ExpoWalletCoreModule.kt +6 -11
- package/ios/ExpoWalletCore.podspec +1 -1
- package/ios/ExpoWalletCoreModule.swift +8 -1
- package/package.json +3 -3
- package/src/ExpoWalletCoreModule.ts +1 -6
- package/src/index.test.ts +41 -0
- package/src/index.ts +28 -31
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @vultisig/walletcore-native
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1541](https://github.com/vultisig/vultisig-sdk/pull/1541) [`b9f81af`](https://github.com/vultisig/vultisig-sdk/commit/b9f81af9065a5c0bfc2f86f8fb20aa51e670ab77) Thanks [@realpaaao](https://github.com/realpaaao)! - Add Robinhood Chain (Arbitrum Orbit EVM L2, chain id 4663, ETH gas). Swaps enabled via LiFi and KyberSwap.
|
|
8
|
+
|
|
9
|
+
## 0.1.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#272](https://github.com/vultisig/vultisig-sdk/pull/272) [`496fa54`](https://github.com/vultisig/vultisig-sdk/commit/496fa54a7132d14c82933f27b78b428d4c0caf4a) Thanks [@NeOMakinG](https://github.com/NeOMakinG)! - Fix Android Kotlin compilation against TrustWallet JNI bindings
|
|
14
|
+
- Import `wallet.core.java.AnySigner` (lives outside `wallet.core.jni.*`)
|
|
15
|
+
- Fix `anyAddressIsValidSS58` return type (`Nothing` -> `Boolean`) so Kotlin can reify the type parameter
|
|
16
|
+
- Use `AnySigner.nativePlan(byte[], int)` instead of protobuf `plan()` overload that requires 3 params
|
|
17
|
+
- Pass required `bounceable` and `testnet` boolean params to `TONAddressConverter.toUserFriendly`
|
package/android/build.gradle
CHANGED
|
@@ -47,7 +47,8 @@ repositories {
|
|
|
47
47
|
username = System.getenv("GITHUB_USER")
|
|
48
48
|
?: System.getenv("GITHUB_ACTOR")
|
|
49
49
|
?: "token"
|
|
50
|
-
password = System.getenv("
|
|
50
|
+
password = System.getenv("TRUSTWALLET_PAT")
|
|
51
|
+
?: System.getenv("GITHUB_TOKEN")
|
|
51
52
|
?: System.getenv("GH_TOKEN")
|
|
52
53
|
?: ""
|
|
53
54
|
}
|
|
@@ -60,7 +61,7 @@ repositories {
|
|
|
60
61
|
dependencies {
|
|
61
62
|
implementation project(':expo-modules-core')
|
|
62
63
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.8.10')}"
|
|
63
|
-
implementation 'com.trustwallet:wallet-core:4.
|
|
64
|
+
implementation 'com.trustwallet:wallet-core:4.7.0'
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
def safeExtGet(prop, fallback) {
|
|
@@ -3,6 +3,7 @@ package expo.modules.walletcore
|
|
|
3
3
|
import expo.modules.kotlin.modules.Module
|
|
4
4
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
5
|
import wallet.core.jni.*
|
|
6
|
+
import wallet.core.java.AnySigner
|
|
6
7
|
|
|
7
8
|
class ExpoWalletCoreModule : Module() {
|
|
8
9
|
// NOTE: nextHandle and the key/wallet maps are accessed from the Expo module
|
|
@@ -64,6 +65,7 @@ class ExpoWalletCoreModule : Module() {
|
|
|
64
65
|
"cronosChain" to CoinType.CRONOSCHAIN,
|
|
65
66
|
"blast" to CoinType.BLAST,
|
|
66
67
|
"zksync" to CoinType.ZKSYNC,
|
|
68
|
+
"robinhoodChain" to CoinType.ROBINHOODCHAIN,
|
|
67
69
|
"osmosis" to CoinType.OSMOSIS,
|
|
68
70
|
"terraV2" to CoinType.TERRAV2,
|
|
69
71
|
"noble" to CoinType.NOBLE,
|
|
@@ -143,15 +145,8 @@ class ExpoWalletCoreModule : Module() {
|
|
|
143
145
|
AnyAddress.isValidBech32(address, CoinType.createFromValue(coinType), hrp)
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// result, so callers know this code path is not supported yet.
|
|
149
|
-
Function("anyAddressIsValidSS58") { _address: String, _coinType: Int, _ss58Prefix: Int ->
|
|
150
|
-
throw Exception(
|
|
151
|
-
"anyAddressIsValidSS58 is not supported on Android: the JNI binding " +
|
|
152
|
-
"does not expose an SS58-prefix overload. Use anyAddressIsValid as a " +
|
|
153
|
-
"fallback (ignores ss58Prefix) or implement a pure-Kotlin SS58 check."
|
|
154
|
-
)
|
|
148
|
+
Function("anyAddressIsValidSS58") { address: String, coinType: Int, ss58Prefix: Int ->
|
|
149
|
+
AnyAddress.isValidSS58(address, CoinType.createFromValue(coinType), ss58Prefix)
|
|
155
150
|
}
|
|
156
151
|
|
|
157
152
|
Function("anyAddressCreateWithString") { address: String, coinType: Int ->
|
|
@@ -198,7 +193,7 @@ class ExpoWalletCoreModule : Module() {
|
|
|
198
193
|
// AnySigner
|
|
199
194
|
Function("anySignerPlan") { txInputDataBase64: String, coinType: Int ->
|
|
200
195
|
val txData = android.util.Base64.decode(txInputDataBase64, android.util.Base64.NO_WRAP)
|
|
201
|
-
val result = AnySigner.
|
|
196
|
+
val result = AnySigner.nativePlan(txData, coinType)
|
|
202
197
|
android.util.Base64.encodeToString(result, android.util.Base64.NO_WRAP)
|
|
203
198
|
}
|
|
204
199
|
|
|
@@ -338,7 +333,7 @@ class ExpoWalletCoreModule : Module() {
|
|
|
338
333
|
|
|
339
334
|
// TONAddressConverter
|
|
340
335
|
Function("tonAddressToUserFriendly") { address: String ->
|
|
341
|
-
TONAddressConverter.toUserFriendly(address)
|
|
336
|
+
TONAddressConverter.toUserFriendly(address, false, false)
|
|
342
337
|
}
|
|
343
338
|
|
|
344
339
|
// SolanaAddress
|
|
@@ -92,6 +92,7 @@ public class ExpoWalletCoreModule: Module {
|
|
|
92
92
|
"polygon": .polygon, "optimism": .optimism,
|
|
93
93
|
"cronosChain": .cronosChain, "blast": .blast,
|
|
94
94
|
"zksync": .zksync, "osmosis": .osmosis,
|
|
95
|
+
"robinhoodChain": .robinhoodChain,
|
|
95
96
|
"terraV2": .terraV2, "terra": .terra,
|
|
96
97
|
"noble": .noble, "kujira": .kujira,
|
|
97
98
|
"dydx": .dydx, "akash": .akash, "mantle": .mantle, "sei": .sei,
|
|
@@ -342,7 +343,13 @@ public class ExpoWalletCoreModule: Module {
|
|
|
342
343
|
throw NSError(domain: "ExpoWalletCore", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid HDWallet handle"])
|
|
343
344
|
}
|
|
344
345
|
let ct = try coinTypeFromValue(coinType)
|
|
345
|
-
let key = wallet.getKey(coin: ct, derivationPath: derivationPath)
|
|
346
|
+
guard let key = wallet.getKey(coin: ct, derivationPath: derivationPath) else {
|
|
347
|
+
throw NSError(
|
|
348
|
+
domain: "ExpoWalletCore",
|
|
349
|
+
code: -1,
|
|
350
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to derive PrivateKey for CoinType raw value \(coinType)"]
|
|
351
|
+
)
|
|
352
|
+
}
|
|
346
353
|
return storePrivateKey(key)
|
|
347
354
|
}
|
|
348
355
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/walletcore-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Native WalletCore bridge for Vultisig SDK (React Native / Expo)",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"@noble/hashes": "^1.8.0"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"expo": ">=
|
|
18
|
+
"expo": ">=56.0.8"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"expo": ">=
|
|
21
|
+
"expo": ">=56.0.12"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
@@ -129,12 +129,7 @@ interface ExpoWalletCoreModuleType {
|
|
|
129
129
|
hdWalletGetAddressForCoin(handle: number, coinType: number): string
|
|
130
130
|
|
|
131
131
|
/** Get the extended private key. */
|
|
132
|
-
hdWalletGetExtendedPrivateKey(
|
|
133
|
-
handle: number,
|
|
134
|
-
purposeValue: number,
|
|
135
|
-
coinType: number,
|
|
136
|
-
versionValue: number
|
|
137
|
-
): string
|
|
132
|
+
hdWalletGetExtendedPrivateKey(handle: number, purposeValue: number, coinType: number, versionValue: number): string
|
|
138
133
|
|
|
139
134
|
/** Free an HDWallet handle. */
|
|
140
135
|
freeHDWallet(handle: number): void
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
const native = vi.hoisted(() => ({
|
|
4
|
+
derivationPath: vi.fn((_coinType: number) => "m/44'/60'/0'/0/0"),
|
|
5
|
+
deriveAddressFromPublicKey: vi.fn((_coinType: number, _handle: number) => '0x1234'),
|
|
6
|
+
}))
|
|
7
|
+
|
|
8
|
+
vi.mock('expo-modules-core', () => ({
|
|
9
|
+
requireNativeModule: () => native,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import { type NativePublicKeyInstance, NativeWalletCore } from './index'
|
|
13
|
+
|
|
14
|
+
describe('NativeWalletCore Robinhood contract', () => {
|
|
15
|
+
beforeEach(() => vi.clearAllMocks())
|
|
16
|
+
|
|
17
|
+
it('passes the canonical finite coin type to the native derivation bridge', () => {
|
|
18
|
+
const walletCore = NativeWalletCore.getInstance()
|
|
19
|
+
const coinType = walletCore.CoinType.robinhoodChain
|
|
20
|
+
|
|
21
|
+
expect(coinType).toBe(10_004_663)
|
|
22
|
+
expect(Number.isInteger(coinType)).toBe(true)
|
|
23
|
+
expect(walletCore.CoinTypeExt.derivationPath(coinType)).toBe("m/44'/60'/0'/0/0")
|
|
24
|
+
expect(native.derivationPath).toHaveBeenCalledWith(10_004_663)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('uses the same EVM address derivation contract as Ethereum', () => {
|
|
28
|
+
const walletCore = NativeWalletCore.getInstance()
|
|
29
|
+
const publicKey = { _handle: 7 } as NativePublicKeyInstance
|
|
30
|
+
|
|
31
|
+
const ethereumAddress = walletCore.CoinTypeExt.deriveAddressFromPublicKey(walletCore.CoinType.ethereum, publicKey)
|
|
32
|
+
const robinhoodAddress = walletCore.CoinTypeExt.deriveAddressFromPublicKey(
|
|
33
|
+
walletCore.CoinType.robinhoodChain,
|
|
34
|
+
publicKey
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
expect(robinhoodAddress).toBe(ethereumAddress)
|
|
38
|
+
expect(native.deriveAddressFromPublicKey).toHaveBeenNthCalledWith(1, 60, 7)
|
|
39
|
+
expect(native.deriveAddressFromPublicKey).toHaveBeenNthCalledWith(2, 10_004_663, 7)
|
|
40
|
+
})
|
|
41
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Provides a JS object matching the WalletCore API shape expected by the SDK.
|
|
6
6
|
*/
|
|
7
7
|
import { keccak_256 } from '@noble/hashes/sha3'
|
|
8
|
+
|
|
8
9
|
import ExpoWalletCore from './ExpoWalletCoreModule'
|
|
9
10
|
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
@@ -95,13 +96,22 @@ export interface WalletCoreLike {
|
|
|
95
96
|
isValidBech32(address: string, coinType: number, hrp: string): boolean
|
|
96
97
|
isValidSS58(address: string, coinType: number, ss58Prefix: number): boolean
|
|
97
98
|
createWithString(address: string, coinType: number): NativeAnyAddressInstance
|
|
98
|
-
createBech32WithPublicKey(
|
|
99
|
+
createBech32WithPublicKey(
|
|
100
|
+
publicKey: NativePublicKeyInstance,
|
|
101
|
+
coinType: number,
|
|
102
|
+
hrp: string
|
|
103
|
+
): NativeAnyAddressInstance
|
|
99
104
|
createBech32(address: string, coinType: number, hrp: string): NativeAnyAddressInstance
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
TransactionCompiler: {
|
|
103
108
|
preImageHashes(coinType: number, txInputData: Uint8Array): Uint8Array
|
|
104
|
-
compileWithSignatures(
|
|
109
|
+
compileWithSignatures(
|
|
110
|
+
coinType: number,
|
|
111
|
+
txInputData: Uint8Array,
|
|
112
|
+
signatures: NativeDataVectorInstance,
|
|
113
|
+
publicKeys: NativeDataVectorInstance
|
|
114
|
+
): Uint8Array
|
|
105
115
|
}
|
|
106
116
|
|
|
107
117
|
DataVector: {
|
|
@@ -161,31 +171,27 @@ export interface WalletCoreLike {
|
|
|
161
171
|
// ---------------------------------------------------------------------------
|
|
162
172
|
// Helpers — base64 <-> Uint8Array
|
|
163
173
|
// ---------------------------------------------------------------------------
|
|
174
|
+
//
|
|
175
|
+
// Both helpers assume `Buffer` is globally available. On RN/Hermes that is
|
|
176
|
+
// guaranteed because `@vultisig/sdk`'s react-native entrypoint installs the
|
|
177
|
+
// buffer polyfill before any module graph import runs; on Node it is a
|
|
178
|
+
// builtin. Consumers importing `@vultisig/walletcore-native` directly
|
|
179
|
+
// (without going through @vultisig/sdk's RN entrypoint) must polyfill
|
|
180
|
+
// `globalThis.Buffer` themselves before invoking any WalletCore method.
|
|
164
181
|
|
|
165
182
|
function toBase64(bytes: Uint8Array | Buffer): string {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
let binary = ''
|
|
170
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
171
|
-
binary += String.fromCharCode(bytes[i]!)
|
|
172
|
-
}
|
|
173
|
-
return btoa(binary)
|
|
183
|
+
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
|
184
|
+
return buf.toString('base64')
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
function fromBase64(b64: string): Uint8Array {
|
|
177
|
-
|
|
178
|
-
const bytes = new Uint8Array(binary.length)
|
|
179
|
-
for (let i = 0; i < binary.length; i++) {
|
|
180
|
-
bytes[i] = binary.charCodeAt(i)
|
|
181
|
-
}
|
|
182
|
-
return bytes
|
|
188
|
+
return new Uint8Array(Buffer.from(b64, 'base64'))
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
// ---------------------------------------------------------------------------
|
|
186
192
|
// CoinType enum — numeric values matching TrustWallet's CoinType
|
|
187
|
-
// Values sourced from TrustWallet wallet-core v4.
|
|
188
|
-
// https://github.com/trustwallet/wallet-core/blob/
|
|
193
|
+
// Values sourced from TrustWallet wallet-core v4.7.0:
|
|
194
|
+
// https://github.com/trustwallet/wallet-core/blob/4.7.0/include/TrustWalletCore/TWCoinType.h
|
|
189
195
|
// ---------------------------------------------------------------------------
|
|
190
196
|
|
|
191
197
|
const CoinTypeValues: Record<string, number> = {
|
|
@@ -216,6 +222,7 @@ const CoinTypeValues: Record<string, number> = {
|
|
|
216
222
|
cronosChain: 10000025,
|
|
217
223
|
blast: 81457,
|
|
218
224
|
zksync: 10000324,
|
|
225
|
+
robinhoodChain: 10004663,
|
|
219
226
|
osmosis: 10000118,
|
|
220
227
|
terraV2: 10000330,
|
|
221
228
|
noble: 18000118,
|
|
@@ -601,9 +608,7 @@ function abiEncode(name: string, params: AbiParam[]): Uint8Array {
|
|
|
601
608
|
|
|
602
609
|
// Concatenate: selector + heads + tails
|
|
603
610
|
const totalLen =
|
|
604
|
-
selector.length +
|
|
605
|
-
headParts.reduce((sum, p) => sum + p.length, 0) +
|
|
606
|
-
tailParts.reduce((sum, p) => sum + p.length, 0)
|
|
611
|
+
selector.length + headParts.reduce((sum, p) => sum + p.length, 0) + tailParts.reduce((sum, p) => sum + p.length, 0)
|
|
607
612
|
|
|
608
613
|
const result = new Uint8Array(totalLen)
|
|
609
614
|
let offset = 0
|
|
@@ -785,16 +790,8 @@ export class NativeWalletCore {
|
|
|
785
790
|
const dataB64 = ExpoWalletCore.anyAddressData(address, coinType)
|
|
786
791
|
return new NativeAnyAddress(desc, dataB64)
|
|
787
792
|
},
|
|
788
|
-
createBech32WithPublicKey(
|
|
789
|
-
publicKey
|
|
790
|
-
coinType: number,
|
|
791
|
-
hrp: string
|
|
792
|
-
): NativeAnyAddress {
|
|
793
|
-
const desc = ExpoWalletCore.anyAddressCreateBech32WithPublicKey(
|
|
794
|
-
publicKey._handle,
|
|
795
|
-
coinType,
|
|
796
|
-
hrp
|
|
797
|
-
)
|
|
793
|
+
createBech32WithPublicKey(publicKey: NativePublicKey, coinType: number, hrp: string): NativeAnyAddress {
|
|
794
|
+
const desc = ExpoWalletCore.anyAddressCreateBech32WithPublicKey(publicKey._handle, coinType, hrp)
|
|
798
795
|
return new NativeAnyAddress(desc)
|
|
799
796
|
},
|
|
800
797
|
createBech32(address: string, coinType: number, hrp: string): NativeAnyAddress {
|