Skip to main content

MachinePay Edge

Type: IoT machine-economy gateway
Audience: IoT developers, mesh network operators, renewable energy traders, compute rental platforms

MachinePay Edge turns any device into a pay-per-use service — Wi-Fi hotspot, solar inverter, GPU compute node, or bandwidth relay. Micro-payments flow over Omnia channels. Policy enforces minimum price per unit, maximum unpaid usage, and auto-shutdown when credit runs out.


Packages used

PackageRole in MachinePay Edge
@totemsdk/omniaOff-chain payment channels for micro-payment streams
@totemsdk/omnia-hyperswarmPeer-to-peer connectivity for device clients
@totemsdk/statechainOff-chain ownership of prepaid service tokens
@totemsdk/agent-policyMin price, max unpaid usage, auto-shutdown enforcement
@totemsdk/pearPear runtime for edge device deployment
@totemsdk/wots-leaseWOTS key lifecycle for device signing
@totemsdk/txpowTxPoW calibration for on-chain settlement triggers
@totemsdk/lookup-clientResolves client wallets from the lookup network

Core integration path

1. Initialise the edge device

import { createPearRuntime } from '@totemsdk/pear';
import { HyperswarmTransport } from '@totemsdk/omnia-hyperswarm';

const pear = await createPearRuntime({
appId: `machinepay-edge:${DEVICE_ID}`,
storage: './device-data',
});

const transport = new HyperswarmTransport({ swarm: pear.swarm });

// Advertise this device on the lookup network
await lookupClient.announce({
address: DEVICE_WALLET_ADDRESS,
publicKey: DEVICE_PUBLIC_KEY,
serviceType: 'wifi-hotspot',
pricePerMB: 100n, // 100 satoshis per MB
});

2. MachinePay policy

import type { AgentPolicy, AgentProposal } from '@totemsdk/agent-policy';

const MIN_PRICE_PER_MB_SATOSHIS = 50n; // Floor price
const MAX_UNPAID_MB = 5; // Grace buffer before shutdown

const machinePolicy: AgentPolicy = {
async evaluate(proposal: AgentProposal) {
const { intent } = proposal;

// New client connecting — check their prepaid credit
if (intent.type === 'service_access') {
const prepaidCredit = await getClientCredit(intent.clientAddress);
if (prepaidCredit <= 0n) {
return { outcome: 'rejected', reason: 'No prepaid credit — top up your channel first' };
}
}

// Usage tick — enforce min price and unpaid buffer
if (intent.type === 'usage_tick') {
const offeredPrice = BigInt(intent.pricePerUnit);
if (offeredPrice < MIN_PRICE_PER_MB_SATOSHIS) {
return { outcome: 'rejected', reason: `Price ${offeredPrice} is below floor ${MIN_PRICE_PER_MB_SATOSHIS}` };
}

const unpaidUsage = await getUnpaidUsage(intent.clientAddress);
if (unpaidUsage >= MAX_UNPAID_MB) {
return {
outcome: 'rejected',
reason: `Max unpaid buffer (${MAX_UNPAID_MB} MB) reached — service suspended`,
};
}
}

// Manual override — auto-shutdown
if (intent.type === 'auto_shutdown') {
return {
outcome: 'requires_human',
prompt: 'Auto-shutdown triggered by policy. Confirm service suspension?',
};
}

return { outcome: 'approved', receipt: buildReceipt(proposal, `machine-policy:${DEVICE_ID}`) };
},
};

3. Micro-payment stream over a channel

import { openChannel, updateChannel } from '@totemsdk/omnia';

// Client opens a channel to the device
const channel = await openChannel({
counterpartyKey: DEVICE_PUBLIC_KEY,
localAmount: 10_000_000n, // 10 MIN prepaid
remoteAmount: 0n,
transport,
chainProvider,
wotsLease: clientSigner,
});

// Every MB consumed triggers a channel update
device.on('mb_consumed', async ({ clientAddress, mb }) => {
const proposal = buildProposal('usage_tick', {
clientAddress,
pricePerUnit: String(100n), // 100 sat/MB
units: mb,
});

const decision = await machinePolicy.evaluate(proposal);
if (decision.outcome !== 'approved') {
return device.suspend(clientAddress, decision.reason ?? 'policy_block');
}

await updateChannel(channel, { localDelta: -(100n * BigInt(mb)) });
});

4. Statechain prepaid pass

import { createStatechain, verifyStatechain } from '@totemsdk/statechain';

// Issuer creates a 1-hour Wi-Fi pass as a statechain asset
const wifiPass = await createStatechain({
assetId: `wifi:${DEVICE_ID}:${Date.now()}`,
issuer: DEVICE_WALLET_ADDRESS,
recipient: clientAddress,
metadata: { durationMs: 3_600_000, maxMB: 500 },
signer: deviceSigner,
});

// Client presents the pass — device verifies without an on-chain call
const valid = await verifyStatechain(wifiPass, {
expectedIssuer: DEVICE_WALLET_ADDRESS,
currentHolder: clientAddress,
checkExpiry: true,
});

if (valid) device.grantAccess(clientAddress);

Future QVAC hook

Future QVAC hook

A QVAC agent can adjust pricing dynamically based on demand (surge pricing during events, discounts at off-peak hours), automatically provision new devices into the lookup network when adding capacity, and aggregate multi-device revenue into a cooperative pool — all as proposals through machinePolicy. The device never exposes its signing keys to the agent.