') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - Sentinel-Bluebuilder/blue-csharp-sdk: C# / .NET 8 SDK for Sentinel dVPN — WireGuard + V2Ray tunnels, Cosmos blockchain, 814 tests. Includes a full WPF desktop client example. · GitHub
Skip to content

Repository files navigation

Sentinel dVPN SDK — C# / .NET 8

Complete protocol library for building decentralized VPN applications on the Sentinel network with C# and .NET 8. WireGuard and V2Ray tunnels, wallet management, session handling, and all chain message types for Sentinel v3. 814+ tests, zero external service dependencies. Includes a full WPF desktop client example with documented UI patterns.

Also available:JavaScript SDK | AI Connect (zero-config JS wrapper)

Quick Start

usingvarvpn=newSentinelVpnClient(SentinelWallet.FromMnemonic(mnemonic),new());varresult=awaitvpn.ConnectAutoAsync(newConnectAutoOptions{Countries=["DE","US"]});awaitvpn.DisconnectAsync();// or let IDisposable handle it

Install

dotnet add package Sentinel.SDK # Meta-package (all three)
dotnet add package Sentinel.SDK.Core # Wallet + chain only
dotnet add package Sentinel.SDK.Node # + handshake + VPN client
dotnet add package Sentinel.SDK.Tunnel # + WireGuard/V2Ray

Requires .NET 8.0+. WireGuard nodes require admin privileges; without admin, the SDK connects via V2Ray nodes (~70% of the network). V2Ray 5.2.1 binary required for V2Ray nodes (do NOT use 5.44.1+).

NuGet Packages

PackageDescription
Sentinel.SDK.CoreWallet, chain client, protobuf encoding, transaction building, error hierarchy, helpers, state persistence
Sentinel.SDK.NodeNode discovery, V3 handshake, session management, SentinelVpnClient orchestrator
Sentinel.SDK.TunnelWireGuard tunnel service, V2Ray process management, kill switch, DNS leak prevention

Architecture

 ┌──────────────────────────────────────────┐
│ Your Application │
└─────────────────┬────────────────────────┘
│
┌─────────────────▼────────────────────────┐
│ Sentinel.SDK.Node │
│ │
│ SentinelVpnClient (orchestrator) │
│ ConnectAsync SessionManager │
│ ConnectAutoAsync Handshake │
│ ConnectViaSubAsync NodeClient │
│ DisconnectAsync DiagnoseAsync │
│ Events: Progress, Connected, │
│ Disconnected, Error │
└──────┬───────────────────────┬───────────┘
│ │
┌────────────────▼──────────┐ ┌────────▼─────────────────┐
│ Sentinel.SDK.Core │ │ Sentinel.SDK.Tunnel │
│ │ │ │
│ SentinelWallet │ │ WireGuard/ │
│ ChainClient (LCD+RPC) │ │ WireGuardTunnel │
│ TransactionBuilder │ │ KillSwitch │
│ MessageBuilder (17 msgs) │ │ DnsLeakPrevention │
│ SentinelErrors (42 codes)│ │ V2Ray/ │
│ AutoReconnect │ │ V2RayConfigBuilder │
│ CircuitBreaker │ │ V2RayProcess │
│ NetworkMonitor │ └───────────────────────────┘
│ NodeCache, SpeedTest │
│ SessionTracker │
│ VpnSettings, Helpers │
│ ISdkLogger, StateManager │
│ TofuTrustStore │
└───────────────────────────┘

Full Example

