A lightweight Solana SDK for Arduino and ESP32-based microcontrollers.
Solduino - Solana Library for Arduino/ESP32
Solduino is a comprehensive embedded software development kit (SDK) for interacting with the Solana blockchain from Arduino and ESP32 microcontrollers. It provides tools for wallet generation, transaction signing, and RPC communication.
Features
- โ RPC Communication: Full-featured Solana RPC client for ESP32
- โ Wallet Generation: Generate and manage Solana keypairs with Ed25519
- โ Transaction Signing: Build, sign, and serialize Solana transactions
- โ Transaction Serialization: Serialize transactions to Solana wire format
- โ Message Signing: Sign messages with Ed25519 keypairs
- โ HTTPS Support: Secure connections using WiFiClientSecure
- โ Arduino Compatible: Works with Arduino IDE and PlatformIO
Table of Contents
Installation
Prerequisites
- Arduino IDE 1.8.13+ or PlatformIO
- ESP32 Board Support Package installed
- WiFi connection for RPC communication
Installing via Arduino Library Manager
- Open Arduino IDE
- Go to Sketch โ Include Library โ Manage Libraries
- Search for "Solduino" or "sol"
- Click Install
Manual Installation
- Download or clone this repository:
git clone https://github.com/torrey-xyz/solduino.git
- Copy the
solfolder to your Arduinolibrariesdirectory:
Documents\Arduino\libraries\
- macOS: ~/Documents/Arduino/libraries/
- Linux: ~/Arduino/libraries/
- Restart Arduino IDE
Installing ESP32 Board Support
If you haven't installed ESP32 support:
- In Arduino IDE, go to File โ Preferences
- Add this URL to Additional Board Manager URLs:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/packageesp32index.json
- Go to Tools โ Board โ Boards Manager
- Search for "ESP32" and install esp32 by Espressif Systems
Required Libraries
This library depends on:
- ArduinoJson (v6.19.0+) - Available via Library Manager
- WiFi - Built into ESP32
- HTTPClient - Built into ESP32
- WiFiClientSecure - Built into ESP32
Optional libraries for sensor examples:
- DHT sensor library - For
examples/temperaturedht22demo/ - Adafruit Unified Sensor - Common dependency for DHT library
- max6675 - For
examples/temperaturethermocoupledemo/ - TinyGPSPlus - For
examples/gpsneo7mdemo/
Quick Start
Basic RPC Connection Example
#include <WiFi.h>
#include <rpc_client.h>
const char* ssid = "YOURWIFISSID"; const char* password = "YOURWIFIPASSWORD"; const String DEVNET_RPC = "https://api.devnet.solana.com";
RpcClient solanaClient(DEVNET_RPC);
void setup() { Serial.begin(115200); // Connect to WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi connected!"); // Initialize RPC client if (solanaClient.begin()) { Serial.println("RPC Client initialized!"); // Get network version String version = solanaClient.getVersion(); Serial.println("Solana Version: " + version); // Get current slot String slot = solanaClient.getSlot(); Serial.println("Current Slot: " + slot); } }
void loop() { // Your code here }
Architecture
This section describes the architecture and organization of the Solduino library.
Overview
Solduino is organized into three main components as required for embedded software development:
- Core Embedded Software Development Kit (SDK)
- Modules (Wallet Generation, Transaction Signing, RPC Communication)
- Setup Instructions (provided in Installation section)
Directory Structure
sol/
โโโ README.md # Main documentation and setup instructions
โโโ library.properties # Arduino library metadata
โโโ LICENSE # License file (to be added)
โ
โโโ solduino.h # Core SDK entry point
โโโ solduino.cpp # Core SDK implementation
โ
โโโ rpc_client.h # RPC Communication Module (header)
โโโ rpc_client.cpp # RPC Communication Module (implementation)
โ
โโโ keypair.h # Wallet Generation Module (header)
โโโ keypair.cpp # Wallet Generation Module (implementation)
โโโ crypto.h # Cryptographic Utilities (public header: Base58, address helpers)
โโโ crypto_internal.h # Cryptographic Utilities (internal Ed25519 primitives)
โโโ crypto.cpp # Cryptographic Utilities (implementation)
โ
โโโ transaction.h # Transaction Module (header)
โโโ transaction.cpp # Transaction Module (implementation)
โโโ serializer.h # Transaction Serialization Module (header)
โโโ serializer.cpp # Transaction Serialization Module (implementation)
โ
โโโ examples/
โโโ basicrpcdemo/
โ โโโ basicrpcdemo.ino # Basic RPC operations example
โโโ sensortochain_demo/
โ โโโ sensortochain_demo.ino # Generic sensor -> chain workflow
โโโ temperaturethermistordemo/
โ โโโ temperaturethermistordemo.ino # Thermistor temperature push
โโโ temperaturethermocoupledemo/
โ โโโ temperaturethermocoupledemo.ino # MAX6675 thermocouple push
โโโ temperaturedht22demo/
โ โโโ temperaturedht22demo.ino # DHT22 temp+humidity push
โโโ airmq135demo/
โ โโโ airmq135demo.ino # MQ-135 air quality push
โโโ gpsneo7mdemo/
โ โโโ gpsneo7mdemo.ino # NEO-7M GPS position push
โโโ wallet_demo/
โ โโโ wallet_demo.ino # Wallet generation and management example
โโโ transaction_demo/
โโโ transaction_demo.ino # Transaction creation and signing example
โโโ transfer_demo.ino # SOL transfer example
โโโ airdrop_demo.ino # Airdrop request example
Component Details
1. Core Embedded Software Development Kit (SDK)
Purpose: Provides foundational functionality, version management, and acts as the main entry point for the library.
Files:
solduino.h- Main SDK header with:
solduino.cpp- SDK implementation with:
Key Features:
- Version management (major.minor.patch)
- Library-wide constants (URL lengths, key sizes, etc.)
- RPC endpoint constants (mainnet, devnet, testnet)
- Commitment level enums
- Centralized module access
#include <solduino.h>
Solduino sdk; sdk.begin(); Serial.println(sdk.getVersion());
2. Modules
Module 1: RPC Communication (rpcclient.h / rpcclient.cpp)
Purpose: Enables communication with Solana RPC endpoints.
Features:
- HTTPS support via WiFiClientSecure
- Account information retrieval
- Balance queries
- Transaction submission and status checking
- Block and slot information
- Token account operations
- Network health monitoring
- Custom RPC calls
RpcClient- Main RPC client classAccountInfo- Account information structureBlockInfo- Block information structureTransactionResponse- Transaction response structure
#include <solduino.h> // Includes rpc_client.h
RpcClient client(SOLDUINODEVNETRPC); client.begin(); String balance = client.getBalance(publicKey);
Module 2: Wallet Generation (keypair.h / keypair.cpp, crypto.h / crypto.cpp)
Purpose: Generate and manage Solana keypairs on embedded devices.
Features:
- Ed25519 keypair generation using hardware random number generator
- Import wallets from private keys (bytes or Base58 format)
- Import wallets from seeds
- Public/private key management
- Base58 encoding/decoding for Solana addresses
- Message signing with Ed25519
- Signature verification
keypair.h/keypair.cpp- Keypair class for wallet managementcrypto.h/crypto.cpp- Cryptographic utilities (Base58, Ed25519, SHA-512)
#include <solduino.h>
// Generate new keypair Keypair keypair; keypair.generate();
// Get public address char address[64]; keypair.getPublicKeyAddress(address, sizeof(address)); Serial.println(address);
// Get private key (Base58) char privateKey[128]; keypair.getPrivateKeyBase58(privateKey, sizeof(privateKey));
// Import from private key (Base58) Keypair imported; imported.importFromPrivateKeyBase58("YourPrivateKeyBase58");
// Import from seed uint8_t seed[32]; // ... set seed ... imported.importFromSeed(seed);
// Sign a message String message = "Hello, Solana!"; uint8_t signature[64]; keypair.sign(message, signature);
// Verify a signature bool isValid = keypair.verify((uint8t*)message.cstr(), message.length(), signature);
Module 3: Transaction Signing (transaction.h / transaction.cpp)
Purpose: Build and sign Solana transactions.
Features:
- Transaction construction with multiple instructions
- Built-in transfer instruction helper
- Custom instruction support
- Transaction signing with single or multiple keypairs
- Message building with accounts and blockhash
- Account management (signers, writable, readonly)
transaction.h/transaction.cpp- Transaction and Message classes
Transaction- Main transaction classMessage- Transaction message builderInstruction- Instruction representation
#include <solduino.h>
// Create a transfer transaction Transaction tx; uint8_t fromPubkey[32], toPubkey[32];
// Get blockhash from RPC String blockhashStr = client.getLatestBlockhash(); // Parse blockhash to bytes...
// Add transfer instruction tx.addTransferInstruction(fromPubkey, toPubkey, 1000000); // 1 SOL
// Set recent blockhash tx.setRecentBlockhash(blockhash);
// Sign transaction tx.sign(payerKeypair);
// Multi-signer: pass an array of Keypair pointers (clears then applies in order) const Keypair* signers[] = { &feePayer, &cosigner }; tx.sign(signers, 2);
// Offline / multi-party flows: build up signatures with partialSign() tx.partialSign(feePayer); // ...ship tx bytes to the cosigner, who calls tx.partialSign(cosigner)...
// Low-level (legacy) raw-bytes form -- still supported: // tx.sign(privateKey, fromPubkey); // tx.signMultiple(privateKeys, publicKeys, 2);
Module 4: Transaction Serialization (serializer.h / serializer.cpp)
Purpose: Serialize Solana transactions to wire format for RPC submission.
Features:
- Serialize transactions to Solana compact array format
- Base64 encoding for RPC submission
- Base58 encoding support
- Message serialization
- Size calculation for buffer allocation
serializer.h/serializer.cpp- TransactionSerializer and Base64 classes
TransactionSerializer- Transaction serialization utilitiesBase64- Base64 encoding/decoding utilities
#include <solduino.h>
// After creating and signing a transaction Transaction tx; // ... build and sign transaction ...
// Serialize to base64 (for RPC submission) char serializedTx[2048]; if (TransactionSerializer::encodeTransaction(tx, serializedTx, sizeof(serializedTx))) { // Send to RPC String result = client.sendTransaction(String(serializedTx)); }
// Or serialize to raw bytes first uint8_t buffer[2048]; uint16_t serializedLen; if (TransactionSerializer::serializeTransaction(tx, buffer, sizeof(buffer), serializedLen)) { // Encode to base64 char base64[4096]; Base64::encode(buffer, serializedLen, base64, sizeof(base64)); }
3. Setup Instructions
Complete setup instructions are provided in the Installation section above, including:
- Installation methods (Library Manager, manual)
- Prerequisites
- ESP32 board setup
- Required dependencies
- Quick start examples
- Troubleshooting guide
Module Dependencies
solduino.h (Core SDK)
โโโ Includes: rpc_client.h
โโโ Includes: crypto.h, keypair.h
โโโ Includes: transaction.h, serializer.h
โโโ Provides: Constants, Version Info
rpc_client.h (RPC Module) โโโ Depends on: WiFiClientSecure (ESP32) โโโ Depends on: HTTPClient (ESP32) โโโ Depends on: ArduinoJson
keypair.h (Wallet Module) โโโ Depends on: crypto.h โโโ Provides: Keypair management
transaction.h (Transaction Module) โโโ Depends on: crypto.h โโโ Used by: serializer.h
serializer.h (Serializer Module) โโโ Depends on: transaction.h โโโ Provides: Transaction serialization
Design Principles
- Modularity: Each module is self-contained with clear interfaces
- Arduino Compatibility: Follows Arduino library conventions
- ESP32 Optimized: Uses ESP32-specific features (WiFiClientSecure)
- Memory Efficient: Designed for embedded constraints
- Easy to Use: Simple API with comprehensive examples
Extension Points
Adding New Modules
- Create header file (e.g.,
new_module.h) - Create implementation file (e.g.,
new_module.cpp) - Include in
solduino.hunder "Module Includes" section - Update README.md with documentation
- Add example usage
Adding New RPC Methods
- Add method declaration to
RpcClientclass inrpc_client.h - Implement using
makeRpcRequest()inrpc_client.cpp - Add to README.md API reference
- Update example sketch if applicable
Version Management
Version is managed in solduino.h:
SOLDUINOVERSIONMAJOR- Breaking changesSOLDUINOVERSIONMINOR- New featuresSOLDUINOVERSIONPATCH- Bug fixes
"MAJOR.MINOR.PATCH"
Future Enhancements
- [ ] Add WebSocket support for real-time subscriptions
- [ ] Add certificate validation for production use
- [ ] Add secure key storage support
- [ ] Add more instruction builders (token transfers, program interactions)
- [ ] Add transaction simulation support
- [ ] Add account data parsing utilities
Examples
Example 1: Basic RPC Calls
See examples/basicrpcdemo/basicrpcdemo.ino for a complete example.
#include <WiFi.h>
#include <solduino.h>
RpcClient client(SOLDUINODEVNETRPC);
void setup() { // ... WiFi setup ... client.begin(); // Get account info String accountInfo = client.getAccountInfo("11111111111111111111111111111112"); Serial.println(accountInfo); // Get balance String balance = client.getBalance("11111111111111111111111111111112"); Serial.println(balance); }
Example 2: Wallet Generation and Management
See examples/walletdemo/walletdemo.ino for a complete example.
#include <solduino.h>
void setup() { Serial.begin(115200); // Generate new keypair Keypair keypair; if (keypair.generate()) { char address[64]; keypair.getPublicKeyAddress(address, sizeof(address)); Serial.println("New wallet address: " + String(address)); // Sign a message String message = "Hello, Solana!"; uint8_t signature[64]; if (keypair.sign(message, signature)) { // Verify signature bool isValid = keypair.verify((uint8t*)message.cstr(), message.length(), signature); Serial.println("Signature valid: " + String(isValid)); } } }
Example 3: Create and Send Transaction
See examples/transactiondemo/transactiondemo.ino for a complete example.
#include <WiFi.h>
#include <solduino.h>
RpcClient client(SOLDUINODEVNETRPC); Keypair sender, receiver;
void setup() { // ... WiFi setup ... client.begin(); // Generate keypairs sender.generate(); receiver.generate(); // Get blockhash String blockhashStr = client.getLatestBlockhash(); // Parse blockhash... uint8_t blockhash[32]; // Create transfer transaction Transaction tx; uint8_t fromPubkey[32], toPubkey[32]; sender.getPublicKey(fromPubkey); receiver.getPublicKey(toPubkey); tx.addTransferInstruction(fromPubkey, toPubkey, 1000000); // 1 SOL tx.setRecentBlockhash(blockhash); // Sign transaction -- private key never leaves the Keypair object tx.sign(sender); // Serialize and send char serializedTx[2048]; if (TransactionSerializer::encodeTransaction(tx, serializedTx, sizeof(serializedTx))) { String result = client.sendTransaction(String(serializedTx)); Serial.println("Transaction sent: " + result); } }
Example 4: Network Monitoring
void monitorNetwork() {
String health = client.getHealth();
String slot = client.getSlot();
String version = client.getVersion();
Serial.println("Health: " + health);
Serial.println("Slot: " + slot);
Serial.println("Version: " + version);
}
Example 5: Sensor-to-Chain Suite
Use these examples for DePIN-style data publishing workflows:
examples/sensortochaindemo/sensortochaindemo.ino- Generic templateexamples/temperaturethermistordemo/temperaturethermistordemo.ino- Thermistorexamples/temperaturethermocoupledemo/temperaturethermocoupledemo.ino- Thermocouple (MAX6675)examples/temperaturedht22demo/temperaturedht22demo.ino- DHT22 temperature + humidityexamples/airmq135demo/airmq135demo.ino- MQ-135 air sensorexamples/gpsneo7mdemo/gpsneo7mdemo.ino- NEO-7M GPS with TinyGPSPlus
API Reference
RpcClient Class
Constructor
RpcClient(const String& endpoint)
Methods
Connection Management
bool begin()- Initialize RPC clientvoid end()- Clean up resourcesvoid setTimeout(int timeout)- Set request timeout (ms)
String getAccountInfo(const String& publicKey)- Get account informationString getBalance(const String& publicKey)- Get account balance
String getVersion()- Get Solana versionString getSlot()- Get current slotString getBlockHeight()- Get block heightString getHealth()- Check network healthString getLatestBlockhash()- Get latest blockhash (recommended)String getRecentBlockhash()- Get recent blockhash (deprecated, use getLatestBlockhash instead)
String sendTransaction(const String& transaction, const String& encoding = "base58")- Send transaction (returns signature, or empty string on error)bool getTransaction(const String& signature, TransactionResponse& tx)- Get transaction details
String getBlock(uint64_t slot)- Get block informationString getBlockCommitment(uint64_t slot)- Get block commitmentString getBlocks(uint64t startSlot, uint64t endSlot)- Get multiple blocks
String getTokenAccountsByOwner(const String& owner, const String& mint)- Get token accountsString getTokenSupply(const String& mint)- Get token supply
String callRpc(const String& method, const String& params)- Custom RPC call
Keypair Class
Constructor
Keypair()
Methods
Key Generation and Import
bool generate()- Generate a new random keypairbool importFromPrivateKey(const uint8_t* privateKeyBytes)- Import from 64-byte private keybool importFromPrivateKeyBase58(const char* privateKeyBase58)- Import from Base58 private keybool importFromSeed(const uint8_t* seed)- Import from 32-byte seed
bool getPublicKey(uint8_t* output) const- Get public key as bytes (32 bytes)bool getPrivateKey(uint8_t* output) const- Get private key as bytes (64 bytes)bool getPublicKeyAddress(char* address, size_t addressLen) const- Get public key as Base58 addressbool getPrivateKeyBase58(char* output, size_t outputLen) const- Get private key as Base58 string
bool sign(const uint8t message, sizet messageLen, uint8_t signature) const- Sign messagebool sign(const String& message, uint8_t* signature) const- Sign string messagebool verify(const uint8t message, sizet messageLen, const uint8_t signature) const- Verify signature
bool isInitialized() const- Check if keypair is initializedvoid clear()- Clear keypair (zero out keys)
Transaction Class
Constructor
Transaction()
Methods
Transaction Building
bool addTransferInstruction(const uint8t from, const uint8t to, uint64_t amount)- Add SOL transfer instructionbool addInstruction(const uint8t programId, const uint8t accounts[], uint8t accountCount, const uint8t* data, uint16_t dataLength)- Add custom instructionbool setRecentBlockhash(const uint8_t* blockhash)- Set recent blockhash (32 bytes)
Keypair-based overloads โ the private key never leaves the object) bool sign(const Keypair& signer)- Sign with a singleKeypair. Clears any existing signatures.- bool partialSign(const Keypair& signer)
- Sign with a singleKeypairwithout clearing other signatures. Use for multi-party / offline multisig. Mirrorstx.partialSign(payer). - bool sign(const Keypair* const signers[], uint8_t count)
- Sign with an array ofKeypairpointers. Clears first, then applies each in order. - bool sign(const uint8t privateKey, const uint8t publicKey)
- Low-level / legacy: sign with raw key bytes. - bool signMultiple(const uint8t privateKeys[], const uint8t publicKeys[], uint8_t count)
- Low-level / legacy: sign with raw key bytes for multiple signers.
- Message& getMessage()
- Get transaction message - uint8_t getSignatureCount() const
- Get number of signatures - bool getSignature(uint8t index, uint8t* signature) const
- Get signature by index - bool isValidTransaction() const
- Check if transaction is valid - void reset()
- Reset transaction
TransactionSerializer Class
Methods
Serialization
- static bool serializeMessage(const Message& message, uint8t* buffer, uint16t bufferLen, uint16_t& serializedLen)
- Serialize message to wire format - static bool serializeTransaction(const Transaction& transaction, uint8t* buffer, uint16t bufferLen, uint16_t& serializedLen)
- Serialize transaction to wire format
- static bool encodeTransaction(const Transaction& transaction, char* output, size_t outputLen)
- Encode transaction to Base64 - static bool encodeTransactionBase58(const Transaction& transaction, char* output, size_t outputLen)
- Encode transaction to Base58
- static uint16_t calculateMessageSize(const Message& message)
- Calculate message size - static uint16_t calculateTransactionSize(const Transaction& transaction)
- Calculate transaction size
Base64 Class
Methods
- static sizet encode(const uint8t data, sizet dataLen, char output, sizet outputLen)
- Encode bytes to Base64 - static sizet decode(const char input, uint8t output, size_t outputLen)
- Decode Base64 to bytes
Configuration
RPC Endpoints
Mainnet: <pre><code class="lang-cpp">const String MAINNET_RPC = "https://api.mainnet-beta.solana.com";</code></pre>
Devnet: <pre><code class="lang-cpp">const String DEVNET_RPC = "https://api.devnet.solana.com";</code></pre>
Testnet: <pre><code class="lang-cpp">const String TESTNET_RPC = "https://api.testnet.solana.com";</code></pre>
Timeout Configuration
<pre><code class="lang-cpp">client.setTimeout(15000); // 15 seconds</code></pre>
Troubleshooting
Common Issues
HTTP Error -1 (Connection Failed)
- Ensure WiFi is connected
- Check RPC endpoint URL is correct
- Verify HTTPS is properly configured (should be automatic)
- Network instability
- RPC endpoint might be unavailable
- Try increasing timeout: client.setTimeout(30000)
- Ensure ESP32 board support is installed
- Verify ArduinoJson library is installed
- Check all required headers are included
- Verify SSID and password are correct
- Check WiFi signal strength
- Ensure 2.4GHz network (ESP32 doesn't support 5GHz)
Platform Support
- โ ESP32 (tested)
- โ ESP32-S2
- โ ESP32-S3
- โ ESP32-C3
- โ ๏ธ ESP8266 (may require modifications)
- โ Standard Arduino (insufficient memory)
Limitations
- Certificate validation is currently disabled for HTTPS (uses setInsecure()
) - Large JSON responses may require increased buffer sizes
- Memory constraints limit transaction size on some devices
- Real-time WebSocket subscriptions not yet implemented
Security Considerations
โ ๏ธ Important Security Notes:
- Certificate Validation: The library currently uses setInsecure()
which disables SSL certificate validation. For production use, implement proper certificate validation.
- Private Keys: Never expose private keys in your code. Consider using secure storage solutions for production applications.
- Network Security: Always use HTTPS endpoints. Avoid sending sensitive data over unencrypted connections.
- Key Management: Implement proper key management practices. Consider hardware security modules (HSM) for production deployments.
Contributing
Contributions are welcome! Please read our Contributing Guidelines and Code of Conduct before submitting a Pull Request.
We appreciate all kinds of contributions:
- ๐ Bug reports
- ๐ก Feature suggestions
- ๐ Documentation improvements
- ๐ง Code contributions
- โญ Star the repository
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Acknowledgments
- Solana Labs for the Solana blockchain
- ArduinoJson contributors
- ESP32 Arduino Core team
Support
For issues, questions, or contributions:
- GitHub Issues: Create an issue
- Email: parvat.raj2@gmail.com
- Repository: https://github.com/torrey-xyz/solduino
Changelog
Version 1.0.0 (Current)
- First stable release
- Complete RPC, wallet, and transaction SDK baseline
- Instruction builder API (Instruction
,AccountMeta,Transaction::add()) - Program helpers (SystemProgram
,TokenProgram`) and PDA derivation support - Expanded sensor-to-chain demo suite (thermistor, thermocouple, DHT22, MQ-135, GPS)
- Updated architecture/docs for sensor integrations and setup
Made with โค๏ธ for the Solana and Arduino communities