Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 141 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,134 +1,184 @@
<h1 align="center">Tokencore</h1>

<p align="center">
<strong>Multi-chain cryptocurrency wallet core library for Java</strong>
</p>

<p align="center">
<a href="https://github.com/galaxyscitech/tokencore/actions">
<img src="https://github.com/galaxyscitech/tokencore/actions/workflows/ci.yml/badge.svg" alt="Build Status">
</a>
<a href="https://jitpack.io/#galaxyscitech/tokencore">
<img src="https://jitpack.io/v/galaxyscitech/tokencore.svg" alt="JitPack">
</a>
</p>

<p align="center">
<a href="#quick-start-30-seconds">Quick Start (30s)</a> &nbsp;&bull;&nbsp;
<a href="#integration">Integration</a> &nbsp;&bull;&nbsp;
<a href="#core-features-recommended-minimum">Recommended Minimum</a> &nbsp;&bull;&nbsp;
<a href="#supported-chains">Supported Chains</a>
</p>
# Tokencore

Tokencore is a Java multi-chain wallet core library for exchange backends, custody systems, and wallet services.

## What Tokencore provides

- Multi-chain address generation
- HD wallet derivation and mnemonic workflows
- Encrypted keystore management
- Offline transaction signing for major chain families

Supported chains include:
- **EVM**: Ethereum
- **Bitcoin family**: Bitcoin, Litecoin, Dogecoin, Dash, Bitcoin Cash, Bitcoin SV
- **Others**: TRON, Filecoin, EOS

---

## Introduction
## Core Features (Recommended Minimum)

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

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

## Quick Start (30 seconds)
## Install

### 1) Add dependency
### Gradle

```gradle
repositories {
maven { url 'https://jitpack.io' }
}

dependencies {
implementation 'com.github.galaxyscitech:tokencore:1.3.0'
}
```

### 2) Copy this minimal bootstrap code
### Maven

```java
WalletManager.storage = () -> new File("./keystore");
WalletManager.scanWallets();
```xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

String password = "change_me";
Identity identity = Identity.getCurrentIdentity();
if (identity == null) {
identity = Identity.createIdentity("default", password, "", Network.MAINNET, Metadata.P2WPKH);
}
<dependency>
<groupId>com.github.galaxyscitech</groupId>
<artifactId>tokencore</artifactId>
<version>1.3.0</version>
</dependency>
```

---

Wallet wallet = identity.deriveWalletByMnemonics(
ChainType.ETHEREUM,
password,
MnemonicUtil.randomMnemonicCodes());
## Quick start (runnable)

System.out.println("Address = " + wallet.getAddress());
```java
import org.consenlabs.tokencore.foundation.utils.MnemonicUtil;
import org.consenlabs.tokencore.wallet.*;
import org.consenlabs.tokencore.wallet.model.*;

import java.io.File;

public class QuickStart {
public static void main(String[] args) {
WalletManager.storage = () -> new File("./keystore");
WalletManager.scanWallets();

String password = "UseAStrongPassword_123";
Identity identity = Identity.getCurrentIdentity();
if (identity == null) {
identity = Identity.createIdentity("main", password, "", Network.MAINNET, Metadata.P2WPKH);
}

Wallet ethWallet = identity.deriveWalletByMnemonics(
ChainType.ETHEREUM,
password,
MnemonicUtil.randomMnemonicCodes()
);

Wallet btcWallet = identity.deriveWalletByMnemonics(
ChainType.BITCOIN,
password,
MnemonicUtil.randomMnemonicCodes()
);

System.out.println("ETH address: " + ethWallet.getAddress());
System.out.println("BTC address: " + btcWallet.getAddress());
}
}
```

### 3) Verify locally
---

```bash
./gradlew test
```
## Common usage

## Core Features (Recommended Minimum)
### 1) Import wallet from private key

For new integrators, keep the initial rollout small:
```java
Metadata metadata = new Metadata();
metadata.setChainType(ChainType.ETHEREUM);
metadata.setSource(Metadata.FROM_PRIVATE);
metadata.setNetwork(Network.MAINNET);

Wallet wallet = WalletManager.importWalletFromPrivateKey(
metadata,
"4c0883a69102937d6231471b5dbb6204fe512961708279f14a15c89a7e5a5c3c",
"password123",
true
);
```

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

This reduces integration complexity and speeds up first successful deployment.
```java
Metadata metadata = new Metadata();
metadata.setChainType(ChainType.DOGECOIN);
metadata.setSource(Metadata.FROM_MNEMONIC);
metadata.setNetwork(Network.MAINNET);
metadata.setSegWit(Metadata.NONE);

