@chainberry/trust-wallet-core 2.0.0 → 2.5.1
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/{TrustWalletCoreModule.podspec → ChainberryTrustWalletCoreModule.podspec} +5 -4
- package/README.md +27 -25
- package/android/build.gradle +29 -6
- package/android/libs/README.md +34 -0
- package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.aar +0 -0
- package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.aar.md5 +1 -0
- package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.aar.sha1 +1 -0
- package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.pom +22 -0
- package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.pom.md5 +1 -0
- package/android/libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.pom.sha1 +1 -0
- package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar +0 -0
- package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar.md5 +1 -0
- package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar.sha1 +1 -0
- package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom +21 -0
- package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom.md5 +1 -0
- package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom.sha1 +1 -0
- package/android/libs/download.sh +52 -0
- package/android/src/androidTest/java/com/chainberry/trustwalletcore/AddressDerivationConformanceTest.kt +106 -0
- package/android/src/androidTest/java/com/chainberry/trustwalletcore/SigningConformanceTest.kt +186 -0
- package/android/src/main/java/com/chainberry/trustwalletcore/AmountParsing.kt +45 -0
- package/android/src/main/java/com/chainberry/trustwalletcore/Bech32.kt +68 -0
- package/android/src/main/java/com/chainberry/trustwalletcore/ChainSigning.kt +884 -0
- package/android/src/main/java/com/chainberry/trustwalletcore/ChainberryTrustWalletCoreModule.kt +227 -0
- package/android/src/main/java/com/chainberry/trustwalletcore/NativeWalletStore.kt +888 -0
- package/android/src/test/java/com/chainberry/trustwalletcore/AmountParsingConformanceTest.kt +57 -0
- package/android/src/test/java/com/chainberry/trustwalletcore/Bech32Test.kt +35 -0
- package/android/src/test/java/com/chainberry/trustwalletcore/NativeWalletStoreTest.kt +344 -0
- package/expo-module.config.json +3 -2
- package/ios/AmountParsing.swift +62 -0
- package/ios/Bech32.swift +66 -0
- package/ios/ChainSigning.swift +978 -0
- package/ios/ChainberryTrustWalletCoreModule.swift +336 -0
- package/ios/ConformanceTests/AddressDerivationConformanceTests.swift +39 -0
- package/ios/ConformanceTests/SigningConformanceTests.swift +295 -0
- package/ios/NativeWalletStore.swift +288 -0
- package/package.json +4 -3
- package/src/index.ts +42 -13
- package/android/src/main/java/expo/modules/trustwalletcore/ChainSigning.kt +0 -299
- package/android/src/main/java/expo/modules/trustwalletcore/NativeWalletStore.kt +0 -182
- package/android/src/main/java/expo/modules/trustwalletcore/TrustWalletCoreModule.kt +0 -91
- package/ios/TrustWalletCoreModule.swift +0 -107
|
@@ -3,19 +3,20 @@ require 'json'
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
4
|
|
|
5
5
|
Pod::Spec.new do |s|
|
|
6
|
-
s.name = '
|
|
6
|
+
s.name = 'ChainberryTrustWalletCoreModule'
|
|
7
7
|
s.version = package['version']
|
|
8
8
|
s.summary = package['description']
|
|
9
9
|
s.description = s.summary
|
|
10
10
|
s.homepage = 'https://github.com/Chainberry-com/trust-wallet-core'
|
|
11
11
|
s.license = package['license']
|
|
12
12
|
s.author = 'Chainberry'
|
|
13
|
-
s.platform = :ios, '
|
|
13
|
+
s.platform = :ios, '15.1'
|
|
14
14
|
s.source = { git: 'git@github.com:Chainberry-com/trust-wallet-core.git', tag: "v#{package['version']}" }
|
|
15
15
|
s.static_framework = true
|
|
16
16
|
|
|
17
|
-
s.source_files
|
|
17
|
+
s.source_files = 'ios/**/*.{h,m,mm,swift}'
|
|
18
|
+
s.exclude_files = 'ios/ConformanceTests/**'
|
|
18
19
|
|
|
19
20
|
s.dependency 'ExpoModulesCore'
|
|
20
|
-
s.dependency 'TrustWalletCore'
|
|
21
|
+
s.dependency 'TrustWalletCore', '4.1.19'
|
|
21
22
|
end
|
package/README.md
CHANGED
|
@@ -10,28 +10,13 @@ Supported chains: Ethereum, BNB Smart Chain, Polygon, Solana, Tron, TON, Bitcoin
|
|
|
10
10
|
npx expo install @chainberry/trust-wallet-core
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
This is an Expo
|
|
13
|
+
This is an Expo native module with native Android/iOS code. It uses Expo's autolinking mechanism and does not ship an Expo config plugin. A development build is required (`expo prebuild` / EAS Build) — it will not work in Expo Go.
|
|
14
14
|
|
|
15
|
-
### Android: GitHub
|
|
15
|
+
### Android: no GitHub credentials needed
|
|
16
16
|
|
|
17
|
-
Trust Wallet Core's Android artifact is published to GitHub Packages, which requires authentication even though the package itself is public.
|
|
17
|
+
Trust Wallet Core's Android artifact is only published to GitHub Packages, which requires authentication even though the package itself is public. To avoid making that a requirement for every dev/CI machine, `com.trustwallet:wallet-core` and its `wallet-core-proto` dependency are vendored locally as a plain Maven repo in `android/libs/` — `android/build.gradle` resolves from there first, so a normal `./gradlew` build needs no credentials at all. See `android/libs/README.md` for how it's kept up to date.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```sh
|
|
22
|
-
# Env vars (CI / one-off terminal)
|
|
23
|
-
export GITHUB_ACTOR=your-github-username
|
|
24
|
-
export GITHUB_TOKEN=ghp_xxxxxxxxxxxx # classic PAT, read:packages scope only
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
or add to `~/.gradle/gradle.properties` (permanent local dev setup):
|
|
28
|
-
|
|
29
|
-
```properties
|
|
30
|
-
gpr.user=your-github-username
|
|
31
|
-
gpr.key=ghp_xxxxxxxxxxxx
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Generate a token at github.com/settings/tokens → "classic" → check `read:packages`.
|
|
19
|
+
GitHub Packages auth is still needed (via `GITHUB_ACTOR`/`GITHUB_TOKEN` env vars or `gpr.user`/`gpr.key` in `~/.gradle/gradle.properties`) only when bumping the pinned wallet-core version — see `android/libs/download.sh`.
|
|
35
20
|
|
|
36
21
|
### iOS
|
|
37
22
|
|
|
@@ -42,7 +27,12 @@ Android biometric gating additionally pulls in `androidx.biometric:biometric:1.1
|
|
|
42
27
|
## Usage
|
|
43
28
|
|
|
44
29
|
```ts
|
|
45
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
createWallet,
|
|
32
|
+
importWallet,
|
|
33
|
+
signTransaction,
|
|
34
|
+
exportMnemonic,
|
|
35
|
+
} from "@chainberry/trust-wallet-core";
|
|
46
36
|
|
|
47
37
|
const { walletId, addresses } = await createWallet(); // 128-bit / 12-word by default
|
|
48
38
|
// addresses: { ethereum: "0x...", solana: "...", bnb: "0x...", bitcoin: "...", ... }
|
|
@@ -58,10 +48,10 @@ const mnemonic = await exportMnemonic(walletId);
|
|
|
58
48
|
|
|
59
49
|
## API
|
|
60
50
|
|
|
61
|
-
- `createWallet(strength = 128
|
|
62
|
-
- `importWallet(mnemonic
|
|
51
|
+
- `createWallet(strength = 128)` — generates a new BIP-39 mnemonic and persists it natively (Keychain on iOS / Keystore-backed file on Android, biometry-or-passcode gated). Returns `{ walletId, addresses }` — the mnemonic itself never leaves native code. No BIP-39 passphrase support: `signTransaction` always reconstructs the wallet with an empty passphrase, so a caller-supplied one would derive addresses from a seed different from the one actually used to sign.
|
|
52
|
+
- `importWallet(mnemonic)` — validates and persists an existing mnemonic the same way. The `mnemonic` argument is a one-time exposure from the caller (e.g. a text-entry backup-restore screen); discard your own copy immediately after this call resolves.
|
|
63
53
|
- `listWallets()` — returns `{ walletId, addresses }[]` for every persisted wallet, reading only the ungated metadata store. No biometric prompt.
|
|
64
|
-
- `deleteWallet(walletId)` — removes the wallet's native key material and metadata entry. Irreversible;
|
|
54
|
+
- `deleteWallet(walletId)` — removes the wallet's native key material and metadata entry. Irreversible; requires a fresh biometric/passcode confirmation before deletion proceeds on both platforms.
|
|
65
55
|
- `signTransaction(walletId, chain, unsignedTx)` — triggers a native biometry/passcode prompt, then derives the key and signs entirely inside native code. Returns `{ signedTx, meta? }`; `meta` currently only carries TON's `txHash`.
|
|
66
56
|
- `exportMnemonic(walletId)` — the one sanctioned mnemonic exposure. Biometry/passcode gated. Use only for an explicit "reveal recovery phrase" backup screen; don't hold the result in app state beyond that screen's lifetime.
|
|
67
57
|
|
|
@@ -69,11 +59,23 @@ const mnemonic = await exportMnemonic(walletId);
|
|
|
69
59
|
|
|
70
60
|
Mnemonic and derived private keys are generated, persisted, and used for signing entirely inside this module's native code (Swift/Kotlin) — they are never serialized back across the JS bridge, with the single exception of `exportMnemonic`'s explicit backup flow. This is a deliberate change from this module's earlier version, which returned raw private keys to JS on every address derivation; that let a compromised/malicious JS dependency, an attached JS debugger, or a JS-heap memory dump read wallet secrets in full. Now the JS runtime never holds them at all.
|
|
71
61
|
|
|
72
|
-
Storage: one biometry-or-passcode-gated secret per wallet (`SecAccessControl` + iOS Keychain;
|
|
62
|
+
Storage: one biometry-or-passcode-gated secret per wallet (`SecAccessControl` + iOS Keychain; an Android Keystore AES key gating an encrypted on-disk file), plus a separate, ungated metadata entry (`walletId` → addresses) for read-only UI that shouldn't need a biometric prompt just to show an address or balance.
|
|
63
|
+
|
|
64
|
+
**Android hardware backing is best-effort, not guaranteed.** Key creation requests StrongBox first (API 28+), falling back to a plain Keystore key (which Keymaster backs with a TEE on virtually all real devices, but which can be software-only on an emulator or a device with no secure hardware at all) on `StrongBoxUnavailableException` or below API 28. The actual security level achieved is verified via `KeyInfo` right after creation and logged (`NativeWalletStore` logcat tag) — a software-only key is tolerated rather than blocking wallet creation, so this is a best-effort hardening measure, not an enforced guarantee. Don't assume every wallet on every device is hardware-backed; check the logs on a specific device/build if that matters for your threat model.
|
|
73
65
|
|
|
74
66
|
Bitcoin Cash is derivation-only: sending BCH is unsupported both here and upstream (`chainberry-wallet`'s self-custody transaction preparation has no BCH case), so this module only derives its address.
|
|
75
67
|
|
|
76
|
-
|
|
68
|
+
Both platforms pin **Trust Wallet Core 4.1.19** (`com.trustwallet:wallet-core:4.1.19` in `android/build.gradle`; `s.dependency 'TrustWalletCore', '4.1.19'` in the podspec).
|
|
69
|
+
|
|
70
|
+
**Address derivation is verified for all 10 chains** in `conformance/address-derivation-vectors.json`, asserted by the Android instrumented test (`src/androidTest/.../AddressDerivationConformanceTest.kt`; run via `./gradlew connectedDebugAndroidTest`). Methodology: real on-device 4.1.19 addresses were harvested from the instrumented test running on an emulator, cross-checked against an independent derivation via the WASM build (`@trustwallet/wallet-core` 3.3.3, run standalone in Node — a different upstream release than the pinned 4.1.19, used only as a second data point); on-device 4.1.19 is authoritative wherever the two disagree, since that's what the app actually ships. They agreed on 6 of 7 previously-pending chains exactly; `ton` disagreed only in address-flag encoding (bounceable vs. non-bounceable — same underlying key/hash, see that fixture entry's `_note`). This same run also caught a real bug: the Ethereum/BNB/Polygon address that had been marked `"verified"` since before this pass was actually wrong — the instrumented test that should have caught it had never successfully executed (two pre-existing bugs: `coin.name()` didn't compile against this Kotlin binding, and no `testInstrumentationRunner` was configured, so `connectedAndroidTest` silently ran "0 tests" instead of failing). Both are fixed now; see the test file's header comment for details.
|
|
71
|
+
|
|
72
|
+
**Byte-for-byte signing output is verified for 8 of 9 signable chains** in `conformance/signing-vectors.json`, asserted by `src/androidTest/.../SigningConformanceTest.kt`. Each vector calls `ChainSigner.sign()` — the same call path production code uses — with a fixed, deterministic (not necessarily broadcast-valid) unsigned tx. `ton` is verified but _not_ byte-exact-asserted: `signTon()` embeds a wall-clock `expireAt` into the signed payload, so its output legitimately differs every run — the test instead checks the output is a well-formed signed BOC. `bitcoincash` has no signing vector (sending is unsupported, see above).
|
|
73
|
+
|
|
74
|
+
Both Android suites are CI-gated on every push/PR (`.github/workflows/ci.yml`'s `android-unit-tests` and `android-instrumented-tests` jobs, via `example/` — see that folder's README for why an Expo host app is needed to build this module at all). iOS's CI job is still a structural podspec lint only; see the conformance-suite note below for what's missing to close that gap.
|
|
75
|
+
|
|
76
|
+
**Tron divergence resolved.** iOS's `signTron` used to hand wallet-core the full `rawJson` and return its own reconstruction, diverging from Android's `txId`-only input + manual JSON reassembly — and `TronSigningInput` has no `rawJson` field in the pinned 4.1.19 anyway, so the old iOS code didn't compile. iOS now signs the same way Android does: `TronSigningInput.txID` set to the digest, signature reassembled into `{...tx, signature}` in app code (see `ios/ChainSigning.swift`'s `signTron`). Same key + same digest is guaranteed to produce the same ECDSA signature, so this is a structural fix, not something that needs a device to confirm.
|
|
77
|
+
|
|
78
|
+
**iOS conformance suites are written but not yet wired into a runnable target.** `ios/ConformanceTests/AddressDerivationConformanceTests.swift` and `SigningConformanceTests.swift` mirror the Android fixtures above (all 10 address-derivation chains, the same 8 signing vectors, including a `testTron()` that asserts the reassembled signature matches Android's byte-for-byte). Neither file is part of the `ConformanceTests/` SwiftPM package (which still only builds the amount-parsing target — these two `import WalletCore`/`import XCTest`, which that dependency-free package deliberately avoids) or of any Xcode project (`ios/` is gitignored, regenerated by `expo prebuild`, so nothing durable lives there). An iOS engineer still needs to add both files to an XCTest target in the host app's workspace that links `WalletCore.xcframework`, run them on a Mac, and promote `conformance/signing-vectors.json`'s `tron` vector off `"verified-android-only"` once that run confirms the signature match. Until then, `ChainKey.coinType` mapping identically to Android's makes address derivation _likely_ correct on iOS, but this hasn't been independently run on-device.
|
|
77
79
|
|
|
78
80
|
## License
|
|
79
81
|
|
package/android/build.gradle
CHANGED
|
@@ -12,12 +12,16 @@ apply from: new File(
|
|
|
12
12
|
applyKotlinExpoModulesCorePlugin()
|
|
13
13
|
|
|
14
14
|
android {
|
|
15
|
-
namespace '
|
|
16
|
-
compileSdkVersion
|
|
15
|
+
namespace 'com.chainberry.trustwalletcore'
|
|
16
|
+
compileSdkVersion 36
|
|
17
17
|
|
|
18
18
|
defaultConfig {
|
|
19
19
|
minSdkVersion 24
|
|
20
|
-
targetSdkVersion
|
|
20
|
+
targetSdkVersion 36
|
|
21
|
+
// Without this, AGP defaults to the legacy android.test.InstrumentationTestRunner, which
|
|
22
|
+
// cannot discover @RunWith(AndroidJUnit4::class)-annotated tests at all (connectedAndroidTest
|
|
23
|
+
// silently reports "0 tests"/"No tests found" instead of running AddressDerivationConformanceTest).
|
|
24
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
compileOptions {
|
|
@@ -30,9 +34,14 @@ android {
|
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
// ─── wallet-core
|
|
34
|
-
//
|
|
35
|
-
//
|
|
37
|
+
// ─── wallet-core artifact ──────────────────────────────────────────────────
|
|
38
|
+
// com.trustwallet:wallet-core and its wallet-core-proto dependency are vendored
|
|
39
|
+
// in libs/ as a plain local Maven repo, so a normal build needs NO GitHub
|
|
40
|
+
// credentials at all — see libs/README.md for how it got there and how to
|
|
41
|
+
// re-vendor when bumping the pinned version below.
|
|
42
|
+
//
|
|
43
|
+
// The GitHub Packages repo is kept as a fallback (e.g. resolving a version not
|
|
44
|
+
// yet vendored) and needs auth even for this public package:
|
|
36
45
|
// 1. Env vars GITHUB_ACTOR / GITHUB_TOKEN (CI / one-off terminal)
|
|
37
46
|
// 2. Gradle props gpr.user / gpr.key in (permanent dev setup)
|
|
38
47
|
// ~/.gradle/gradle.properties
|
|
@@ -49,6 +58,8 @@ def githubToken = System.getenv("GITHUB_TOKEN")
|
|
|
49
58
|
?: (project.hasProperty("gpr.key") ? project.property("gpr.key") : "")
|
|
50
59
|
|
|
51
60
|
repositories {
|
|
61
|
+
maven { url = uri("$projectDir/libs") }
|
|
62
|
+
|
|
52
63
|
maven {
|
|
53
64
|
url = uri("https://maven.pkg.github.com/trustwallet/wallet-core")
|
|
54
65
|
credentials {
|
|
@@ -66,4 +77,16 @@ dependencies {
|
|
|
66
77
|
implementation 'com.google.protobuf:protobuf-javalite:3.21.9'
|
|
67
78
|
// BiometricPrompt (biometry-or-device-credential gating on the Keystore-backed wallet cipher)
|
|
68
79
|
implementation 'androidx.biometric:biometric:1.1.0'
|
|
80
|
+
|
|
81
|
+
// JVM unit tests (src/test) — AmountParsingConformanceTest reads the shared JSON fixture
|
|
82
|
+
// in ../conformance/. Use the pure-Java org.json artifact, not android.jar's stubbed
|
|
83
|
+
// org.json (which throws "Stub!" outside Robolectric/instrumented tests).
|
|
84
|
+
testImplementation 'junit:junit:4.13.2'
|
|
85
|
+
testImplementation 'org.json:json:20240303'
|
|
86
|
+
|
|
87
|
+
// Instrumented tests (src/androidTest) — AddressDerivationConformanceTest needs the
|
|
88
|
+
// TrustWalletCore JNI library, which can only load on a real device or emulator.
|
|
89
|
+
// Run via: ./gradlew connectedDebugAndroidTest
|
|
90
|
+
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
|
91
|
+
androidTestImplementation 'androidx.test:runner:1.5.2'
|
|
69
92
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Vendored wallet-core (local Maven repo)
|
|
2
|
+
|
|
3
|
+
`com.trustwallet:wallet-core` (and its `wallet-core-proto` dependency) are only
|
|
4
|
+
published to GitHub Packages, which requires authentication even to download a
|
|
5
|
+
public package. To spare every dev/CI machine from needing a
|
|
6
|
+
`read:packages` PAT, the resolved `.aar`/`.jar` + `.pom` files are vendored
|
|
7
|
+
here in a plain Maven-layout directory:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
libs/com/trustwallet/wallet-core/4.1.19/wallet-core-4.1.19.{aar,pom}
|
|
11
|
+
libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.{jar,pom}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`../build.gradle` points its `repositories {}` block at this directory
|
|
15
|
+
*before* the GitHub Packages fallback, so a normal build resolves entirely
|
|
16
|
+
from here — no credentials needed.
|
|
17
|
+
|
|
18
|
+
Files were downloaded from `maven.pkg.github.com/trustwallet/wallet-core` on
|
|
19
|
+
2026-09-04 and their sha1 checksums verified against GitHub's own
|
|
20
|
+
`.sha1` files (still alongside each artifact here).
|
|
21
|
+
|
|
22
|
+
## Bumping the pinned version
|
|
23
|
+
|
|
24
|
+
1. `./download.sh <new-version>` (needs `GITHUB_ACTOR`/`GITHUB_TOKEN` env vars,
|
|
25
|
+
or `gpr.user`/`gpr.key` in `~/.gradle/gradle.properties` — same credentials
|
|
26
|
+
the GitHub Packages fallback in `build.gradle` already uses).
|
|
27
|
+
2. Update the pinned version in `../build.gradle`
|
|
28
|
+
(`implementation 'com.trustwallet:wallet-core:...'`) and in
|
|
29
|
+
`../../ChainberryTrustWalletCoreModule.podspec` (`s.dependency 'TrustWalletCore', '...'`)
|
|
30
|
+
to keep both platforms on the same wallet-core release.
|
|
31
|
+
3. Delete the old version's directories under `com/trustwallet/wallet-core*/`
|
|
32
|
+
here (or leave them if you want to keep an easy rollback).
|
|
33
|
+
4. Re-run the conformance suite (`conformance/`) — a wallet-core bump can
|
|
34
|
+
change derivation/signing output.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3f07349ecbe013f2098684cc70cef49e
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
58c6ee87c3ab4fb90c6ef4e9ba4f78260740ca16
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
4
|
+
<!-- This module was also published with a richer model, Gradle metadata, -->
|
|
5
|
+
<!-- which should be used instead. Do not delete the following line which -->
|
|
6
|
+
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
|
|
7
|
+
<!-- that they should prefer consuming it instead. -->
|
|
8
|
+
<!-- do_not_remove: published-with-gradle-metadata -->
|
|
9
|
+
<modelVersion>4.0.0</modelVersion>
|
|
10
|
+
<groupId>com.trustwallet</groupId>
|
|
11
|
+
<artifactId>wallet-core</artifactId>
|
|
12
|
+
<version>4.1.19</version>
|
|
13
|
+
<packaging>aar</packaging>
|
|
14
|
+
<dependencies>
|
|
15
|
+
<dependency>
|
|
16
|
+
<groupId>com.trustwallet</groupId>
|
|
17
|
+
<artifactId>wallet-core-proto</artifactId>
|
|
18
|
+
<version>4.1.19</version>
|
|
19
|
+
<scope>compile</scope>
|
|
20
|
+
</dependency>
|
|
21
|
+
</dependencies>
|
|
22
|
+
</project>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
d4a399c80d4f896ae4d4ea6013f1f15f
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a00894bc91fbbbf496fd3792484082334363e0fe
|
|
Binary file
|
package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar.md5
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2c47413fd480c3ae3a4245f8487a343e
|
package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.jar.sha1
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1a68899feeb645d9895264d4c58e046dbcb3d528
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
4
|
+
<!-- This module was also published with a richer model, Gradle metadata, -->
|
|
5
|
+
<!-- which should be used instead. Do not delete the following line which -->
|
|
6
|
+
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
|
|
7
|
+
<!-- that they should prefer consuming it instead. -->
|
|
8
|
+
<!-- do_not_remove: published-with-gradle-metadata -->
|
|
9
|
+
<modelVersion>4.0.0</modelVersion>
|
|
10
|
+
<groupId>com.trustwallet</groupId>
|
|
11
|
+
<artifactId>wallet-core-proto</artifactId>
|
|
12
|
+
<version>4.1.19</version>
|
|
13
|
+
<dependencies>
|
|
14
|
+
<dependency>
|
|
15
|
+
<groupId>com.google.protobuf</groupId>
|
|
16
|
+
<artifactId>protobuf-javalite</artifactId>
|
|
17
|
+
<version>3.22.3</version>
|
|
18
|
+
<scope>compile</scope>
|
|
19
|
+
</dependency>
|
|
20
|
+
</dependencies>
|
|
21
|
+
</project>
|
package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom.md5
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
e3987a3948a049ac60b57fa808b8f8ae
|
package/android/libs/com/trustwallet/wallet-core-proto/4.1.19/wallet-core-proto-4.1.19.pom.sha1
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
90383b24ce13303b7c7a435ba815209115fa7d06
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Re-vendors com.trustwallet:wallet-core (+ its wallet-core-proto dependency)
|
|
3
|
+
# from GitHub Packages into this directory, laid out as a plain local Maven
|
|
4
|
+
# repo (com/<group>/<artifact>/<version>/...). build.gradle points at this
|
|
5
|
+
# directory first, so a normal build needs no GitHub credentials — only
|
|
6
|
+
# re-running this script (to bump the pinned version, or the first time
|
|
7
|
+
# someone sets this up) needs a token.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# GITHUB_ACTOR=you GITHUB_TOKEN=ghp_xxx ./download.sh 4.1.19
|
|
11
|
+
# or rely on gpr.user / gpr.key in ~/.gradle/gradle.properties (same
|
|
12
|
+
# credentials used by build.gradle's GitHub Packages fallback).
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
VERSION="${1:?Usage: download.sh <wallet-core version, e.g. 4.1.19>}"
|
|
16
|
+
LIBS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
|
+
|
|
18
|
+
GITHUB_USER="${GITHUB_ACTOR:-}"
|
|
19
|
+
GITHUB_PASS="${GITHUB_TOKEN:-}"
|
|
20
|
+
if [ -z "$GITHUB_USER" ] || [ -z "$GITHUB_PASS" ]; then
|
|
21
|
+
GRADLE_PROPS="$HOME/.gradle/gradle.properties"
|
|
22
|
+
if [ -f "$GRADLE_PROPS" ]; then
|
|
23
|
+
GITHUB_USER="${GITHUB_USER:-$(grep '^gpr.user=' "$GRADLE_PROPS" | cut -d= -f2-)}"
|
|
24
|
+
GITHUB_PASS="${GITHUB_PASS:-$(grep '^gpr.key=' "$GRADLE_PROPS" | cut -d= -f2-)}"
|
|
25
|
+
fi
|
|
26
|
+
fi
|
|
27
|
+
if [ -z "$GITHUB_USER" ] || [ -z "$GITHUB_PASS" ]; then
|
|
28
|
+
echo "error: no GitHub credentials found (env vars or ~/.gradle/gradle.properties gpr.user/gpr.key)" >&2
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
REGISTRY="https://maven.pkg.github.com/trustwallet/wallet-core"
|
|
33
|
+
|
|
34
|
+
# module:packaging pairs — wallet-core is an .aar, wallet-core-proto is a plain .jar
|
|
35
|
+
MODULES=("wallet-core:aar" "wallet-core-proto:jar")
|
|
36
|
+
|
|
37
|
+
for entry in "${MODULES[@]}"; do
|
|
38
|
+
artifact="${entry%%:*}"
|
|
39
|
+
ext="${entry##*:}"
|
|
40
|
+
dest="$LIBS_DIR/com/trustwallet/$artifact/$VERSION"
|
|
41
|
+
mkdir -p "$dest"
|
|
42
|
+
base="$REGISTRY/com/trustwallet/$artifact/$VERSION"
|
|
43
|
+
for file in "$artifact-$VERSION.pom" "$artifact-$VERSION.$ext" "$artifact-$VERSION.pom.sha1" "$artifact-$VERSION.$ext.sha1"; do
|
|
44
|
+
echo "fetching $file"
|
|
45
|
+
curl -sS -L -f -u "$GITHUB_USER:$GITHUB_PASS" -o "$dest/$file" "$base/$file"
|
|
46
|
+
done
|
|
47
|
+
# verify what we just wrote against GitHub's own sha1
|
|
48
|
+
( cd "$dest" && sha1sum -c "$artifact-$VERSION.pom.sha1" "$artifact-$VERSION.$ext.sha1" )
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
echo "done — vendored wallet-core $VERSION into $LIBS_DIR"
|
|
52
|
+
echo "remember to bump the version in ../build.gradle (dependencies block) and the podspec, and delete the old version's directories above if this is a version bump rather than a first-time vendor."
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
package com.chainberry.trustwalletcore
|
|
2
|
+
|
|
3
|
+
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
4
|
+
import org.junit.Assert.assertEquals
|
|
5
|
+
import org.junit.Assert.assertNotEquals
|
|
6
|
+
import org.junit.Test
|
|
7
|
+
import org.junit.runner.RunWith
|
|
8
|
+
import wallet.core.jni.CoinType
|
|
9
|
+
import wallet.core.jni.HDWallet
|
|
10
|
+
|
|
11
|
+
// Instrumented test — must run on a device or emulator (needs the TrustWalletCore JNI library).
|
|
12
|
+
// Run via: ./gradlew connectedDebugAndroidTest
|
|
13
|
+
//
|
|
14
|
+
// Verifies that HDWallet.getAddressForCoin produces the expected address for every chain
|
|
15
|
+
// under WalletCore 4.1.19 (the pinned version). The test mnemonic is the BIP39 standard
|
|
16
|
+
// test vector — never use it with real funds.
|
|
17
|
+
//
|
|
18
|
+
// All 10 chains were verified on-device (real emulator, WalletCore 4.1.19 JNI) on 2026-08-27,
|
|
19
|
+
// cross-checked against an independent derivation via the WASM build (@trustwallet/wallet-core
|
|
20
|
+
// 3.3.3, run in plain Node — see conformance/address-derivation-vectors.json's _note). On-device
|
|
21
|
+
// 4.1.19 is authoritative wherever the two disagree.
|
|
22
|
+
//
|
|
23
|
+
// IMPORTANT — this test did not actually run before this pass. Two pre-existing bugs prevented
|
|
24
|
+
// it from ever executing: (1) `coin.name()` doesn't compile against this Kotlin CoinType binding
|
|
25
|
+
// (name is a property, not a method — fixed here), and (2) no `testInstrumentationRunner` was
|
|
26
|
+
// configured in build.gradle, so AGP defaulted to the legacy runner, which cannot discover
|
|
27
|
+
// @RunWith(AndroidJUnit4::class) tests at all ("0 tests"/"No tests found", not a real pass).
|
|
28
|
+
// Once actually run, it immediately caught a real bug: the ETHEREUM/SMARTCHAIN "verified" address
|
|
29
|
+
// below was wrong (0x9d8A62f6...) — never actually checked against real WalletCore output despite
|
|
30
|
+
// being marked "verified". The corrected value below is the real on-device 4.1.19 result.
|
|
31
|
+
//
|
|
32
|
+
// For any NEW chain added to ChainKey in the future: add its CoinType to PENDING, run this test,
|
|
33
|
+
// read the printed address in logcat, verify it independently (e.g. against a TWC 4.1.19 REPL or
|
|
34
|
+
// the iOS companion test — see ConformanceTests/), then move it into VERIFIED.
|
|
35
|
+
//
|
|
36
|
+
// Human-readable source of truth: conformance/address-derivation-vectors.json.
|
|
37
|
+
@RunWith(AndroidJUnit4::class)
|
|
38
|
+
class AddressDerivationConformanceTest {
|
|
39
|
+
|
|
40
|
+
companion object {
|
|
41
|
+
init { System.loadLibrary("TrustWalletCore") }
|
|
42
|
+
|
|
43
|
+
const val MNEMONIC = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
44
|
+
|
|
45
|
+
// Chains with expected addresses confirmed against WalletCore 4.1.19, on a real device/emulator.
|
|
46
|
+
// ETH / BNB / POL all share CoinType.ETHEREUM (same secp256k1 key, BIP44 m/44'/60'/0'/0/0).
|
|
47
|
+
val VERIFIED = mapOf(
|
|
48
|
+
CoinType.ETHEREUM to "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", // ethereum / bnb / polygon
|
|
49
|
+
CoinType.SMARTCHAIN to "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", // bnb (same key as ethereum)
|
|
50
|
+
CoinType.BITCOIN to "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
|
|
51
|
+
CoinType.LITECOIN to "ltc1qjmxnz78nmc8nq77wuxh25n2es7rzm5c2rkk4wh",
|
|
52
|
+
CoinType.XRP to "rHsMGQEkVNJmpGWs8XUBoTBiAAbwxZN5v3",
|
|
53
|
+
CoinType.TRON to "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH",
|
|
54
|
+
// Non-bounceable (UQ...) — WalletCore 4.1.19's default for this CoinType. The WASM build
|
|
55
|
+
// (@trustwallet/wallet-core 3.3.3) derives the same underlying hash but defaults to the
|
|
56
|
+
// bounceable (EQ...) encoding instead — a version/binding difference in address-flag
|
|
57
|
+
// defaults, not a key-derivation discrepancy. On-device 4.1.19 (what the app actually ships)
|
|
58
|
+
// is authoritative here.
|
|
59
|
+
CoinType.TON to "UQAzWZa6nM5mJev91wGc7VCSfBoIsYRqKJpV78N8Add9-RKY",
|
|
60
|
+
CoinType.SOLANA to "GjJyeC1r2RgkuoCWMyPYkCWSGSGLcz266EaAkLA27AhL",
|
|
61
|
+
CoinType.BITCOINCASH to "bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
// Steady state is empty — add a chain's CoinType here (and drop it from VERIFIED) only while
|
|
65
|
+
// actively harvesting a newly-added chain's address for the first time.
|
|
66
|
+
val PENDING = emptyList<CoinType>()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@Test
|
|
70
|
+
fun verifiedAddressesMatch() {
|
|
71
|
+
val wallet = HDWallet(MNEMONIC, "")
|
|
72
|
+
for ((coin, expected) in VERIFIED) {
|
|
73
|
+
val actual = wallet.getAddressForCoin(coin)
|
|
74
|
+
assertEquals("address mismatch for coin=${coin.name}", expected, actual)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Regression test for a real bug: ChainSigner.addressForChain originally derived Litecoin's
|
|
79
|
+
// and Bitcoin Cash's hand-rolled testnet address from the identical path m/44'/1'/0'/0/0.
|
|
80
|
+
// BIP32 derivation only depends on (seed, path, curve) — CoinType alone doesn't perturb it
|
|
81
|
+
// when the literal path and curve (secp256k1 for both) are the same — so LTC and BCH silently
|
|
82
|
+
// derived the *same* key, and therefore the same address. Fixed by using each coin's own
|
|
83
|
+
// SLIP-44 index as the account (3rd) path component (see ChainSigner.utxoTestnetPath).
|
|
84
|
+
@Test
|
|
85
|
+
fun testnetAddressesAreDistinctPerChain() {
|
|
86
|
+
val wallet = HDWallet(MNEMONIC, "")
|
|
87
|
+
val btc = ChainSigner.addressForChain(wallet, ChainKey.BITCOIN, isTestnet = true)
|
|
88
|
+
val ltc = ChainSigner.addressForChain(wallet, ChainKey.LITECOIN, isTestnet = true)
|
|
89
|
+
val bch = ChainSigner.addressForChain(wallet, ChainKey.BITCOINCASH, isTestnet = true)
|
|
90
|
+
println("[AddressDerivationConformanceTest] testnet: BTC=$btc LTC=$ltc BCH=$bch")
|
|
91
|
+
assertNotEquals("BTC/LTC testnet addresses must not collide", btc, ltc)
|
|
92
|
+
assertNotEquals("BTC/BCH testnet addresses must not collide", btc, bch)
|
|
93
|
+
assertNotEquals("LTC/BCH testnet addresses must not collide", ltc, bch)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@Test
|
|
97
|
+
fun printPendingAddressesForVerification() {
|
|
98
|
+
val wallet = HDWallet(MNEMONIC, "")
|
|
99
|
+
val lines = PENDING.map { coin -> " ${coin.name} -> ${wallet.getAddressForCoin(coin)}" }
|
|
100
|
+
println(
|
|
101
|
+
"\n[AddressDerivationConformanceTest] Pending — verify and move to VERIFIED map:\n" +
|
|
102
|
+
lines.joinToString("\n")
|
|
103
|
+
)
|
|
104
|
+
// This test intentionally never fails — it exists only to harvest pending addresses.
|
|
105
|
+
}
|
|
106
|
+
}
|