Proof‑of‑Knowledge (PoK)
Proof‑of‑Knowledge (PoK) — Technical Specification
Version: 1.0.0 Solidity: ^0.8.20
Overview
PoK rewards users for proving the execution/result of tasks (e.g., learning/AI). Token issuance is orchestrated by PoKMinter
, which validates a proof
using a verifier (IVerifier
).
Core contracts:
PoKMinter
— contracts/src/minters/PoKMinter.solIVerifier
— contracts/src/interfaces/IVerifier.solECDSAVerifier
— contracts/src/verifiers/ECDSAVerifier.sol
IVerifier
Generic interface for PoK/AI verifiers.
function verify(address recipient, uint256 amount, bytes calldata proof, bytes32 nonce) external view returns (bool ok);
function trustedSigner() external view returns (address); // specific to ECDSA
function setTrustedSigner(address newSigner) external; // admin only
function domainSeparator() external view returns (bytes32); // EIP-712 when applicable
function buildMessageHash(address recipient, uint256 amount, bytes32 nonce, uint256 expiry) external view returns (bytes32);
verify
SHOULD revert on invalid proofs. Thebool
return value is auxiliary.nonce
prevents replay.expiry
is part of the payload (see ECDSA below).
ECDSAVerifier
Implementation based on EIP‑712 + ECDSA.
Domain:
EIP712("NeuronsPoK", "1")
Typehash:
MintProof(address recipient,uint256 amount,bytes32 nonce,uint256 expiry)
verify(...)
:Decode
proof
as(bytes signature, uint256 expiry)
Check
expiry > block.timestamp
Build
structHash
with the fieldsCompute
messageHash = _hashTypedDataV4(structHash)
recover(signature)
and compare totrustedSigner
Admin:
setTrustedSigner(address)
(Ownable)
PoKMinter
Orchestrates validation and calls token.mint(to, amount)
.
State/limits:
nonceUsed[bytes32]
— prevents replayPer-user rate limiting:
minCooldown
(default: 1 hour)maxDailyMint
(default: 1000e18)maxSingleMint
(default: 100e18)
Stats:
totalMintsProcessed
,totalTokensMinted
Events:
TokenSet(address token)
VerifierSet(address verifier)
MintedWithProof(address to, uint256 amount, bytes32 nonce)
LimitsUpdated(uint256 minCooldown, uint256 maxDailyMint, uint256 maxSingleMint)
Flow mintWithProof(to, amount, proof, nonce)
:
Pre-checks: token/verifier set,
to != 0
,amount > 0
, within limitsCheck cooldown and daily window
verifier.verify(...)
must returntrue
(or revert)Mark
nonceUsed[nonce] = true
Update rate/daily trackers
token.mint(to, amount)
(requiresMINTER_ROLE
on token)Update stats and emit event
batchMintWithProofs(...)
:
Processes a list; skips invalid entries without reverting the batch
Admin:
setToken(address)
,setVerifier(address)
setLimits(minCooldown, maxDailyMint, maxSingleMint)
pause()
/unpause()
Errors (via Errors.sol
):
ZeroAddress()
,InvalidAmount()
,ArrayLengthMismatch()
InvalidProof()
,ProofExpired()
,InvalidSignature()
CooldownNotMet()
,DailyLimitExceeded()
,SingleMintLimitExceeded()
End-to-end integration
Backend/Orchestrator:
Build EIP‑712 payload and sign with
trustedSigner
Send
mintWithProof(to, amount, abi.encode(signature, expiry), nonce)
On-chain:
ECDSAVerifier
validates signature and expirationPoKMinter
enforces limits and callstoken.mint
Security and compliance
PoKMinter
must holdMINTER_ROLE
on the token.Rotate
trustedSigner
per policy.Anti-replay protections via
nonce
andexpiry
.Monitor on-chain issuance metrics.
Last updated
Was this helpful?