usingSentinel.SDK.Core;usingSentinel.SDK.Node;// 1. Create or restore walletusingvarwallet=SentinelWallet.FromMnemonic("your twelve word mnemonic phrase goes here ...");// 2. Create VPN client with optionsusingvarvpn=newSentinelVpnClient(wallet,newSentinelVpnOptions{Gigabytes=1,FullTunnel=true,Logger=newConsoleSdkLogger(),});// 3. Subscribe to events for UI bindingvpn.Progress+=(_,e)=>Console.WriteLine($"[{e.Step}] {e.Detail}");vpn.Connected+=(_,e)=>Console.WriteLine($"Connected to {e.NodeAddress}");vpn.Disconnected+=(_,e)=>Console.WriteLine($"Disconnected: {e.Reason}");vpn.Error+=(_,e)=>Console.WriteLine($"Error [{e.Code}]: {e.Message}");// 4. Auto-pick best node and connectvarresult=awaitvpn.ConnectAutoAsync(newConnectAutoOptions{Countries=["DE","US"],ServiceType="wireguard",MaxAttempts=3,});Console.WriteLine($"VPN active! Node: {result.NodeAddress}, Session: {result.SessionId}");// 5. Verify traffic is routed through VPNvarverify=awaitvpn.VerifyConnectionAsync();Console.WriteLine($"External IP: {verify.ExternalIp}");// 6. Disconnect (or let Dispose handle it)awaitvpn.DisconnectAsync();

Key Features

  • IDisposable everywhere -- SentinelWallet, SentinelVpnClient, ChainClient all implement IDisposable for deterministic cleanup. using statements guarantee tunnel teardown and key material disposal
  • Full async/await -- every network operation is async with CancellationToken support
  • ISdkLogger interface -- plug in your logging framework (Serilog, NLog, ILogger<T> adapter). Ships with ConsoleSdkLogger and NullSdkLogger
  • Event-driven -- Progress, Connected, Disconnected, Error events for clean UI binding (WPF, MAUI, Avalonia)
  • Record types -- immutable options (SentinelVpnOptions, ConnectAutoOptions) and results (ConnectionResult, ConnectionDiagnostics)
  • Typed exception hierarchy -- SentinelException base with WalletException, ChainException, NodeException, TunnelException, HandshakeException, each carrying .Code and .Details
  • Two tunnel protocols -- WireGuard (kernel-level, fastest) and V2Ray (userspace, no admin required) with automatic fallback
  • 42 typed error codes -- machine-readable .Code on every exception, with severity levels (fatal, retryable, recoverable) and human-friendly messages via ErrorSeverity.UserMessage()
  • 17 chain message types -- sessions, subscriptions, plans, providers, leases, fee grants, bank send
  • Session reuse -- detects existing active sessions to avoid double-paying
  • 409 conflict recovery -- automatically creates new session on handshake conflict
  • Clock drift detection -- skips V2Ray nodes with >120s drift (VMess AEAD failure)
  • Auto-reconnect -- AutoReconnect class with exponential backoff and configurable retry policy
  • Circuit breaker -- CircuitBreaker prevents repeated connections to failing nodes
  • Network monitor -- NetworkMonitor tracks system network state changes
  • Kill switch -- firewall rules block all non-VPN traffic while connected
  • DNS leak prevention -- forces DNS through the tunnel
  • TOFU TLS -- trust-on-first-use certificate pinning per node
  • LCD failover -- automatic rotation across 4 LCD endpoints
  • Speed testing -- direct and SOCKS5 proxy speed measurement
  • State persistence -- save/load connection state across process restarts

Project Structure

