Portaldot Hacker House 2026 | Portal Meter: pay for any API one call at a time on Portaldot V3

Track: Modular Cloud & Middleware

Project Introduction

Portal Meter lets any API charge per call on Portaldot V3. A caller opens a prepaid session once, then pays each request with a signed voucher over HTTP: no transaction per call. The seller settles many requests in one Ethereum transaction that moves the money in Solidity (pallet-revive) and writes the public record in ink! (pallet-contracts), together or not at all. An MIT package plus a hosted seller.

Try it, no wallet: open the live page Portal Meter · live on Portaldot V3 testnet and press Buy one request. You get HTTP 402 with a 0.01 pUSD quote, a voucher signed in your browser, then HTTP 200 with the data. Then press Replay the session log against the chain.

Problem Solved

Paying on-chain for each request does not work on this chain. We measured it with our own keys: one paid request locked 7.53 tPOT of storage deposit for good (blocks 276657 to 276660), far more than a one-cent call is worth. So we built prepaid sessions. A session of 100 requests locked 7.6 tPOT in total and was settled in one transaction (block 282559). Test tokens have no value; the ratio is the point.

How cost scales (tPOT, storage deposit plus transaction fees; “measured” = read from the chain, the rest is computed from those measurements):

Requests Escrow: txs Escrow: tPOT Session: txs Session: tPOT Session, per request
1 2 7.53 measured 3 7.56 7.56
10 20 75.3 3 7.56 0.76
100 200 753 3 7.56 measured 0.076
1,000 2,000 7,530 3 7.56 0.0076

A session costs 3 transactions: open, one settlement batch, close. The batch redeems only the latest voucher, so its cost does not grow with the number of requests. From the chain: open holds 11.52 tPOT (block 282490), close returns 7.68 (block 297818), each batch writes one 3.63 tPOT ink! anchor per session; fees are 0.01 to 0.05 per step. Each extra batch adds about 3.68 tPOT, so 1,000 requests settled in 4 batches cost 18.6 tPOT (0.019 per request). The seller picks the batching rule: ours settles once 25 requests wait or 6 hours after the last one, at most every 30 minutes. For a single request, escrow is as cheap as a session; sessions win from the second request on. Raw data: https://portal-meter.swiftbotlab.workers.dev/deployments/proof/session-measure.json

Link

Live Web / Demo Video (choose one): live page Portal Meter · live on Portaldot V3 testnet and the 2:23 video https://youtu.be/sgGdQ-WLum0
GitHub: GitHub - swiftbotlabs/portal-meter: Pay-per-request metering on Portaldot, settled on-chain. · GitHub
Pitch Deck: https://portal-meter.swiftbotlab.workers.dev/pitch/portal-meter-deck.pdf
DoraHacks BUIDL: Portal Meter | Buidls | DoraHacks
The 137-request batch, both VMs in one extrinsic: Portaldot Blcok Explorer

Check us from a terminal, no key, one command (replays a real session’s log against the Redeemed event and the ink! anchor and prints ACCEPT; about 90 seconds on an empty npm cache, mostly the install):

npx -y --package=https://portal-meter.swiftbotlab.workers.dev/source/portal-meter-0.1.0.tgz portal-meter session-verify https://portal-meter.swiftbotlab.workers.dev --id 0xbf59f966153d082007c9a1b36c6361dc1365adc1522c71badc1c6d0f7f1778ab --provider 0xE13A4d566A1f6492C1511EF100DC0417ccE18E59 --endpoint 3

Or see the price yourself: curl -i https://portal-meter.swiftbotlab.workers.dev/v1/asset/7777 answers HTTP 402 with the price quote.

Technical Highlights

  1. One Ethereum transaction settles many sessions across both VMs. It calls the runtime pallets address with utility.batchAll([revive.call(redeem), contracts.call(record), ...]). Block 282559 settled 137 requests from 3 sessions this way.
  2. The batch is the buyer’s signature, not the seller’s word. Each voucher commits to the previous response (head[n] = keccak256(head[n-1], request[n], response[n-1])), so an edited, cut or reordered log no longer reaches the payer-signed head.
  3. Native assets as ERC-20s. Payment is pUSD (asset 7777) through the pallet-assets precompile.
  4. The contracts refuse cheating. 22 of 22 bad vouchers and dry-runs are refused by the live seller and contract, 14 of 14 on the escrow path (node scripts/negative-checks-sessions.mjs, no key needed).
  5. Source matches the chain. Bytematch, another Hacker House team’s verifier, lists all 3 Solidity contracts we deployed as byte-for-byte matches.

