Skip to content

Commit fee0c75

Browse files
Merge pull request #37 from GalaxySciTech/codex-jnlk9p
Add mnemonic string parsing, improve keystore/address handling, update README and tests
2 parents 2c11142 + e79d02d commit fee0c75

8 files changed

Lines changed: 1012 additions & 864 deletions

File tree

README.md

Lines changed: 141 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,184 @@
1-
<h1 align="center">Tokencore</h1>
2-
3-
<p align="center">
4-
<strong>Multi-chain cryptocurrency wallet core library for Java</strong>
5-
</p>
6-
7-
<p align="center">
8-
<a href="https://github.com/galaxyscitech/tokencore/actions">
9-
<img src="https://github.com/galaxyscitech/tokencore/actions/workflows/ci.yml/badge.svg" alt="Build Status">
10-
</a>
11-
<a href="https://jitpack.io/#galaxyscitech/tokencore">
12-
<img src="https://jitpack.io/v/galaxyscitech/tokencore.svg" alt="JitPack">
13-
</a>
14-
</p>
15-
16-
<p align="center">
17-
<a href="#quick-start-30-seconds">Quick Start (30s)</a> &nbsp;&bull;&nbsp;
18-
<a href="#integration">Integration</a> &nbsp;&bull;&nbsp;
19-
<a href="#core-features-recommended-minimum">Recommended Minimum</a> &nbsp;&bull;&nbsp;
20-
<a href="#supported-chains">Supported Chains</a>
21-
</p>
1+
# Tokencore
2+
3+
Tokencore is a Java multi-chain wallet core library for exchange backends, custody systems, and wallet services.
4+
5+
## What Tokencore provides
6+
7+
- Multi-chain address generation
8+
- HD wallet derivation and mnemonic workflows
9+
- Encrypted keystore management
10+
- Offline transaction signing for major chain families
11+
12+
Supported chains include:
13+
- **EVM**: Ethereum
14+
- **Bitcoin family**: Bitcoin, Litecoin, Dogecoin, Dash, Bitcoin Cash, Bitcoin SV
15+
- **Others**: TRON, Filecoin, EOS
2216

2317
---
2418

25-
## Introduction
19+
## Core Features (Recommended Minimum)
2620

27-
Tokencore is a lightweight Java library for wallet fundamentals: HD derivation, encrypted keystore management, and offline signing.
21+
- Java 8+
22+
- Gradle wrapper included (`./gradlew`)
2823

29-
If your goal is "install and use immediately", start with the 30-second quick start below and only enable additional chains/features later.
24+
---
3025

31-
## Quick Start (30 seconds)
26+
## Install
3227

33-
### 1) Add dependency
28+
### Gradle
3429

3530
```gradle
3631
repositories {
3732
maven { url 'https://jitpack.io' }
3833
}
34+
3935
dependencies {
4036
implementation 'com.github.galaxyscitech:tokencore:1.3.0'
4137
}
4238
```
4339

44-
### 2) Copy this minimal bootstrap code
40+
### Maven
4541

46-
```java
47-
WalletManager.storage = () -> new File("./keystore");
48-
WalletManager.scanWallets();
42+
```xml
43+
<repositories>
44+
<repository>
45+
<id>jitpack.io</id>
46+
<url>https://jitpack.io</url>
47+
</repository>
48+
</repositories>
4949