csharp-sdk/
├── Sentinel.SDK.sln
├── src/
│ ├── Sentinel.SDK.Core/ # Foundation layer
│ │ ├── Wallet.cs Key generation, BIP39/BIP44, secp256k1, Bech32
│ │ ├── ISentinelWallet.cs Wallet interface for testability
│ │ ├── ChainClient.cs LCD queries with failover + broken pagination handling
│ │ ├── IChainClient.cs Chain client interface for DI
│ │ ├── TransactionBuilder.cs SIGN_MODE_DIRECT, gas estimation, sequence recovery
│ │ ├── MessageBuilder.cs 17 Cosmos message types (protobuf)
│ │ ├── ProtobufWriter.cs Low-level protobuf wire format
│ │ ├── SentinelErrors.cs Exception hierarchy + 42 error codes + severity map
│ │ ├── ISdkLogger.cs Pluggable logger interface + Console/Null implementations
│ │ ├── AutoReconnect.cs Reconnection with exponential backoff
│ │ ├── CircuitBreaker.cs Fail-fast for repeatedly-failing nodes
│ │ ├── NetworkMonitor.cs System network state tracking
│ │ ├── NodeCache.cs In-memory node cache with TTL
│ │ ├── CredentialStore.cs Encrypted credential persistence
│ │ ├── SessionTracker.cs Session state + payment mode tracking
│ │ ├── StateManager.cs Connection state persistence
│ │ ├── VpnSettings.cs Typed settings with defaults
│ │ ├── SpeedTest.cs Direct + SOCKS5 speed measurement
│ │ ├── DynamicTransportRates.cs Transport reliability scoring
│ │ ├── BatchBuilder.cs Batch TX construction (operator use)
│ │ ├── NodeTester.cs Network audit tooling (operator use)
│ │ ├── TofuTrustStore.cs TLS certificate pinning store
│ │ ├── DependencyCheck.cs Runtime dependency verification
│ │ ├── SystemProxy.cs System proxy configuration
│ │ ├── Constants.cs Chain IDs, endpoints, gas prices
│ │ ├── Helpers.cs FormatP2P, FormatBytes, ShortAddress, ...
│ │ └── Types.cs Shared types, enums, records
│ │
│ ├── Sentinel.SDK.Node/ # Connection layer
│ │ ├── SentinelVpnClient.cs High-level orchestrator (Connect/Auto/Plan/Disconnect)
│ │ ├── SentinelVpnService.cs Background service wrapper
│ │ ├── Handshake.cs V3 handshake protocol implementation
│ │ ├── NodeClient.cs Node status + metadata queries
│ │ └── SessionManager.cs Session lifecycle + allocation tracking
│ │
│ └── Sentinel.SDK.Tunnel/ # Tunnel layer
│ ├── WireGuard/
│ │ ├── WireGuardTunnel.cs Windows service tunnel management
│ │ ├── KillSwitch.cs Firewall-based traffic blocking
│ │ └── DnsLeakPrevention.cs DNS override + leak prevention
│ └── V2Ray/
│ ├── V2RayConfigBuilder.cs JSON config matching sentinel-go-sdk format
│ └── V2RayProcess.cs V2Ray process lifecycle management
│
├── tests/
│ └── Sentinel.SDK.Tests/ # 814+ tests across 33 test classes
│
├── desktop/
│ └── HandshakeDVPN/ # Example WPF desktop client — Windows (5,980 lines)
│ ├── App.xaml Theme system — colors, fonts, styles
│ ├── MainWindow.xaml UI layout — sidebar, orb, status bar
│ ├── MainWindow.xaml.cs App logic — state machine, events, polling
│ └── Services/ SDK integration layer
│
├── examples/ # Small code snippets
│ ├── QueryNodes/ List active nodes
│ ├── WalletBasics/ Create/import wallet
│ └── ConnectDirect/ Connect to a specific node
│
└── docs/
├── QUICK-START.md Get running in under 50 lines
├── API-REFERENCE.md Complete public API catalog
└── EDGE-CASES.md Gotchas and production lessons learned

Example: Full WPF Desktop Client

The desktop/HandshakeDVPN/ directory contains a complete example Windows dVPN desktop application built with WPF and .NET 8. It is not a production release — it's a reference for builders creating their own Windows desktop VPN clients.

What's included (5,980 lines across 7 files):

FileLinesWhat You Learn
App.xaml125Complete WPF theme — color tokens, font loading, reusable button/textbox styles with hover/disabled states
App.xaml.cs62App startup, backend initialization, exception handling
MainWindow.xaml583Full layout — sidebar node browser, connection orb, status bar, test dashboard, wallet overlay
MainWindow.xaml.cs3,669Connection state machine, node rendering, search/filter, polling timers, speed display, animations
Services/IHnsVpnBackend.cs403Service interface + all data models (nodes, sessions, status, pricing)
Services/NativeVpnClient.cs1,076SDK integration — wallet, chain queries, connect/disconnect, session management, DNS config
Services/DiskCache.cs62JSON file persistence to LocalAppData