Contracts: MeterSession 0xCc2aBc8AC1B5676e8f9678bb5B6881A0b743B3d5, MeterSettlement 0x9E7Ad2Aa754A0EBA70CFbd1db01d25ef97e5781e, MeterRegistry (ink!) 5DHgN8JZRpyo9mDaG1BSNh224AZXcQw8p3Y8GZK1K2Vd8Ku4.

Team

Swift Bot Labs, a small studio building payment tools.
GitHub: swiftbotlabs
Email: swiftbotlabs@gmail.com

Judges & Voting Fit

For Judges: every claim has a block number. Buy a call on the live page, replay it against both VMs in one command, and read the cost of 1 to 1,000 requests from the chain.

The four criteria:

  • Technical feasibility. Three contracts live on the V3 testnet. 123 tests: 42 Solidity (unit, fuzz, invariant), 8 ink!, 73 Node. The hosted seller has settled 257 requests in 8 transactions (live count at /health), and its cron settles without us (block 282470). More than 60 commits since 1 Nov.
  • Innovation. Money in Solidity and the record in ink!, atomic in one Ethereum transaction: a single-VM chain would need a bridge or a second transaction. The design was driven by a measured Portaldot cost (storage deposits), not copied from another chain.
  • Ecosystem contribution. Any Portaldot API can charge per call with a few lines on Node.js, Cloudflare Workers, Bun or Deno, and one command registers an endpoint on both VMs. We proved reuse with a second seller built only on the package’s public API (endpoint 4, settled by its own alarm in block 327272). We also publish our Portaldot V3 notes and a SCALE encoder that needs no polkadot.js.
  • Business potential. Users: data and API providers on Portaldot (indexers, RPC, analytics, AI tool endpoints) and the apps and agents calling them. Who pays what: the caller pays the API’s price per request (here 0.01 pUSD) and the session’s deposit, two thirds of it returned at close; the provider pays the anchor deposit and fee per batch. Fee model (planned, not in the testnet contracts): a small protocol fee taken at settlement, inside the batch the provider already sends, plus the hosted seller as a paid service for providers who don’t want to run one.

Objections, answered:

  • No outside users yet? True. The 257 settled requests came from our own keys, our own example and visitors pressing the demo button, which uses one shared test key. No outside provider, no revenue, nothing on mainnet. What we’re doing: we will wire Portal Meter into one other team’s public API for free during judging. If you run one, reply here.
  • Why do two endpoints point to 127.0.0.1? Endpoints 1 and 2 were listed by our escrow test run against a seller on our own machine (blocks 276612 and 276613). Changing them needs a new on-chain transaction, which the code freeze rules out. The live page now labels them “local test endpoint, not reachable”. The public sellers are endpoints 3 and 4.
  • 2 or 0 transactions per request? Two columns of one table: escrow needs 2 per request (pay, settle), a session needs none per request and 3 per session. The page now shows that in separate rows, and the table above shows how it scales.
  • 100% scores with 0 confirmations? The ink! score is (served − disputed) / (served + refunded) (reputation in meter_registry/lib.rs), so a provider’s own served count showed 100% before any payer had rated it. The page now shows “—, no confirmations yet” until a payer confirms. Only endpoint 1 has a confirmation (block 276665).
  • What does it show that other entries don’t? Not more tests: some rivals have far more. A paid call you make yourself in a browser with no wallet, settled with Solidity and ink! in one transaction, which you can replay against both VMs in one command.

The page fixes above (7 Nov) change display only: no contract, seller or on-chain change.

For Community Voters: open the live page, press “Buy one request”, and get real data back with no wallet and no transaction per call. That is how apps and AI agents on Portaldot could pay for APIs.