50-
String password = "change_me";
51-
Identity identity = Identity.getCurrentIdentity();
52-
if (identity == null) {
53-
identity = Identity.createIdentity("default", password, "", Network.MAINNET, Metadata.P2WPKH);
54-
}
50+
<dependency>
51+
<groupId>com.github.galaxyscitech</groupId>
52+
<artifactId>tokencore</artifactId>
53+
<version>1.3.0</version>
54+
</dependency>
55+
```
56+
57+
---
5558

56-
Wallet wallet = identity.deriveWalletByMnemonics(
57-
ChainType.ETHEREUM,
58-
password,
59-
MnemonicUtil.randomMnemonicCodes());
59+
## Quick start (runnable)
6060

61-
System.out.println("Address = " + wallet.getAddress());
61+
```java
62+
import org.consenlabs.tokencore.foundation.utils.MnemonicUtil;
63+
import org.consenlabs.tokencore.wallet.*;
64+
import org.consenlabs.tokencore.wallet.model.*;
65+
66+
import java.io.File;
67+
68+
public class QuickStart {
69+
public static void main(String[] args) {
70+
WalletManager.storage = () -> new File("./keystore");
71+
WalletManager.scanWallets();
72+
73+
String password = "UseAStrongPassword_123";
74+
Identity identity = Identity.getCurrentIdentity();
75+
if (identity == null) {
76+
identity = Identity.createIdentity("main", password, "", Network.MAINNET, Metadata.P2WPKH);
77+
}
78+
79+
Wallet ethWallet = identity.deriveWalletByMnemonics(
80+
ChainType.ETHEREUM,
81+
password,
82+
MnemonicUtil.randomMnemonicCodes()
83+
);
84+
85+
Wallet btcWallet = identity.deriveWalletByMnemonics(
86+
ChainType.BITCOIN,
87+
password,
88+
MnemonicUtil.randomMnemonicCodes()
89+
);
90+
91+
System.out.println("ETH address: " + ethWallet.getAddress());
92+
System.out.println("BTC address: " + btcWallet.getAddress());
93+
}
94+
}
6295
```
6396

64-
### 3) Verify locally
97+
---
6598

66-
```bash
67-
./gradlew test
68-
```
99+
## Common usage
69100

70-
## Core Features (Recommended Minimum)
101+
### 1) Import wallet from private key
71102

72-
For new integrators, keep the initial rollout small:
103+
```java
104+
Metadata metadata = new Metadata();
105+
metadata.setChainType(ChainType.ETHEREUM);
106+
metadata.setSource(Metadata.FROM_PRIVATE);
107+
metadata.setNetwork(Network.MAINNET);
108+
109+
Wallet wallet = WalletManager.importWalletFromPrivateKey(
110+
metadata,
111+
"4c0883a69102937d6231471b5dbb6204fe512961708279f14a15c89a7e5a5c3c",
112+
"password123",
113+
true
114+
);
115+
```
73116

74-
1. **Identity + keystore only** (account generation + secure storage)
75-
2. **Single chain first** (recommend: ETH or BTC)
76-
3. **Offline signing only** (avoid online key usage)
77-
4. **No multi-chain abstraction in v1 API surface**
117+
### 2) Import wallet from mnemonic
78118

79-
This reduces integration complexity and speeds up first successful deployment.
119+
```java
120+
Metadata metadata = new Metadata();
121+
metadata.setChainType(ChainType.DOGECOIN);
122+
metadata.setSource(Metadata.FROM_MNEMONIC);
123+
metadata.setNetwork(Network.MAINNET);
124+
metadata.setSegWit(Metadata.NONE);
125+
126+
Wallet wallet = WalletManager.importWalletFromMnemonic(
127+
metadata,
128+
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
129+
BIP44Util.DOGECOIN_MAINNET_PATH,
130+
"password123",
131+
true
132+
);
133+
```
80134

81-
## Integration
135+
### 3) Find wallet by mnemonic (BTC-family friendly)
82136

83-
### Gradle
137+
```java
138+
Wallet wallet = WalletManager.findWalletByMnemonic(
139+
ChainType.DOGECOIN,
140+
Network.MAINNET,
141+
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
142+
BIP44Util.DOGECOIN_MAINNET_PATH,
143+
Metadata.NONE
144+
);
145+
```
84146

85-
```gradle
86-
repositories {
87-
maven { url 'https://jitpack.io' }
88-
}
89-
dependencies {
90-
implementation 'com.github.galaxyscitech:tokencore:1.3.0'
91-
}
147+
### 4) Export keystore and recover by keystore
148+
149+
```java
150+
String keystoreJson = WalletManager.exportKeystore(wallet.getId(), "password123");
151+
Wallet found = WalletManager.findWalletByKeystore(ChainType.ETHEREUM, keystoreJson, "password123");
92152
```
93153

94-
### Maven
154+
---
95155

96-
```xml
97-
<repositories>
98-
<repository>
99-
<id>jitpack.io</id>
100-
<url>https://jitpack.io</url>
101-
</repository>
102-
</repositories>
156+
## Security recommendations
103157

104-
<dependency>
105-
<groupId>com.github.galaxyscitech</groupId>
106-
<artifactId>tokencore</artifactId>
107-
<version>1.3.0</version>
108-
</dependency>
109-
```
158+
- Never log or print private keys, mnemonics, or decrypted keystore payloads.
159+
- Keep signing in isolated/offline environments whenever possible.
160+
- Use strong passwords and avoid hardcoded secrets.
161+
- Consider HSM/KMS for production secret governance.
162+
- Enforce strict access controls around keystore files.
110163

111-
## Supported Chains
164+
---
165+
166+
## Typical errors
112167

