Proofkit SDK for building and publishing PoVal p1 notes
npm install @axiomatic_oracle/proofkitTypeScript/JavaScript SDK for building and publishing p1 Proof-of-Valuation (PoVal) attestations on Algorand for Axiomatic Oracle.
It focuses on:
1. Building canonical, deterministic p1 payloads (JCS/ACJ-style JSON).
2. Anchoring them on-chain as the note of a 0-ALGO self-transaction.
3. Keeping signing and key management fully client-side.
4. Remaining interoperable with independent verifiers (Node + Python).
This package is ESM-first and works with Node.js (18+) and modern browsers.
---
@axiomatic_oracle/proofkit if you:
p1 payloads aligned with the Python SDKs.
@axiomatic_oracle/verifier (Node) or axiomatic_verifier (Python).
v and interval u for a property.
p1 attestation via ProofKit.
p1 notes and verify them independently.
bash
npm install @axiomatic_oracle/proofkit algosdk
`
Requirements:
* Node.js 18+ (or a browser with fetch, TextEncoder, crypto.subtle).
* algosdk is required by your app (listed as a dependency).
---
p1 structure
buildP1 returns an object of the form:
`ts
export type P1 = {
s: "p1"; // schema marker
a: string; // asset tag (e.g. "re:EUR")
mv: string; // model version
mh: string; // model hash (hex, optional)
ih: string; // input hash (hex, required)
v: number; // point estimate (e.g. value)
u: [number, number]; // uncertainty range [low, high]
ts: number; // unix epoch seconds
};
`
The object is normalized and serialized using a JCS/ACJ-style canonical JSON
encoder for stable hashing and cross-language parity.
---
Quickstart (Node.js): build and publish a p1
Example using a local mnemonic on TestNet (demo only).
`ts
import "dotenv/config";
import algosdk from "algosdk";
import {
buildP1,
publishP1,
buildCanonicalInput,
computeInputHash,
} from "@axiomatic_oracle/proofkit";
async function main() {
const mnemonic = process.env.ALGORAND_MNEMONIC || "";
const network = (process.env.ALGORAND_NETWORK || "testnet").trim();
if (!mnemonic) {
throw new Error("Missing ALGORAND_MNEMONIC");
}
const { sk, addr } = algosdk.mnemonicToSecretKey(mnemonic);
const from = addr.toString();
// 1) Optional: derive a canonical input hash from your raw input
const rawInput = {
property_id: "demo-123",
country: "IT",
value_hint: 550000,
};
const allowedKeys = Object.keys(rawInput);
const canonicalInput = buildCanonicalInput(rawInput, allowedKeys);
const inputHashHex = await computeInputHash(canonicalInput, allowedKeys);
// 2) Build a p1 attestation
const p1 = buildP1({
assetTag: "re:EUR",
modelVersion: "v2",
modelHashHex: "",
inputHashHex,
valueEUR: 550000,
uncertaintyLowEUR: 520000,
uncertaintyHighEUR: 580000,
// timestampEpochSec optional (defaults to now)
});
// 3) Signer: you control the keys. ProofKit only passes bytes to sign.
const sign = async (unsignedBytes: Uint8Array): Promise => {
const tx = algosdk.decodeUnsignedTransaction(unsignedBytes);
const { blob } = algosdk.signTransaction(tx, sk);
return blob; // msgpack-encoded SignedTransaction
};
// 4) Publish as a 0-ALGO self-transaction with canonical note
const res = await publishP1({
p1,
from,
sign,
network, // "testnet" or "mainnet"
// optional: custom algod via algod
// optional: Pera in browser via pera
});
console.log("P1 published:", res);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
`
This will:
1. Build a canonical p1.
2. Create a 0-ALGO self-payment with the p1 note.
3. Sign using your function or Pera.
4. Submit via Algonode by default.
5. Return { txid, explorerUrl }.
---
Publish → verify (end-to-end)
To verify a published p1 attestation from Node, use
@axiomatic_oracle/verifier:
`ts
import { verifyTx } from "@axiomatic_oracle/verifier";
const res = await verifyTx({
txid: "YOUR_TXID",
network: "testnet",
maxSkewPastSec: 3600,
maxSkewFutureSec: 300,
});
console.log(res.verified, res.reason);
`
This checks that:
* the note is structurally valid,
* canonicalization and sha256 match,
* the timestamp ts is inside your time window.
---
API surface
From @axiomatic_oracle/proofkit:
* buildP1(options) → P1
* canonicalNoteBytesP1(p1) → { bytes, sha256, size }
* assertNoteSizeOK(p1, maxBytes?)
* buildCanonicalInput(record, allowedKeys, stripNone?)
* computeInputHash(record, allowedKeys) → sha256 (JCS-style)
* publishP1(options) → { txid, explorerUrl }
* NOTE_MAX_BYTES
* DEFAULT_ASSET_TAG
* Types: P1, BuildP1Opts, PublishOpts, Network
$3
publishP1 is intentionally minimal:
`ts
export type PublishOpts = {
p1: P1;
network?: "testnet" | "mainnet";
algod?: any; // custom Algodv2 client (optional)
pera?: any; // PeraWallet instance in browser (optional)
from?: string;
sign?: (unsignedBytes: Uint8Array) => Promise;
waitRounds?: number;
};
`
You must provide either:
* pera: in-browser signing flow, or
* sign: a function that receives unsigned tx bytes and returns signed tx bytes.
This keeps all key management under your control.
---
Relationship with other SDKs
* Use @axiomatic_oracle/proofkit to build and publish p1 attestations.
* Use @axiomatic_oracle/verifier (Node) or axiomatic_verifier` (Python) to