Contribution best practices
This document outlines guidelines and best practices for contributions to VisualSign. The project is in active development, and some specifics may change in the future.What is VisualSign parser?
VisualSign Parser is a platform for decoding various blockchains in Rust. It is deployed as a single binary and works with potentially conflicting dependencies from different blockchain ecosystems. The project is split into packages with thevisualsign package serving as a common “core” that chain_parsers use.
Core principles
Minimize dependencies aggressively
Every dependency introduces supply chain risk and increases build times. While this can be mitigated by splitting deployments into different binaries, the fundamental problem remains. Strategies:- Remove dependencies when possible
- Replicate simpler functionalities rather than importing heavy libraries
- For development and test builds, you can be more liberal with
[dev-dependencies]
Test thoroughly
Ensure all changes and refactors are tested thoroughly. Use tools likecargo-tarpaulin for test coverage data:
Respect blockchain conventions
Our experience with dozens of blockchains has shown there’s no one-size-fits-all approach to encoding. Instead of forcing a particular default everywhere:- Make pragmatic defaults that don’t conflict
- Let blockchains set conventions that make sense for them
- Keep
visualsigncore lean and minimally opinionated
- Ethereum (RLP and hex)
- Solana (Base58 or Base64)
- Future chains with different encodings
Project structure
Monolithic binary with workspace
We deploy a monolithic binary with many differentchain_parsers that implement chain-specific dependencies. While Rust is more forgiving than languages like Go, overlapping dependencies can still cause conflicts.
Dependency guidelines
-
Don’t add blockchain-specific dependencies to the
parsercrate. These belong in thechain_parserscrates for:- Locality of context
- Clear dependency management
-
Evaluate necessity. Is the library truly essential, or can it be replicated and imported as a
dev-dependency? - Integration tests are required. Every chain should have at least one high-level integration test that validates baseline functionality (e.g., decoding a native token transfer).
- Minimize features. Keep dependencies to a minimum and only enable the features you need. Avoid feature bloat.
Code organization
We’ve found that putting everything inlib.rs becomes unwieldy quickly. General guidelines:
- Layer dependencies and context - solve for basic constructs first
- Create clearly named modules - split into files or directories when files exceed ~2000 lines
- General to specific - organize from most general to most specific implementations
Backwards compatibility
Once the toolchain is fully integrated into production wallets, any output changes must be thoroughly examined. Display values, ordering, and formatting should remain stable between versions.Writing good tests
Test coverage within chains is a great model to aim for. Build incrementally:- Start with basic transaction parsing tests
- Add tests for each transaction type
- Include edge cases and error conditions
- Validate against real-world transaction data
Related documentation
- Project Structure - Architecture and dependency guidelines
- Integration Testing - Testing framework proposal
- Adding a New Chain - Step-by-step chain integration guide