Features: node browser with search/filter, animated connection orb, per-GB and per-hour pricing, real-time speed display, built-in node tester with export, Handshake DNS integration, wallet management (create/import/send), session tracking.

See the desktop client README for the full architecture guide, UI structure, and code-behind patterns.

Error Handling

Every SDK error extends SentinelException with a machine-readable .Code:

usingSentinel.SDK.Core;try{varresult=awaitvpn.ConnectAutoAsync(opts);}catch(NodeExceptionex)when(ErrorSeverity.Get(ex.Code)=="retryable"){// Try another nodelogger.Warn($"Retryable: {ex.Code} -- {ErrorSeverity.UserMessage(ex.Code)}");}catch(ChainExceptionex){logger.Error($"Chain error [{ex.Code}]: {ex.Message}");}catch(TunnelExceptionex){logger.Error($"Tunnel error [{ex.Code}]: {ex.Message}");}

Exception hierarchy: SentinelException > WalletException, ChainException, NodeException, TunnelException, HandshakeException.

Message Builder (17 Message Types)

CategoryMessages
SessionStartSession, EndSession
SubscriptionStartSubscription, SubStartSession, PlanStartSession
PlanCreatePlan, UpdatePlanStatus, LinkNode, UnlinkNode
ProviderRegisterProvider, UpdateProviderDetails, UpdateProviderStatus
LeaseStartLease, EndLease
BankSend
Fee GrantGrantFeeAllowance, RevokeFeeAllowance

Security

FeatureDescription
Kill switchFirewall rules block all traffic outside the VPN tunnel
DNS leak preventionOverrides system DNS to prevent queries outside the tunnel
TOFU TLSPins node TLS certificates on first contact; alerts on change
On-chain sessionsSession start/end recorded on the Sentinel blockchain
Key disposalIDisposable ensures wallet key material is zeroed on cleanup
No accountsWallet-based authentication only. No servers, no sign-ups
No external dependenciesConnects directly to decentralized nodes. No relay servers
Credential storeEncrypted persistence for sensitive configuration

Sentinel Chain v3

The SDK targets Sentinel chain v3. Key differences from v2:

  • Nodes use service_type (not type) and remote_addrs array (not remote_url string)
  • Sessions are wrapped in base_session
  • Active node status is status=1 (not STATUS_ACTIVE)
  • Provider queries remain on v2 (/sentinel/provider/v2/)
  • Token: P2P (chain denom: udvpn, 1 P2P = 1,000,000 udvpn)

LCD failover endpoints (rotated automatically):

  1. https://lcd.sentinel.co
  2. https://api.sentinel.quokkastake.io
  3. https://sentinel-api.polkachu.com
  4. https://sentinel.api.trivium.network:1317
PropertyValue
Chain IDsentinelhub-2
Denomudvpn (1 P2P = 1,000,000 udvpn)
HD Pathm/44'/118'/0'/0/0
Bech32sent1 (account), sentnode1 (node), sentprov1 (provider)
Gas Price0.2 udvpn per gas unit

Dependencies

PackagePurpose
NBitcoinBIP39, BIP44, secp256k1, Bech32
Google.ProtobufProtobuf message encoding
NSec.CryptographyX25519 (Curve25519) for WireGuard key generation

Building and Testing

814+ tests across 33 test classes covering wallet operations, chain queries, transaction building, message encoding, handshake protocol, V2Ray configuration, WireGuard tunnels, error handling, session management, and live mainnet integration.

dotnet build
dotnet test

Documentation

  • Quick Start -- Get running in under 50 lines
  • API Reference -- Complete public API catalog
  • Edge Cases -- Gotchas and production lessons learned
  • Protocol specs: V3-HANDSHAKE-SPEC, V2RAY-CONFIG-SPEC, WIREGUARD-CONFIG-SPEC, LCD-API-REFERENCE (see sentinel-proto/ and SDK docs)

License

MIT

About

C# / .NET 8 SDK for Sentinel dVPN — WireGuard + V2Ray tunnels, Cosmos blockchain, 814 tests. Includes a full WPF desktop client example.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages