This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Crosschain is a Go library for interacting with multiple blockchains. The main design principle is to isolate functionality into separate Client, Signer, and TxBuilder interfaces, providing unified interfaces for all supported chains while allowing blockchains to be safely used in secure contexts.
# Build all packages
make all
# or with CGO disabled (default in Makefile)
CGO_ENABLED=0 go build -v ./...
# Run tests (excludes CI integration tests)
make test
# or directly
go test -mod=readonly -tags not_ci ./...
# Lint code
make lint
# Format code
make fmt
# Install the xc CLI utility
make install
# or directly
CGO_ENABLED=0 go install -v ./cmd/...# Run tests for a specific chain
go test ./chain/bitcoin/...
go test ./chain/evm/...
go test ./chain/solana/...
# Run a single test
go test -run TestName ./path/to/packageThe xc utility demonstrates library usage and is useful for manual testing:
# Install
go install -v ./cmd/xc/...
# Set up environment (required for most commands)
# For mainnet:
source .envrc-testnet
# Or, for testnet:
source .envrc-mainnet
# Common commands
xc address --chain SOL
xc balance <address> --chain ETH
xc transfer <destination> <amount> -v --chain SOL
xc tx-info --chain BTC <tx-hash>
xc tx-input <from-address> --chain ETH
xc staking stake --amount 0.1 --chain SOL --validator <validator-address>
# Use custom RPC
xc balance <address> --chain ETH --rpc https://your-rpc-urlThe library separates concerns into three main interfaces:
-
Client (
client/client.go) - Fetches data from blockchain and submits transactionsFetchTransferInput()- Get transaction inputs (gas, nonces, UTXOs)FetchBalance()- Query balancesFetchTxInfo()- Get transaction detailsSubmitTx()- Broadcast signed transactionsFetchBlock()- Retrieve block data- Extensions:
StakingClient,MultiTransferClient
-
TxBuilder (
builder/builder.go) - Constructs unsigned transactionsTransfer()- Build transfer transactionsMultiTransfer()- Build multi-destination transfersStake(),Unstake(),Withdraw()- Build staking transactions
-
Signer (
factory/signer/signer.go) - Signs transaction payloads- Supports multiple signature algorithms: Ed25519, K256 (Keccak/SHA256), Schnorr, BLS12-381
- Environment variable
XC_SIGN_WITH_SCALAR=1enables scalar signing for Ed25519 (for MPC compatibility)
Each chain implementation follows a consistent pattern in chain/<chain-name>/:
client/client.go- Chain-specific client implementationbuilder/builder.go- Transaction builder for the chainaddress/- Address derivation and validationtx/ortx_input/- Transaction and input structuressigner.go(some chains) - Chain-specific signing logic
The factory/ package provides a factory pattern for constructing chain-specific components:
factory/main.go- Main factory implementationfactory/drivers/- Driver registry for all chainsfactory/defaults/chains/- Default chain configurations (mainnet.yaml, testnet.yaml)factory/new.go- Factory initialization
Use the factory to create clients, builders, and signers:
xcFactory := factory.NewDefaultFactory()
client, err := xcFactory.NewClient(chainConfig)
txBuilder, err := xcFactory.NewTxBuilder(chainConfig)
signer, err := xcFactory.NewSigner(chainConfig, privateKey)See chain/ directory for all implementations. Major chains include:
- Bitcoin family: bitcoin, bitcoin_cash, dogecoin (UTXO-based)
- EVM chains: evm, evm_legacy (Ethereum and compatible chains)
- Cosmos ecosystem: cosmos (+ derivatives like Terra, Injective, XPLA)
- Modern chains: solana, sui, aptos, ton, tron
- Substrate-based: substrate (Polkadot, Kusama, Astar, etc.)
- Specialized: hyperliquid, kaspa, xlm (Stellar), xrp
Each chain configuration is defined in factory/defaults/chains/mainnet.yaml and testnet.yaml.
Core types are defined in the root package (github.com/cordialsys/crosschain):
xc.Tx- Universal transaction interfacexc.TxInput- Chain-specific inputs needed for transaction constructionxc.TxInfo- Normalized transaction information across chainsxc.AmountBlockchain- Blockchain-native amounts (big integers)xc.AmountHumanReadable- Human-readable decimal amountsxc.Address,xc.TxHash,xc.ContractAddress- Type-safe string wrappers
- Chain configurations use YAML in
factory/defaults/chains/ - Each chain has a unique
Driverenum value (e.g.,DriverBitcoin,DriverEVM) - Chain-specific settings: RPC URLs, chain IDs, decimals, gas multipliers, staking configs
- The
networkfield determines mainnet vs testnet behavior
- Use
address.AddressOptionfor chain-specific address format selection (e.g., Bitcoin legacy vs segwit vs taproot) - Address builders normalize and validate addresses per chain rules
- Many chains use HD path derivation - see
chain_coin_hd_pathin chain configs
Always convert between human-readable and blockchain amounts using the factory:
blockchain, err := factory.ConvertAmountStrToBlockchain(cfg, "1.5")
human, err := factory.ConvertAmountToHuman(cfg, blockchainAmount)Standard transaction flow:
- Get inputs:
client.FetchTransferInput(ctx, args) - Build tx:
builder.Transfer(args, input) - Sign tx:
tx.Sign(signatures)orsigner.Sign(req) - Submit:
client.SubmitTx(ctx, tx)
Staking support varies by chain. Check chain/<name>/client.go for StakingClient implementation.
- Substrate chains use
SubtensorModule.add_stake/remove_stake - Cosmos chains use native staking modules
- Ethereum uses third-party staking providers (Kiln, Twinstake)
- Integration tests are tagged with
not_ciand excluded frommake test - CI tests in
ci/directory test against real networks (use sparingly) - Use
testutil/helpers for test setup - Most chains have devnet Docker images for local testing
Branch: substrate-staking
Modified: chain/substrate/tx_input/calls.go (working on staking calls)
Chain configs: factory/defaults/chains/testnet.yaml
- Use
-vflag withxcCLI for verbose logging - Set
logrus.SetLevel(logrus.DebugLevel)for detailed logs - Check
client/errors/for chain-specific error handling - RPC errors are normalized through
factory.CheckError()