Wallet wallet = WalletManager.importWalletFromMnemonic(
metadata,
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
BIP44Util.DOGECOIN_MAINNET_PATH,
"password123",
true
);
```

## Integration
### 3) Find wallet by mnemonic (BTC-family friendly)

### Gradle
```java
Wallet wallet = WalletManager.findWalletByMnemonic(
ChainType.DOGECOIN,
Network.MAINNET,
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
BIP44Util.DOGECOIN_MAINNET_PATH,
Metadata.NONE
);
```

```gradle
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.galaxyscitech:tokencore:1.3.0'
}
### 4) Export keystore and recover by keystore

```java
String keystoreJson = WalletManager.exportKeystore(wallet.getId(), "password123");
Wallet found = WalletManager.findWalletByKeystore(ChainType.ETHEREUM, keystoreJson, "password123");
```

### Maven
---

```xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
## Security recommendations

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

## Supported Chains
---

## Typical errors

| Chain | Token Standards | Features |
|-------|----------------|----------|
| **Bitcoin** | BTC, OMNI | UTXO management, SegWit (P2WPKH) |
| **Ethereum** | ETH, ERC-20 | Offline signing, nonce management |
| **TRON** | TRX, TRC-20 | Transaction signing |
| **Bitcoin Cash** | BCH | CashAddr format |
| **Bitcoin SV** | BSV | Transaction signing |
| **Litecoin** | LTC | Transaction signing |
| **Dogecoin** | DOGE | Transaction signing |
| **Dash** | DASH | Transaction signing |
| **Filecoin** | FIL | Transaction signing |
- `password_incorrect`
- `mnemonic_length_invalid`
- `mnemonic_word_invalid`
- `invalid_mnemonic_path`
- `unsupported_chain`
- `private_key_address_not_match`

---

## Build & Test
## Build and test

```bash
./gradlew build
./gradlew test
./gradlew build
```

## License

This project is licensed under the [GNU General Public License v3.0](LICENSE).
CI runs on Java 8/11/17 via GitHub Actions.
Original file line number Diff line number Diff line change
@@ -1,43 +1,59 @@
package org.consenlabs.tokencore.foundation.utils;

import com.google.common.base.Joiner;
import org.bitcoinj.crypto.MnemonicCode;
import org.consenlabs.tokencore.wallet.model.Messages;
import org.consenlabs.tokencore.wallet.model.TokenException;

import java.util.List;

public class MnemonicUtil {
public static void validateMnemonics(List<String> mnemonicCodes) {
try {
MnemonicCode.INSTANCE.check(mnemonicCodes);
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicWordException e) {
throw new TokenException(Messages.MNEMONIC_BAD_WORD);
} catch (Exception e) {
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
}
}

public static List<String> randomMnemonicCodes() {
return toMnemonicCodes(NumericUtil.generateRandomBytes(16));
}

public static String randomMnemonicStr() {
List<String> mnemonicCodes=randomMnemonicCodes();
return Joiner.on(" ").join(mnemonicCodes);
}


public static List<String> toMnemonicCodes(byte[] entropy) {
try {
return MnemonicCode.INSTANCE.toMnemonic(entropy);
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
} catch (Exception e) {
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
}
}

}
package org.consenlabs.tokencore.foundation.utils;

import com.google.common.base.Joiner;
import org.bitcoinj.crypto.MnemonicCode;
import org.consenlabs.tokencore.wallet.model.Messages;
import org.consenlabs.tokencore.wallet.model.TokenException;

import java.util.Arrays;
import java.util.List;

public class MnemonicUtil {
public static void validateMnemonics(List<String> mnemonicCodes) {
try {
MnemonicCode.INSTANCE.check(mnemonicCodes);
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicWordException e) {
throw new TokenException(Messages.MNEMONIC_BAD_WORD);
} catch (Exception e) {
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
}
}

public static List<String> randomMnemonicCodes() {
return toMnemonicCodes(NumericUtil.generateRandomBytes(16));
}

public static String randomMnemonicStr() {
List<String> mnemonicCodes=randomMnemonicCodes();
return Joiner.on(" ").join(mnemonicCodes);
}




public static List<String> toMnemonicCodes(String mnemonic) {
if (mnemonic == null) {
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
}

String normalized = mnemonic.trim().replaceAll("\\s+", " ");
if (normalized.isEmpty()) {
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
}

return Arrays.asList(normalized.split(" "));
}

public static List<String> toMnemonicCodes(byte[] entropy) {
try {
return MnemonicCode.INSTANCE.toMnemonic(entropy);
} catch (org.bitcoinj.crypto.MnemonicException.MnemonicLengthException e) {
throw new TokenException(Messages.MNEMONIC_INVALID_LENGTH);
} catch (Exception e) {
throw new TokenException(Messages.MNEMONIC_CHECKSUM);
}
}

}
Loading
Loading