Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1020f28
Initial
dev2-nomo Jan 9, 2025
2c9c78c
Initial
dev2-nomo Jan 9, 2025
bcc503a
Migrate to builtIn HDNode insteaf of bip32
dev2-nomo Jan 13, 2025
610a5e6
Fix Lint
dev2-nomo Jan 13, 2025
d65d3de
Fix Pipe
dev2-nomo Jan 13, 2025
e02dc68
Refactor derivation functions to use NetworkNodeInfo and simplify par…
dev2-nomo Jan 13, 2025
b2ad177
Add command framework with Help and Exit commands to CLI Example
dev2-nomo Jan 13, 2025
0659823
Bip39 impl (#141)
dev2-nomo Jan 30, 2025
13540e8
Update http package to version 1.3.0 and SDK constraint to 3.3.0
dev2-nomo Jan 30, 2025
ae830e8
Merge branch 'main' of https://github.com/nomo-app/walletkit-dart int…
dev2-nomo Jan 30, 2025
ae29d9f
Fix Lint
dev2-nomo Jan 30, 2025
dbda488
test: Enhance BIP39 tests to validate extended private key generation
dev2-nomo Jan 30, 2025
3731128
refactor: Comment out mnemonic generation test for word 'arm'
dev2-nomo Jan 30, 2025
353d1f0
feat: Add TODO for future test cases in multiple languages
dev2-nomo Jan 30, 2025
a48eac4
Update sdk
dev2-nomo Mar 20, 2025
806441e
Merge branch 'main' of https://github.com/nomo-app/walletkit-dart int…
dev2-nomo Mar 20, 2025
db65476
Segwit fee fix (#149)
dev2-nomo Mar 20, 2025
4997ead
Initial (#130)
nomo-app Mar 20, 2025
8137b73
format
dev2-nomo Mar 20, 2025
41abf45
Add cursorignore
dev2-nomo Mar 24, 2025
fea2619
Update Readme and add License
dev2-nomo Mar 24, 2025
d94e931
Start Refactor
dev2-nomo Mar 24, 2025
602f9d0
Fix Imports
dev2-nomo Mar 26, 2025
8b8c9b0
Fix Input Output Length Byte
ThomasFercher Sep 26, 2025
b700dbd
Wallet Impl First Try
ThomasFercher Sep 28, 2025
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
11 changes: 11 additions & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.dart_tool/
build/
coverage/
.idea/

.env*

protos/
coverage/

lib/src/crypto/tron/repositories/rpc/api/
2 changes: 2 additions & 0 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ jobs:
"test/ci/sending",
"test/ci/tron",
"test/ci/rlp",
"test/ci/bip39",
"test/ci/bip32",
]
steps:
- uses: actions/checkout@v3
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

44 changes: 44 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Repository Guidelines

## Project Structure & Module Organization
- `lib/`: Package source entry `walletkit_dart.dart` plus modules under `src/` (EVM, UTXO, Tron, wallet utils, domain entities, utils).
- `test/`: Organized by domain (e.g., `test/ci/evm`, `test/ci/fetching`, `test/ci/tron`). `ci-mocked/` holds tests with mocks; `no_ci/` are local-only.
- `example/`: Minimal CLI helpers and usage snippets.
- `protos/`: Protocol definitions; generated Dart files live in `lib/src/crypto/tron/repositories/rpc/`.
- `coverage/`: Local/CI coverage outputs.

## Build, Test, and Development Commands
- Prereqs: Dart SDK `^3.7.2` (see `pubspec.yaml`).
- Install deps: `dart pub get`
- Static analysis: `dart analyze`
- Format code: `dart format .`
- Run all tests: `dart test`
- Run a test subset: `dart test test/ci/evm`
- Generate coverage (local):
- `dart pub global activate coverage`
- `dart test --coverage=coverage`
- `dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --package=. --report-on=lib`

## Coding Style & Naming Conventions
- Style: Dart `package:lints/recommended` (see `analysis_options.yml`).
- Indentation: 2 spaces; max line length per Dart defaults.
- Naming: types in `UpperCamelCase`, methods/vars in `lowerCamelCase`, files in `lower_snake_case.dart`.
- Keep public API exports centralized in `lib/walletkit_dart.dart`.

## Testing Guidelines
- Framework: `package:test` with domain-focused directories.
- Name tests after subject and behavior: `feature_action_test.dart`.
- Prefer deterministic tests; use `ci-mocked` for network-sensitive paths.
- Env for integration tests: uses `.env` via `dotenv`. Common keys: `ETHERSCAN_API_KEYS`, `TRONSCAN_API_KEYS`, `DEV_SEED`, `REJECT_SEED`, `TRON_SEED`. Do not commit secrets.

## Commit & Pull Request Guidelines
- Commits: prefer Conventional Commits (`feat:`, `fix:`, `refactor:`, `test:`, `chore:`). Keep changes scoped and descriptive.
- PRs should include:
- Purpose and summary of changes; link related issues.
- Notes on API surface changes (exports in `walletkit_dart.dart`).
- Test coverage: list added/updated tests and how to run a focused subset.
- Screenshots/trace snippets when debugging protocol/tx parsing.

## Security & Configuration Tips
- Secrets: store locally in `.env`; CI uses repository secrets. Never log private keys or seeds.
- When adding new RPC/backends, gate keys via `dotenv` and add mocked tests under `test/ci-mocked`.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 NOMO

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
184 changes: 67 additions & 117 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,154 +1,104 @@
[![TestSuite](https://img.shields.io/github/actions/workflow/status/nomo-app/walletkit-dart/dart.yml?branch=main&style=for-the-badge&logo=testing-library&label=Test%20Suite)](https://github.com/nomo-app/walletkit-dart/actions/workflows/dart.yml)
[![TestSuite](https://img.shields.io/github/actions/workflow/status/nomo-app/walletkit-dart/dart.yml?branch=wallet_interface&style=for-the-badge&logo=testing-library&label=Test%20Suite)](https://github.com/nomo-app/walletkit-dart/actions/workflows/dart.yml)
[![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdev.nomo.app%2Fwalletkit-dart%2Fbadges%2Fcoverage.json&query=message&style=for-the-badge&logo=codecov&logoSize=24&label=Coverage&link=https%3A%2F%2Fdev.nomo.app%2Fwalletkit-dart%2Fcoverage%2F)](https://dev.nomo.app/walletkit-dart/coverage/)

# WalletKit-Dart

WalletKit-Dart provides features for interacting with
Bitcoin/Ethereum/Tron/ZENIQ/ZENIQ Smartchain/Polygon/Binance
Smartchain/Litecoin/Bitcoin Cash/Eurocoin as well as several layer 2 chains. If
needed, it is easy to expand WalletKit-Dart with other chains.

See the [Uniswap WebOn](https://github.com/nomo-app/uniswap-webon) or the
Unit-tests for a practical example how to use WalletKit-Dart.

See the [api-docs](https://dev.nomo.app/walletkit-dart) for a list of individual
functions.
A powerful Dart library for interacting with multiple blockchain networks, including Bitcoin, Ethereum, Tron, ZENIQ, Polygon, Binance Smart Chain, Litecoin, Bitcoin Cash, and Eurocoin, as well as various layer 2 chains.

## Features

- Sending transactions, including legacy/SegWit/P2SH/EVM
- Fetching transactions and balances, including xPub/zPub/ERC20
- Advanced parsing for making smart contract calls readable for humans (EVM)
- Deriving addresses from mnemonics (HD-Wallet)
- Performance by default: Immutable data will be cached in-memory
- A large suite of Unit-tests

## Why WalletKit-Dart?

WalletKit-Dart has been inspired by the
[WalletKit-C](https://github.com/blockset-corp/walletkit) from blockset-corp and
by [bitcoin_flutter](https://github.com/dart-bitcoin/bitcoin_flutter) from the
dart-bitcoin-project.

The WalletKit-C was one of the first WalletKits that combined UTXO-chains and
EVM-chains under a unified class hierarchy. However, the WalletKit-C was plagued
by race conditions and memory corruptions. Also, the WalletKit-C had an "object
oriented architecture" that was poorly supported by the C-language.

bitcoin_flutter worked well, but bitcoin_flutter did not support modern
null-safe Dart and it was difficult to expand for multiple chains.

WalletKit-Dart has been developed to solve all those problems. WalletKit-Dart
works with modern Dart-versions and is easy to expand for multiple chains.

## How to integrate

First, add this package as a Git-submodule by using Git-commands:

```
- **Multi-Chain Support**: Native support for both UTXO-based and EVM-based chains
- **Transaction Management**:
- Send transactions (legacy/SegWit/P2SH/EVM)
- Fetch transactions and balances (including xPub/zPub/ERC20)
- Advanced smart contract call parsing for human readability
- **Wallet Features**:
- HD-Wallet support with mnemonic phrase derivation
- Address validation and management
- Fee estimation
- **Performance Optimized**:
- In-memory caching for immutable data
- Stateless API design
- **Comprehensive Testing**:
- Extensive unit test suite
- CI/CD integration

## Getting Started

### Installation

Add WalletKit-Dart to your project as a Git submodule:

```bash
git submodule add https://github.com/nomo-app/walletkit-dart.git packages/walletkit-dart
```

Next, expand your pubspec.yaml accordingly:
Update your `pubspec.yaml`:

```
```yaml
dependencies:
walletkit_dart:
path: packages/walletkit-dart
walletkit_dart:
path: packages/walletkit-dart
```

Afterwards, clone submodules with:
Initialize the submodules:

```
```bash
git submodule update --init --recursive
```

The `--recursive` is important because WalletKit-Dart depends on other
grandchild-submodules.
### Requirements

## Architecture

WalletKit-Dart is built for both _UTXO-chains_ and _EVM-chains_. WalletKit-Dart
provides a class hierarchy where both `UTXOTransaction` and `EVMTransaction`
inherit from a `GenericTransaction` base class.

Here is a quick summary if you do not yet understand the difference between UTXO
and EVM:

```
UTXO-based chains and EVM-based chains are two different architectures for blockchain systems.
UTXO (Unspent Transaction Output) is a concept used in Bitcoin and some other cryptocurrencies.
In this architecture, each transaction spends one or more previously unspent outputs and creates new outputs.
The sum of the inputs must be equal to or greater than the sum of the outputs.
EVM (Ethereum Virtual Machine) is used in Ethereum and some other blockchain platforms that support smart contracts.
In this architecture, each transaction is executed in the EVM as a smart contract, which can modify the state of the blockchain and create new contracts.
The state is stored in a database, rather than as a set of unspent outputs.
In summary, UTXO-based chains focus on tracking ownership of tokens, while EVM-based chains focus on executing arbitrary code in the form of smart contracts.
```

## API Philosophy
- Dart SDK: ^3.7.2
- See [pubspec.yaml](pubspec.yaml) for detailed dependencies

WalletKit-Dart provides a _stateless API_. Neither does it store seed phrases,
nor does it store transactions. It is the users responsibility to store any
needed data.

By design, WalletKit-Dart does not have any persistent databases. Instead,
WalletKit-Dart only has a few in-memory-caches to improve performance of
repeated calls. This design helps to simplify the API.

Moreover, WalletKit-Dart provides different APIs for UTXO-chains and EVM-chains.
Although every transaction inherits from a generic base transaction, we want to
provide APIs that are specifically targeted for the architecture of a chain. In
that sense, we deviate from a traditional object oriented approach.

In other words, while we aim to reuse code between chains, we do not want to
create broken abstraction layers by abstracting too much complexity away.

## Backend APIs

Depending on the chain, WalletKit-Dart depends on multiple backend APIs. For
UTXO-chains, WalletKit-Dart depends on the
[ElectrumX Protocol](https://electrumx.readthedocs.io/en/latest/protocol-methods.html).
## Architecture

For EVM-chains, WalletKit-Dart depends on several JSON-RPC-providers as well as
etherscan-styled APIs.
WalletKit-Dart is designed to handle both UTXO-based and EVM-based chains efficiently:

## The following Unit-tests show how to use WalletKit-Dart
### UTXO Chains
- Bitcoin and similar cryptocurrencies
- Tracks ownership through unspent transaction outputs
- Efficient for simple value transfers

[Get Token Info for a ERC20 Token](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/evm/erc20_test.dart)
### EVM Chains
- Ethereum and compatible networks
- Supports smart contracts and complex transactions
- State-based architecture

[Fetch EVM Transaction from Explorer](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/evm/evm_explorer_test.dart)
## API Design Philosophy

[Walletkit Json RPC Interface](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/evm/evm_rcp_test.dart)
- **Stateless**: No storage of seed phrases or transactions
- **Memory-Efficient**: Uses in-memory caches for performance
- **Chain-Specific APIs**: Specialized interfaces for different chain architectures
- **No Broken Abstractions**: Maintains clear separation between chain types

[Fetch Bitcoin Transactions](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/fetching/assets/bitcoin_fetch_test.dart)
## Backend Integration

[Get best health endpoints utxo](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/fetching/endpoint_test.dart)
- **UTXO Chains**: Uses the [ElectrumX Protocol](https://electrumx.readthedocs.io/en/latest/protocol-methods.html)
- **EVM Chains**: Integrates with JSON-RPC providers and Etherscan-style APIs

[EPubKey Derivation](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/fetching/epubkey_test.dart)
## Examples

[Fetch UTXO Transaction](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/fetching/fetch_utxo_transactions_test.dart)
Check out these example implementations:

[Parse MessageHex into EVM Transaction](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/parsing/parse_hex_transaction_test.dart)
- [Uniswap WebOn](https://github.com/nomo-app/uniswap-webon)
- [API Documentation](https://dev.nomo.app/walletkit-dart)

[Decode datafield from EVM Transaction](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/parsing/reverse-hash-computation_test.dart)
### Test Examples

[Address Validation](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/sending/address_validation_test.dart)
The test suite provides practical examples for various use cases:

[Estimate Fee](https://github.com/nomo-app/walletkit-dart/blob/main/test/ci/gasfees_test.dart)
- [ERC20 Token Info](test/ci/evm/erc20_test.dart)
- [EVM Transaction Fetching](test/ci/evm/evm_explorer_test.dart)
- [Bitcoin Transaction Management](test/ci/fetching/assets/bitcoin_fetch_test.dart)
- [Address Validation](test/ci/sending/address_validation_test.dart)
- [Gas Fee Estimation](test/ci/gasfees_test.dart)

[Send EVM Transaction](https://github.com/nomo-app/walletkit-dart/blob/main/test/no_ci/send_evm_test.dart)
## Contributing

[Fetch Peers from ElectrumX](https://github.com/nomo-app/walletkit-dart/blob/main/test/no_ci/peers_test.dart)
Contributions are welcome! Please feel free to submit a Pull Request.

[Broadcast UTXO Transaction](https://github.com/nomo-app/walletkit-dart/blob/main/test/no_ci/wallet_test.dart)
## License

protoc -I.
--dart_out=grpc:/home/thomas/src/walletkit-dart/lib/src/crypto/tron/rpc
core/Tron.proto core/Discover.proto core/TronInventoryItems.proto
core/contract/common.proto core/contract/account_contract.proto
core/contract/asset_issue_contract.proto core/contract/balance_contract.proto
core/contract/exchange_contract.proto core/contract/market_contract.proto
core/contract/proposal_contract.proto core/contract/shield_contract.proto
core/contract/smart_contract.proto core/contract/storage_contract.proto
core/contract/witness_contract.proto api/api.proto
This project is licensed under the MIT License - see the LICENSE file for details.
43 changes: 43 additions & 0 deletions example/command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'dart:async';

abstract class Command<T> {
String get name;
String get description;
FutureOr<T> execute(List<String> args);
}

class CommandResult<T> {
final bool success;
final T? data;
final String? error;

CommandResult.success(this.data)
: success = true,
error = null;
CommandResult.failure(this.error)
: success = false,
data = null;

@override
String toString() {
if (success) {
return data?.toString() ?? 'Command completed successfully';
} else {
return 'Error: ${error ?? "Unknown error"}';
}
}
}

class CommandRegistry {
final Map<String, Command> _commands = {};

void register(Command command) {
_commands[command.name.toLowerCase()] = command;
}
Comment on lines +34 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add duplicate command name validation.

The register method should check for existing commands with the same name (case-insensitive) to prevent overwriting.

  void register(Command command) {
+   ArgumentError.checkNotNull(command, 'command');
+   final normalizedName = command.name.toLowerCase();
+   if (_commands.containsKey(normalizedName)) {
+     throw ArgumentError('Command "${command.name}" is already registered');
+   }
-   _commands[command.name.toLowerCase()] = command;
+   _commands[normalizedName] = command;
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void register(Command command) {
_commands[command.name.toLowerCase()] = command;
}
void register(Command command) {
ArgumentError.checkNotNull(command, 'command');
final normalizedName = command.name.toLowerCase();
if (_commands.containsKey(normalizedName)) {
throw ArgumentError('Command "${command.name}" is already registered');
}
_commands[normalizedName] = command;
}


Command? get(String name) {
return _commands[name.toLowerCase()];
}

List<Command> get commands => _commands.values.toList();
}
38 changes: 38 additions & 0 deletions example/commands.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'dart:io';

import 'command.dart';

class HelpCommand extends Command<String> {
final CommandRegistry registry;

HelpCommand(this.registry);

@override
String get name => 'help';

@override
String get description => 'Show available commands';

@override
String execute(List<String> args) {
final buffer = StringBuffer('Available commands:\n');
for (final command in registry.commands) {
buffer.writeln(' ${command.name.padRight(10)} - ${command.description}');
}
return buffer.toString();
}
}

class ExitCommand extends Command<void> {
@override
String get name => 'exit';

@override
String get description => 'Exit the application';

@override
Future<void> execute(List<String> args) async {
print('Goodbye!');
exit(0);
}
}
Comment on lines +26 to +38
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement graceful shutdown.

The ExitCommand uses exit(0) which abruptly terminates the application. Consider implementing a graceful shutdown that allows cleanup of resources.

  @override
  Future<void> execute(List<String> args) async {
    print('Goodbye!');
-   exit(0);
+   // Signal the application to start cleanup
+   return Future.value();
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class ExitCommand extends Command<void> {
@override
String get name => 'exit';
@override
String get description => 'Exit the application';
@override
Future<void> execute(List<String> args) async {
print('Goodbye!');
exit(0);
}
}
class ExitCommand extends Command<void> {
@override
String get name => 'exit';
@override
String get description => 'Exit the application';
@override
Future<void> execute(List<String> args) async {
print('Goodbye!');
// Signal the application to start cleanup
return Future.value();
}
}

Loading