113-
| Chain | Token Standards | Features |
114-
|-------|----------------|----------|
115-
| **Bitcoin** | BTC, OMNI | UTXO management, SegWit (P2WPKH) |
116-
| **Ethereum** | ETH, ERC-20 | Offline signing, nonce management |
117-
| **TRON** | TRX, TRC-20 | Transaction signing |
118-
| **Bitcoin Cash** | BCH | CashAddr format |
119-
| **Bitcoin SV** | BSV | Transaction signing |
120-
| **Litecoin** | LTC | Transaction signing |
121-
| **Dogecoin** | DOGE | Transaction signing |
122-
| **Dash** | DASH | Transaction signing |
123-
| **Filecoin** | FIL | Transaction signing |
168+
- `password_incorrect`
169+
- `mnemonic_length_invalid`
170+
- `mnemonic_word_invalid`
171+
- `invalid_mnemonic_path`
172+
- `unsupported_chain`
173+
- `private_key_address_not_match`
174+
175+
---
124176

125-
## Build & Test
177+
## Build and test
126178

127179
```bash
128-
./gradlew build
129180
./gradlew test
181+
./gradlew build
130182
```
131183

132-
## License
133-
134-
This project is licensed under the [GNU General Public License v3.0](LICENSE).
184+
CI runs on Java 8/11/17 via GitHub Actions.
Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,59 @@
1-
package org.consenlabs.tokencore.foundation.utils;
2-
3-
import com.google.common.base.Joiner;
4-
import org.bitcoinj.crypto.MnemonicCode;
5-
import org.consenlabs.tokencore.wallet.model.Messages;
6-
import org.consenlabs.tokencore.wallet.model.TokenException;
7-
8-
import java.util.List;
9-
10-
public class MnemonicUtil {
11-
public static void validateMnemonics(List<String> mnemonicCodes) {
12-
try {
13-
MnemonicCode.INSTANCE.check(mnemonicCodes);
14-
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
15-
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
16-
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicWordException e) {
17-
throw new TokenException(Messages.MNEMONIC_BAD_WORD);
18-
} catch (Exception e) {
19-
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
20-
}
21-
}
22-
23-
public static List<String> randomMnemonicCodes() {
24-
return toMnemonicCodes(NumericUtil.generateRandomBytes(16));
25-
}
26-
27-
public static String randomMnemonicStr() {
28-
List<String> mnemonicCodes=randomMnemonicCodes();
29-
return Joiner.on(" ").join(mnemonicCodes);
30-
}
31-
32-
33-
public static List<String> toMnemonicCodes(byte[] entropy) {
34-
try {
35-
return MnemonicCode.INSTANCE.toMnemonic(entropy);
36-
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
37-
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
38-
} catch (Exception e) {
39-
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
40-
}
41-
}
42-
43-
}
1+
package org.consenlabs.tokencore.foundation.utils;
2+
3+
import com.google.common.base.Joiner;
4+
import org.bitcoinj.crypto.MnemonicCode;
5+
import org.consenlabs.tokencore.wallet.model.Messages;
6+
import org.consenlabs.tokencore.wallet.model.TokenException;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
11+
public class MnemonicUtil {
12+
public static void validateMnemonics(List<String> mnemonicCodes) {
13+
try {
14+
MnemonicCode.INSTANCE.check(mnemonicCodes);
15+
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
16+
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
17+
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicWordException e) {
18+
throw new TokenException(Messages.MNEMONIC_BAD_WORD);
19+
} catch (Exception e) {
20+
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
21+
}
22+
}
23+
24+
public static List<String> randomMnemonicCodes() {
25+
return toMnemonicCodes(NumericUtil.generateRandomBytes(16));
26+
}
27+
28+
public static String randomMnemonicStr() {
29+
List<String> mnemonicCodes=randomMnemonicCodes();
30+
return Joiner.on(" ").join(mnemonicCodes);
31+
}
32+
33+
34+
35+
36+
public static List<String> toMnemonicCodes(String mnemonic) {
37+
if (mnemonic == null) {
38+
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
39+
}
40+
41+
String normalized = mnemonic.trim().replaceAll("\\s+", " ");
42+
if (normalized.isEmpty()) {
43+
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
44+
}
45+
46+
return Arrays.asList(normalized.split(" "));
47+
}
48+
49+
public static List<String> toMnemonicCodes(byte[] entropy) {
50+
try {
51+
return MnemonicCode.INSTANCE.toMnemonic(entropy);
52+
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
53+
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
54+
} catch (Exception e) {
55+
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
56+
}
57+
}
58+
59+
}

0 commit comments

Comments
 (0)