CCL Bridge compiles Cardano Client Lib (CCL) into a native shared library (libccl.so / libccl.dylib / libccl.dll) using GraalVM native-image. This lets any language call CCL's offline Cardano operations via FFI — no JVM required at runtime.
Cardano Client Lib is a mature, feature-rich Cardano SDK covering key derivation, transaction building, Plutus data handling, governance, and more. CCL Bridge makes selected CCL modules available as a native shared library with a C ABI, so languages like Python, Go, Rust, and JavaScript can use it directly — whether as the foundation for a wrapper library, a transaction builder, or for individual functions like crypto, address parsing, and CBOR serialization.
The bridge exposes CCL's offline/local operations:
- Account — Create accounts, derive keys, export public/private keys, sign transactions
- Address — Parse, validate, convert between bech32 and bytes
- Crypto — Blake2b hashing, mnemonic generation/validation, Ed25519 sign/verify
- Transaction — Serialize, deserialize, hash, sign transactions
- Plutus — PlutusData CBOR/JSON conversion, datum hashing
- Script — Native script parsing, script hashing
- Governance — DRep, committee cold/hot key derivation
- HD Wallet — Create wallets, derive addresses
- QuickTx — JSON-driven offline transaction builder supporting payments, staking, governance, Plutus scripts, and multi-party compose (documentation)
Backend/HTTP modules (Blockfrost, Koios, Ogmios) are intentionally excluded — every language has good HTTP libraries, and CCL's real value is the hard parts listed above.
ccl-bridge/
├── core/ # Java bridge + GraalVM native-image → libccl
│ ├── src/main/java/ # @CEntryPoint API classes
│ └── src/test/java/ # JVM unit tests (72+ tests)
├── native-test/ # C smoke tests
├── wrappers/
│ ├── python/ # Python bindings (ctypes)
│ ├── go/ # Go bindings (cgo)
│ ├── rust/ # Rust bindings (FFI)
│ └── js/ # JavaScript bindings (Bun FFI)
├── docs/ # Documentation
│ └── quicktx.md # QuickTx transaction builder reference
├── build.gradle
└── settings.gradle
For wrapper developers (no GraalVM needed — uses pre-built binaries):
- Install whichever language runtime you need (Python, Go, Rust, Bun, C compiler)
- The pre-built native library is downloaded automatically via
makeor-PusePrebuilt
For core developers (building from source):
- GraalVM 25+ (includes
native-image)sdk install java 25.0.2-graal # via SDKMAN
Language runtimes (install whichever you need):
- Python 3.8+
pip install pytest
- Go 1.21+ — install from go.dev
- Rust 1.70+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- Bun 1.0+ (for JavaScript — Node.js is not supported due to GraalVM FFI incompatibility)
curl -fsSL https://bun.sh/install | bash - C compiler
# macOS xcode-select --install # Linux (Debian/Ubuntu) sudo apt install build-essential
Use make to download the pre-built library and run tests:
make test-python # Download lib + run Python tests
make test-go # Download lib + run Go tests
make test-rust # Download lib + run Rust tests
make test-js # Download lib + run JS tests (Bun)
make test-c # Download lib + run C smoke testsOr use Gradle with the -PusePrebuilt flag:
./gradlew :wrappers:go:test -PusePrebuilt
./gradlew :wrappers:python:test -PusePrebuilt# Build the native library
./gradlew :core:nativeCompile
# Run wrapper tests (builds from source automatically)
./gradlew :wrappers:go:test
./gradlew :wrappers:python:test
# Or build + run all tests
make test-allThe native library is produced at core/build/native/nativeCompile/libccl.dylib (macOS) or libccl.so (Linux), along with libccl.h and graal_isolate.h headers.
./gradlew :core:testDownload the native library for your platform from GitHub Releases:
macOS (Apple Silicon):
curl -L https://github.com/bloxbean/ccl-bridge/releases/latest/download/ccl-bridge-v0.1.0-macos-aarch64.tar.gz | tar xz -C /usr/local/lib/Linux (x86_64):
curl -L https://github.com/bloxbean/ccl-bridge/releases/latest/download/ccl-bridge-v0.1.0-linux-x86_64.tar.gz | tar xz -C /usr/local/lib/Then set the library path:
export CCL_LIB_PATH=/usr/local/lib
# Linux
export LD_LIBRARY_PATH=/usr/local/lib
# macOS
export DYLD_LIBRARY_PATH=/usr/local/libYou can also run wrapper tests directly. Set CCL_LIB_PATH to point to the native library directory.
cd native-test
make CCL_LIB_PATH=../core/build/native/nativeCompile
make testPYTHONPATH=wrappers/python \
CCL_LIB_PATH=core/build/native/nativeCompile \
pytest wrappers/python/tests/ -vcd wrappers/go/ccl
CGO_CFLAGS="-I../../../core/build/native/nativeCompile" \
CGO_LDFLAGS="-L../../../core/build/native/nativeCompile -lccl" \
DYLD_LIBRARY_PATH=../../../core/build/native/nativeCompile \
go test -v ./...CCL_LIB_PATH=core/build/native/nativeCompile \
DYLD_LIBRARY_PATH=core/build/native/nativeCompile \
cargo test --manifest-path wrappers/rust/Cargo.toml -- --test-threads=1CCL_LIB_PATH=core/build/native/nativeCompile \
bun test wrappers/js/test/ccl.test.jsNote: Node.js FFI libraries (ffi-napi, koffi) crash with GraalVM native-image on macOS ARM64 due to stack boundary detection issues. Use Bun instead, which has built-in FFI that works correctly.
All functions follow the same pattern:
| Aspect | Convention |
|---|---|
| Inputs | Strings via char* (JSON for complex data, hex for binary) |
| Return value | int status code (0 = success, negative = error) |
| Get result | ccl_get_result(thread) → result string (JSON or hex) |
| Get error | ccl_get_last_error(thread) → error message |
| Memory | Free returned strings with ccl_free_string(thread, ptr) |
| Network ID | 0 = mainnet, 1 = testnet, 2 = preprod, 3 = preview |
#include "libccl.h"
graal_isolatethread_t *thread = NULL;
graal_isolate_t *isolate = NULL;
graal_create_isolate(NULL, &isolate, &thread);
int rc = ccl_account_create(thread, 0); // 0 = mainnet
if (rc == 0) {
char *json = ccl_get_result(thread);
printf("Account: %s\n", json);
ccl_free_string(thread, json);
} else {
char *err = ccl_get_last_error(thread);
printf("Error: %s\n", err);
ccl_free_string(thread, err);
}
graal_tear_down_isolate(thread);from ccl import CclLib
lib = CclLib() # loads libccl and creates isolate
account = lib.account.create(network_id=0)
print(account) # {'mnemonic': '...', 'base_address': 'addr1...', ...}
info = lib.address.info(account['base_address'])
hash = lib.crypto.blake2b_256("48656c6c6f")
tx_hash = lib.tx.hash(tx_cbor_hex)
datum_hash = lib.plutus.data_hash("182a")
drep = lib.gov.drep_key_from_mnemonic(account['mnemonic'])
wallet = lib.wallet.create()
lib.close()use ccl::Bridge;
let bridge = Bridge::new().unwrap();
let result = bridge.account().create(ccl::network::MAINNET).unwrap();
let account: serde_json::Value = serde_json::from_str(&result).unwrap();
println!("Address: {}", account["base_address"]);
let hash = bridge.crypto().blake2b_256("48656c6c6f").unwrap();
let tx_hash = bridge.tx().hash(tx_cbor).unwrap();
let datum_hash = bridge.plutus().data_hash("182a").unwrap();
// Bridge::drop() tears down the isolate automaticallyimport "github.com/bloxbean/ccl-bridge/wrappers/go/ccl"
bridge, _ := ccl.New()
defer bridge.Close()
account, _ := bridge.Account.Create(ccl.Mainnet)
fmt.Println("Address:", account.BaseAddress)
hash, _ := bridge.Crypto.Blake2b256("48656c6c6f")
txHash, _ := bridge.Tx.Hash(txCbor)
datumHash, _ := bridge.Plutus.DataHash("182a")
wallet, _ := bridge.Wallet.Create(ccl.Mainnet)import { CclBridge, MAINNET } from '@bloxbean/ccl';
const bridge = new CclBridge();
const account = bridge.account.create(MAINNET);
console.log('Address:', account.base_address);
const hash = bridge.crypto.blake2b256('48656c6c6f');
const txHash = bridge.tx.hash(txCbor);
const datumHash = bridge.plutus.dataHash('182a');
const wallet = bridge.wallet.create(MAINNET);
bridge.close();| Function | Description |
|---|---|
ccl_version |
Returns library version |
ccl_get_result |
Returns last successful result string |
ccl_get_last_error |
Returns last error message |
ccl_free_string |
Frees a string returned by the library |
| Function | Description |
|---|---|
ccl_account_create |
Create a new random account (returns JSON with mnemonic, addresses) |
ccl_account_from_mnemonic |
Restore account from mnemonic phrase |
ccl_account_get_public_key |
Get public key hex from mnemonic |
ccl_account_get_private_key |
Get private key hex from mnemonic |
ccl_account_sign_tx |
Sign a transaction CBOR hex with mnemonic |
ccl_account_get_drep_id |
Get DRep ID (bech32) from mnemonic |
| Function | Description |
|---|---|
ccl_address_info |
Parse address → JSON (type, network, credentials) |
ccl_address_validate |
Validate a bech32 address |
ccl_address_to_bytes |
Convert bech32 address to hex bytes |
ccl_address_from_bytes |
Convert hex bytes to bech32 address |
| Function | Description |
|---|---|
ccl_crypto_blake2b_256 |
Blake2b-256 hash (hex in → hex out) |
ccl_crypto_blake2b_224 |
Blake2b-224 hash (hex in → hex out) |
ccl_crypto_generate_mnemonic |
Generate mnemonic (12 or 24 words) |
ccl_crypto_validate_mnemonic |
Validate a mnemonic phrase |
ccl_crypto_sign |
Ed25519 sign (message hex + secret key hex → signature hex) |
ccl_crypto_verify |
Ed25519 verify (signature + message + public key) |
| Function | Description |
|---|---|
ccl_tx_hash |
Compute transaction hash from CBOR hex |
ccl_tx_sign_with_secret_key |
Sign transaction with a secret key |
ccl_tx_to_json |
Convert transaction CBOR hex to JSON |
ccl_tx_from_json |
Convert transaction JSON to CBOR hex |
ccl_tx_deserialize |
Deserialize transaction CBOR hex to JSON |
| Function | Description |
|---|---|
ccl_plutus_data_hash |
Compute datum hash from CBOR hex |
ccl_plutus_data_to_json |
Convert PlutusData CBOR to JSON |
ccl_plutus_data_from_json |
Convert PlutusData JSON to CBOR hex |
| Function | Description |
|---|---|
ccl_script_native_from_json |
Parse native script from JSON → CBOR hex |
ccl_script_hash |
Compute script hash from CBOR hex |
| Function | Description |
|---|---|
ccl_gov_drep_key_from_mnemonic |
Derive DRep key pair from mnemonic |
ccl_gov_committee_cold_key_from_mnemonic |
Derive committee cold key pair |
ccl_gov_committee_hot_key_from_mnemonic |
Derive committee hot key pair |
| Function | Description |
|---|---|
ccl_wallet_create |
Create new HD wallet (returns mnemonic + addresses) |
ccl_wallet_from_mnemonic |
Restore HD wallet from mnemonic |
ccl_wallet_get_address |
Derive address at given index |
| Function | Description |
|---|---|
ccl_quicktx_build |
Build an unsigned transaction from a JSON spec (documentation) |
- Cardano Client Lib: bloxbean/cardano-client-lib v0.7.1
- GraalVM: 25.0.2 (
native-image --shared)