Skip to content

SmartNet App SDK ​

The SmartNet App SDK is the surface that a dApp uses to talk to the SmartNet Rust core — wallet, payments, storage. Every method is an asynchronous IPC call that (for state-changing operations) prompts the user for confirmation via a native GUI dialog.

Prerequisite

Read the SmartNet Overview first — it explains the IPC security model and why the dApp never sees the user's private keys.

Detecting SmartNet ​

The Tauri core injects window.smartholdem into every dApp WebView. Fall back gracefully when running in a regular browser:

javascript
if (window.smartholdem) {
  // Full SmartNet SDK available
} else {
  // Regular browser — fall back to WalletConnect or ask the user to open in SmartNet
}

Optionally, install the ergonomic wrapper package for Vue 3 composables:

bash
yarn add @smartholdem/smartnet-sdk

Core Hooks (Vue 3 Composition API) ​

useSmartNetWallet() ​

Access user identity, live balance, and request signatures.

typescript
{
  address: Ref<string>,          // user's public address
  balance: Ref<bigint>,          // in smarthoshi (1 STH = 10^8)
  publicKey: Ref<string>,
  signTransaction: (payload) => Promise<SignedTx>,
  signMessage: (msg: string) => Promise<{ signature, publicKey }>
}
vue
<script setup>
import { useSmartNetWallet } from '@smartholdem/smartnet-sdk'

const { address, balance, signTransaction } = useSmartNetWallet()

const sendSTH = async (to, amount) => {
  const tx = await signTransaction({ recipientId: to, amount })
  // → broadcast via @smartholdem/client
}
</script>

usePayments() ​

Handles in-app purchases, subscriptions, and paid messages — all settled in STH on the SmartHoldem blockchain.

typescript
{
  createPayment: (opts) => Promise<Receipt>,      // one-off IAP
  verifyPayment: (txId) => Promise<boolean>,       // check status
  getSubscriptions: () => Promise<Subscription[]>, // active recurring
  sendPaidMessage: (opts) => Promise<Receipt>      // paid inbox (anti-spam)
}
vue
<script setup>
import { usePayments } from '@smartholdem/smartnet-sdk'

const { createPayment, sendPaidMessage } = usePayments()

const unlockPremium = () =>
  createPayment({ amount: 100_000_000, vendorField: 'premium_access' })

const contactExpert = (expertAddress, body) =>
  sendPaidMessage({ to: expertAddress, body, fee: 1_000_000 })
</script>

useStorage() ​

Persistent key-value store scoped to your dApp. Data lives inside the user's local sled database sealed with AES-GCM — the host filesystem is never touched.

typescript
{
  get: (key: string) => Promise<any>,
  set: (key: string, value: any) => Promise<void>,
  remove: (key: string) => Promise<void>,
  clear: () => Promise<void>
}
vue
<script setup>
import { useStorage } from '@smartholdem/smartnet-sdk'

const { get, set } = useStorage()

await set('user_preferences', { theme: 'dark', lang: 'en' })
const prefs = await get('user_preferences')
</script>

Raw window.smartholdem API ​

For React, Svelte, or plain JavaScript dApps that don't use Vue composables.

signMessage(message) — Full Example ​

Sign an arbitrary string with the user's key. The Rust core displays a native confirmation dialog with the raw payload before producing the signature; the dApp never receives the private key.

vue
<template>
  <div>
    <input v-model="message" placeholder="Message to sign" />
    <button :disabled="loading" @click="signWithSmartNet">Sign with SmartNet</button>

    <div v-if="result">
      <p><strong>Signature:</strong> <code>{{ result.signature }}</code></p>
      <p><strong>Public key:</strong> <code>{{ result.publicKey }}</code></p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const message = ref('Hello SmartNet — sign this for me')
const loading = ref(false)
const result  = ref(null)

const signWithSmartNet = async () => {
  if (!window.smartholdem) {
    alert('This action requires the SmartNet client')
    return
  }
  loading.value = true
  try {
    // Native GUI dialog appears here — the user must approve
    result.value = await window.smartholdem.signMessage(message.value)
  } catch (e) {
    // Rejection is a normal outcome, not an exception in the runtime sense
    console.error('User rejected signature:', e)
  } finally {
    loading.value = false
  }
}
</script>

sendTransaction(payload) ​

Broadcast a pre-built transaction payload. Native confirmation dialog appears before signing & broadcasting.

javascript
const { transactionId } = await window.smartholdem.sendTransaction({
  type: 0,
  amount: '100000000',                                   // 1 STH
  recipientId: 'Sg6epK4DXVKVZ2t57kndUZjtjkS2eCYUZ1',
  fee: '10000000'
})

getBalance() ​

Read the wallet's current balance and nonce.

javascript
const { balance, nonce } = await window.smartholdem.getBalance()
console.log(`Balance: ${Number(balance) / 1e8} STH · nonce: ${nonce}`)

React Example ​

jsx
import { useEffect, useState } from 'react'

export default function SmartNetGate() {
  const [balance, setBalance] = useState(0)

  useEffect(() => {
    if (window.smartholdem) {
      window.smartholdem.getBalance().then(({ balance }) => {
        setBalance(Number(balance) / 1e8)
      })
    }
  }, [])

  return <div>Balance: {balance} STH</div>
}

Cheat Sheet ​

TaskAPI
Detect environment!!window.smartholdem
Read address / balance / nonceuseSmartNetWallet() · getBalance()
Sign an off-chain messagesignMessage(msg)
Sign & broadcast a transactionsignTransaction(payload) → client SDK broadcast
Send a fully-built transactionsendTransaction(payload)
One-off payment (IAP)usePayments().createPayment()
Paid inbox messageusePayments().sendPaidMessage()
Store dApp state locallyuseStorage().set(k, v)

Next ​

Code is the Law. Zero Infrastructure. Absolute Autonomy.