Python port of the WalletKit SDK for WalletConnect Protocol.
✅ Production Ready - Full Implementation Complete
Phase 0: Foundation ✅
- Virtual environment setup
- Project structure
- Testing suite configuration
- EventEmitter implementation (async support)
- Storage abstraction (FileStorage, MemoryStorage)
- JSON-RPC utilities
Phase 1: Core Controllers ✅
- Type definitions (IWalletKit, IWalletKitEngine)
- Crypto utilities (X25519, ChaCha20-Poly1305, HKDF)
- KeyChain implementation
- Crypto controller (encryption/decryption, key management)
- URI parsing and formatting utilities
- Relayer controller (WebSocket communication with reconnection, heartbeat)
- Pairing controller (URI handling, pairing management)
- Core class (orchestrates all controllers)
Phase 2: Client API ✅
- Full SignClient implementation (complete protocol support)
- Engine controller (SignClient wrapper)
- WalletKit client (main API with full method surface)
- Event forwarding and handling
- Store implementations (SessionStore, ProposalStore, RequestStore)
- Session authentication support
Phase 3: Additional Controllers ✅
- Expirer controller (expiry management)
- EventClient (telemetry)
- EchoClient (push notifications)
- Notifications utility
Phase 4: Testing ✅
- 296+ unit tests passing
- 81.80% test coverage (exceeds 70% target)
- Comprehensive test suite covering:
- Relayer (88% coverage - WebSocket, reconnection, heartbeat)
- SignClient (78% coverage - all protocol methods, edge cases)
- Core controllers and utilities
- Integration test framework
Phase 5: Examples & Documentation ✅
- Basic wallet example
- DApp simulator example
- Full flow example
- Comprehensive API documentation
- Integration tests with real WalletConnect relay
- Error handling improvements (retries, timeouts, reconnection)
- Performance optimization
- PyPI distribution
# Create virtual environment
python -m venv venv
# Activate (Windows)
.\venv\Scripts\Activate.ps1
# Activate (Linux/macOS)
source venv/bin/activate
# Install dependencies
# Option 1: Install all dev dependencies
pip install -e ".[all-dev]"
# Option 2: Install specific groups
pip install -e ".[dev,test]" # Development and testing tools only
# Option 3: Use requirements files (legacy, pyproject.toml is source of truth)
pip install -r requirements-dev.txt
pip install -e .Single Source of Truth: pyproject.toml is the authoritative source for all dependencies.
- Production dependencies: Defined in
[project.dependencies] - Optional dependencies: Organized into groups:
dev: Development tools (black, flake8, isort, mypy)test: Testing tools (pytest, playwright, etc.)docs: Documentation tools (sphinx)storage: Storage backends (aiosqlite)security: Security auditing (pip-audit)all-dev: Meta-group including dev, test, docs, security
Version Policy:
- Dependencies use
>=lower bounds with upper bounds (e.g.,>=11.0.0,<14.0.0) - Upper bounds protect against breaking major version changes
- Regular updates recommended for security and features
Security Monitoring:
- Run
pip-auditregularly to check for vulnerabilities - Install with:
pip install -e ".[security]"then runpip-audit - Consider setting up automated security scanning in CI/CD
Generating Locked Requirements:
# Install pip-tools
pip install pip-tools
# Generate locked requirements.txt from pyproject.toml
pip-compile pyproject.toml -o requirements.txt
# Generate locked requirements-dev.txt
pip-compile pyproject.toml --extra dev --extra test --extra docs --extra security -o requirements-dev.txt# Run all tests
pytest
# Run with coverage
pytest --cov=walletkit
# Run specific test file
pytest tests/unit/test_events.pywalletkit-python/
├── src/
│ └── walletkit/ # Main package
│ ├── utils/ # ✅ Utilities (events, storage, jsonrpc, crypto, uri)
│ ├── controllers/ # ✅ Controllers (crypto, keychain, relayer, pairing)
│ ├── types/ # ✅ Type definitions
│ ├── constants/ # ✅ Constants
│ └── core.py # ✅ Core implementation
├── tests/ # ✅ Test suite
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests (to be implemented)
├── docs/ # ✅ Documentation
└── tmp/ # Reference implementations
296+ tests passing ✅
Coverage: 81.80% (exceeds 70% target)
- Relayer: 88% coverage
- SignClient: 78% coverage
- Core utilities: 80%+ coverage
The port follows the same architecture as the JavaScript implementation:
- Core: Orchestrates all controllers (Crypto, Relayer, Pairing)
- Crypto: Handles encryption/decryption, key management
- Relayer: Manages WebSocket communication with relay server
- Pairing: Handles pairing creation and management
- SignClient: Stub implementation (placeholder for full port)
- Engine: Wraps SignClient for protocol interactions
- WalletKit Client: Main API for wallet integration
import asyncio
from walletkit import WalletKit, Core
from walletkit.utils.storage import MemoryStorage
async def main():
# Initialize Core
storage = MemoryStorage()
core = Core(
project_id="your-project-id",
storage=storage,
)
await core.start()
# Initialize WalletKit
wallet = await WalletKit.init({
"core": core,
"metadata": {
"name": "My Wallet",
"description": "My Wallet Description",
"url": "https://mywallet.com",
"icons": ["https://mywallet.com/icon.png"],
},
})
# Listen for session proposals
@wallet.on("session_proposal")
async def on_proposal(event):
proposal_id = event.get("id")
# Approve session
await wallet.approve_session(
id=proposal_id,
namespaces={
"eip155": {
"chains": ["eip155:1"],
"methods": ["eth_sendTransaction", "eth_sign"],
"events": ["chainChanged"],
},
},
)
# Pair with a URI from a dApp
await wallet.pair("wc:...")
# Keep running
await asyncio.Event().wait()
asyncio.run(main())import asyncio
from walletkit import WalletKit, Core
from walletkit.utils.storage import MemoryStorage
async def main():
# Initialize
storage = MemoryStorage()
core = Core(project_id="your-project-id", storage=storage)
await core.start()
dapp = await WalletKit.init({
"core": core,
"metadata": {
"name": "My DApp",
"description": "My DApp Description",
"url": "https://mydapp.com",
"icons": ["https://mydapp.com/icon.png"],
},
})
# Create pairing URI
pairing = await dapp.core.pairing.create({
"methods": ["wc_sessionPropose"],
})
uri = pairing.get("uri")
print(f"Share this URI with wallet: {uri}")
await asyncio.Event().wait()
asyncio.run(main())See examples/ directory for complete runnable examples.
See docs/ folder for comprehensive documentation:
- API Reference - Complete API documentation
- Usage Guide - Usage examples and integration guides
- Wallet Setup - Wallet setup for integration testing
from walletkit import WalletKit, Core
from walletkit.utils.storage import MemoryStorage
# Initialize
storage = MemoryStorage()
core = Core(project_id="your-project-id", storage=storage)
await core.start()
wallet = await WalletKit.init({
"core": core,
"metadata": {
"name": "My Wallet",
"description": "My Wallet Description",
"url": "https://mywallet.com",
"icons": ["https://mywallet.com/icon.png"],
},
})
# Handle session proposals
@wallet.on("session_proposal")
async def on_proposal(event):
proposal_id = event.get("id")
# Auto-approve or show UI
await wallet.approve_session(
id=proposal_id,
namespaces={
"eip155": {
"chains": ["eip155:1"],
"methods": ["eth_sendTransaction", "eth_sign"],
"events": ["chainChanged", "accountsChanged"],
},
},
)
# Handle requests
@wallet.on("session_request")
async def on_request(event):
topic = event.get("topic")
request_id = event.get("id")
# Process request and respond
await wallet.respond_session_request(
topic=topic,
response={
"id": request_id,
"jsonrpc": "2.0",
"result": "0x...",
},
)
# Pair with dApp
await wallet.pair("wc:...")from walletkit import WalletKit, Core
from walletkit.utils.storage import MemoryStorage
# Initialize
storage = MemoryStorage()
core = Core(project_id="your-project-id", storage=storage)
await core.start()
dapp = await WalletKit.init({
"core": core,
"metadata": {
"name": "My DApp",
"description": "My DApp Description",
"url": "https://mydapp.com",
"icons": ["https://mydapp.com/icon.png"],
},
})
# Create pairing URI
pairing = await dapp.core.pairing.create({
"methods": ["wc_sessionPropose"],
})
uri = pairing.get("uri")
print(f"Share this URI: {uri}")
# Wait for session approval
@dapp.on("session_approve")
async def on_approve(event):
session = event.get("session")
topic = session.get("topic")
print(f"Session approved: {topic}")
# Send request
await dapp.engine.request({
"topic": topic,
"chainId": "eip155:1",
"request": {
"method": "eth_sendTransaction",
"params": {
"to": "0x...",
"value": "0x0",
},
},
})Code: Licensed under the GNU Affero General Public License v3.0 (AGPLv3). See LICENSE for details.
Documentation and other non-code materials: Licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC-BY-SA-4.0). See LICENSE-DOCS for details.