Adding a New Chain to the Vultisig App Ecosystem
The how to steps to add a missing chains to the App store ecosystem
This document provides a high-level overview of the steps required to add support for a new blockchain across the Vultisig App Store ecosystem. The process involves multiple repositories and follows a dependency chain where each layer builds upon the previous.
Overview
Adding a new chain requires changes across five main repositories:
vultisig-go - Core address generation and chain definitions
recipes - Transaction parsing, validation rules, and policy engine
verifier - Transaction indexing and status monitoring
app-recurring - Automation services (send/swap execution)
plugin-marketplace - Frontend UI support
Step by step Guide
Note that if you run into any issues please contact us in the Vultisig discord.
1. Vultisig-go (Foundation Layer)
Purpose: Provides the foundational chain definitions and address derivation logic.
What Needs to Be Added
Chain Enumeration (common/chain.go)
Add the new chain to the
Chainenum constantAdd the chain to
chainToStringmapping for serializationAdd the derivation path to
chainDerivePathmapping (HD wallet path)Add the native symbol to
NativeSymbol()methodIf EVM-compatible, add the chain ID to
EvmID()methodIf EdDSA-based (like Solana, Sui), update
IsEdDSA()method
Address Generation (address/)
Create a new file (e.g.,
newchain.go) implementing address derivationImplement the address encoding specific to the chain (e.g., bech32, base58check, hex)
Add the chain case to
GetAddress()inaddress.goto route to the new implementationCreate corresponding test file with address derivation test vectors
Trust Wallet Core Dependency
Important: Address generation may or may not require Trust Wallet Core support depending on the chain type:
ECDSA chains (Bitcoin-like, EVM): Use
tss.GetDerivedPubKey()frommobile-tss-libfor key derivation, then custom address encodingEdDSA chains (Solana, Sui, etc.): Typically use the root public key directly without derivation
Cosmos chains: Use bech32 encoding with chain-specific HRP (human-readable prefix)
Custom curves: May require Trust Wallet Core or custom implementation
The mobile-tss-lib package handles the TSS key derivation, while address encoding is typically implemented directly in vultisig-go.
2. Recipes (Policy & Validation Layer)
Purpose: Defines how transactions are parsed, validated, and what policy rules can be applied.
What Needs to Be Added
Chain Implementation (chain/{chaintype}/)
Create a new directory structure (or add to existing category like utxo/, evm/):
chain.go- Implements thetypes.Chaininterface:ID()- Unique chain identifier (lowercase, e.g., "zcash")Name()- Human-readable nameDescription()- Brief descriptionSupportedProtocols()- List of protocol IDs (e.g., ["zec"])ParseTransaction()- Decode raw transaction bytes into structured formatGetProtocol()- Return protocol handler by IDComputeTxHash()- Compute transaction hash with signatures applied
decode.go- Transaction deserialization logic:Parse raw transaction bytes into chain-specific transaction structure
Handle version detection, input/output parsing, signatures
protocol.go- Implements thetypes.Protocolinterface:Define supported functions (transfer, swap, etc.)
Implement
MatchFunctionCall()for policy constraint validationExtract and validate transaction parameters against policy rules
Registry Registration (chain/registry.go)
Import the new chain package
Add
RegisterChain(newchain.NewChain())ininit()
Engine Implementation (engine/{chaintype}/)
Create the rule evaluation engine:
Engine struct - Wraps chain-specific validation logic:
Supports()- Return true for the supported chain(s)Evaluate()- Validate a transaction against policy rulesParse transaction, extract parameters, check constraints
Constraint validation - Validate output addresses, amounts, data fields
Engine Registry (engine/registry.go)
Import the new engine package
Add engine registration in
NewChainEngineRegistry()
Why Each Component Is Needed
Chain
Identifies the blockchain and routes to correct handlers
Protocol
Defines what operations are possible (transfer, swap)
Engine
Validates transactions match allowed policy rules
Decoder
Parses raw bytes into structured transaction data
3. Verifier (Transaction Monitoring Layer)
Purpose: Tracks transaction status on-chain and computes final transaction hashes.
What Needs to Be Added
TX Indexer Chain Implementation (plugin/tx_indexer/pkg/chain/)
newchain.go- Implementschain.Indexerinterface:ComputeTxHash()- Compute transaction hash from proposed transaction and signaturesTypically wraps the recipes chain implementation
RPC Client (plugin/tx_indexer/pkg/rpc/)
newchain.go- Blockchain RPC client:GetTxStatus()- Query transaction confirmation statusReturn
TxOnChainPending,TxOnChainSuccess, orTxOnChainFailedUse appropriate API (native RPC, block explorer API like Blockchair, etc.)
Chains List (plugin/tx_indexer/chains_list.go)
Register the new chain in the supported chains list
Wire up the indexer and RPC client
What the Verifier Checks
The verifier performs several critical functions:
Policy Validation - Ensures transaction matches the approved policy rules
Transaction Tracking - Monitors transaction from proposal to confirmation
Hash Computation - Computes final transaction hash after signatures are applied
Status Monitoring - Polls blockchain for confirmation status
4. App-recurring (Automation Layer)
Purpose: Executes automated transactions (sends, swaps) based on scheduled policies.
What Needs to Be Added
Network Package (internal/{chain}/)
Create a new directory with:
types.go- Define chain-specific types:Fromstruct (address, amount, public key)Tostruct (chain, asset ID, address)TxInput,TxOutputstructuresAny chain-specific interfaces (e.g.,
TxBroadcaster)
network.go- Network service orchestration:Initialize all chain services
Provide
Send()andSwap()entry pointsCoordinate between services
send_service.go- Build send transactions:BuildTransfer()- Create transaction outputs for a simple transferHandle change output calculation
swap_service.go- Build swap transactions:FindBestAmountOut()- Query swap providers for best rateAggregate results from multiple providers
swap_provider.go- DEX/swap provider integration:MakeOutputs()- Build transaction outputs for swapIntegrate with Thorchain, MayaChain, or other DEXs
signer_service.go- Transaction signing and broadcast:SignAndBroadcast()- Coordinate TSS signingBuild keysign request with message hashes
Apply signatures and broadcast to network
client.go- Blockchain RPC client:GetUTXOs()- Fetch unspent outputs (for UTXO chains)GetBalance()- Query account balanceBroadcastTransaction()- Submit signed transactionGetFeeRate()- Query current network fees
fee_provider.go- Fee estimation:Query network for current fee rates
Calculate transaction fees
address.go(if needed) - Address utilities:Address validation
Script generation (P2PKH, P2SH, etc.)
Consumer Integration (internal/recurring/consumer.go)
Add Network to Consumer struct:
Add field for the new chain's Network service
Add to
NewConsumer()constructor
Add pubkey-to-address helper:
newchainPubToAddress()- Derive chain address from vault public key
Add operation handlers:
handleNewchainSend()- Execute send operationshandleNewchainSwap()- Execute swap operations
Update handle() routing:
Add chain detection in the main handler
Route to appropriate send/swap handler
Worker Initialization (cmd/worker/main.go)
Initialize the new chain's Network service
Add to DCA Consumer constructor
Configure RPC endpoints and dependencies
Supported Chains (internal/recurring/spec.go)
Add the chain to
supportedChainssliceThis enables dynamic policy generation for the new chain
What the App Does
The app-recurring service:
Schedules - Triggers transactions based on policy schedule (hourly, daily, etc.)
Builds Transactions - Constructs appropriate transaction for send or swap
Signs - Coordinates TSS signing across vault participants
Broadcasts - Submits signed transaction to the blockchain
Tracks - Monitors transaction until confirmation
5. Plugin-marketplace (Frontend Layer)
Purpose: Provides the user interface for creating and managing policies.
What Needs to Be Added
Chain Configuration (src/utils/chain.ts)
Add to chain category:
For EVM: Add to
evmChainsandevmChainInfowith viem chain configFor UTXO: Add to
utxoChainsFor other: Add to
otherChains
Add ticker: Add native token ticker to
tickersmappingAdd RPC URL (if EVM): Add to
evmRpcUrlsmapping
Storage (src/storage/chain.ts)
Usually no changes needed - uses the chain types from utils
UI Components
Depending on chain characteristics, may need:
Token images in
public/tokens/Chain-specific validation logic
Custom UI for chain-specific features
Summary Checklist
vultisig-go
recipes
verifier
app-recurring
plugin-marketplace
Chain Type Patterns
UTXO Chains (Bitcoin, Zcash, Litecoin, etc.)
Require UTXO management (fetching, selection, change calculation)
Transaction format: inputs referencing previous outputs, new outputs
Typically use base58check or bech32 addresses
May have chain-specific features (Zcash's shielded transactions, BCH's CashAddr)
EVM Chains (Ethereum, Arbitrum, Base, etc.)
Simpler: single account model, no UTXO
Use standard Ethereum address format (0x prefixed hex)
Can share most infrastructure with existing EVM implementation
Just need chain ID and RPC configuration
Account-Based Non-EVM (Solana, XRP, etc.)
Account model but different transaction format
May require chain-specific SDKs
Often have unique address formats
Testing Recommendations
Unit Tests: Address derivation from known test vectors
Integration Tests: Transaction building and parsing round-trips
End-to-End Tests: Full send/swap flow on testnet
Policy Tests: Constraint validation with various policy rules
Last updated
Was this helpful?
