A full-stack, decentralised license verification system built on Solana. Issuers mint tamper-proof, on-chain licenses tied to off-chain assets; anyone can verify them in seconds without trusting a central authority.
- Overview
- Architecture & Monorepo Structure
- Smart Contract (
contract/) - REST API (
api/) - Web Frontend (
web/) - Getting Started
- API Reference
- Tech Stack
- Contributing
- License
Veryfy solves the problem of digital license forgery. Traditional licensing platforms store license data in centralised databases — which can be manipulated, lost, or taken offline. Veryfy records every license directly on the Solana blockchain, making each one:
- Immutable — once issued, the record cannot be silently altered.
- Publicly verifiable — anyone with a license identifier can confirm its validity without contacting the issuer.
- Permissioned — only registered issuers can create or revoke licenses; revocation is also recorded on-chain.
Built with Anchor 0.32.1 on Solana. The program ID is:
F2NmTxchnwJJTbCLCAkFa3c8RYXE8PL5ToZwoao8jvD3
| Account | Seeds | Fields |
|---|---|---|
Issuer |
["issuer", authority_pubkey] |
authority, name (≤64 chars), issued_count, bump |
License |
["license", asset_hash] |
holder, issuer, status, expiry, asset_hash, bump |
register_issuer()
│
▼
[Issuer PDA]
│
issue_license()
│
▼
Active ──── revoke_license() ──▶ Revoked
│
(expiry timestamp reached)
│
▼
Expired
| Instruction | Signer | Description |
|---|---|---|
register_issuer(name) |
Payer | Creates an Issuer PDA for the calling wallet |
issue_license(asset_hash, expiry) |
Payer (authority) | Mints a License PDA linked to a 32-byte asset hash; expiry = 0 means never expires |
revoke_license(asset_hash) |
Authority | Marks an existing license as Revoked; only the original issuing authority may call this |
renew_license |
Authority | (In development) Extends the expiry of an existing license |
| Event | Emitted When |
|---|---|
LicenseIssued |
A new license is successfully created |
| Code | Message | Trigger |
|---|---|---|
UnauthorizedIssuer |
Unauthorized issuer | Signer does not match the authority stored on the Issuer account |
MathOverflow |
Math overflow | issued_count arithmetic would overflow |
NotImplemented |
Feature not yet implemented | Stub instruction placeholders |
A lightweight Go HTTP server with no external framework dependencies. It provides a JSON bridge for clients that cannot interact directly with Solana RPC.
Module: github.com/odingaval/veryfy/api
Go version: 1.26+
- Recover — catches panics and returns
500with structured JSON. - RequestLogger — structured
slogrequest/response logging. - CORS — configurable allowed origins.
- Timeout — per-request deadline enforcement.
| Service | Responsibility |
|---|---|
HashService |
Deterministic SHA-256 hashing of asset content / URLs to produce the 32-byte asset_hash |
LicenseService |
Issue, verify, and revoke licenses; delegates to repository |
IssuerService |
Register issuers; delegates to repository |
MemoryRepository provides a thread-safe, in-memory store suitable for development and testing. It can be replaced by a database-backed implementation without changing the service or handler layers (interface-driven design).
A React 18 + Vite 6 single-page application styled with Tailwind CSS v4 and shadcn/ui (Radix UI primitives).
| Route (in-app state) | Component | Purpose |
|---|---|---|
landing |
Landing.tsx |
Hero section, feature overview, navigation CTAs |
issue |
IssuerDashboard.tsx |
Connect wallet, upload asset, issue / revoke on-chain licenses |
verify |
PublicVerify.tsx |
Paste a license ID or asset hash; fetches and displays on-chain status |
| Package | Purpose |
|---|---|
@coral-xyz/anchor ^0.32.1 |
Type-safe Anchor client for on-chain instruction calls |
@solana/wallet-adapter-* |
Multi-wallet connection (Phantom, Solflare, etc.) |
@solana/web3.js ^1.98 |
Core Solana RPC interactions |
react-router 7 |
Client-side navigation |
recharts |
Analytics charts in the Issuer Dashboard |
sonner |
Toast notifications |
motion |
Framer-Motion-compatible animations |
lucide-react |
Icon library |
| Tool | Version | Install |
|---|---|---|
| Rust | stable | rustup install stable |
| Solana CLI | ≥ 1.18 | docs.solana.com/cli/install |
| Anchor CLI | 0.32.1 | cargo install --git https://github.com/coral-xyz/anchor avm --locked && avm install 0.32.1 |
| Go | ≥ 1.26 | go.dev/dl |
| Node.js | ≥ 20 | nvm install 20 |
| pnpm | ≥ 9 | npm i -g pnpm |
cd contract
# 1. Start a local validator
solana-test-validator --reset &
# 2. Set Solana CLI to localnet
solana config set --url localhost
# 3. Build the Anchor program
anchor build
# 4. Deploy to localnet
anchor deploy
# 5. Run integration tests
anchor test --skip-local-validatorcd api
# Copy and edit environment config (see internal/config for supported vars)
cp .env.example .env # or set env vars directly
# Run the server
go run ./cmd/server
# Default: listens on :8080
# Health check:
curl http://localhost:8080/healthEnvironment Variables
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP listen port |
ALLOWED_ORIGINS |
* |
Comma-separated CORS origins |
REQUEST_TIMEOUT |
30s |
Per-request deadline |
cd web
# Install dependencies
pnpm install
# Start the dev server
pnpm dev
# → http://localhost:5173To build for production:
pnpm buildAll responses use the envelope { "data": ... } on success and { "error": { "code": "...", "message": "..." } } on failure.
Returns server uptime and readiness status.
{
"data": {
"status": "ok",
"service": "veryfy-api",
"uptimeSec": 42
}
}Register a new issuer.
Request
{ "name": "Acme Corp", "authority": "<solana-pubkey>" }Issue a new license for an asset.
Request
{
"assetUrl": "https://example.com/asset.pdf",
"holderAddress": "<solana-pubkey>",
"expiryTimestamp": 1893456000
}Verify whether a license is active.
Request
{ "assetHash": "<hex-encoded-32-byte-hash>" }Revoke an existing license.
Request
{ "assetHash": "<hex-encoded-32-byte-hash>", "authority": "<solana-pubkey>" }| Layer | Technology |
|---|---|
| Blockchain | Solana |
| Smart Contract | Rust · Anchor 0.32.1 |
| Backend API | Go 1.26 · net/http |
| Frontend | React 18 · TypeScript · Vite 6 |
| Styling | Tailwind CSS v4 · shadcn/ui · Radix UI |
| Wallet | Solana Wallet Adapter |
| State Management | React useState / custom hooks |
| Testing | Mocha (contract) · Go testing package (API) |
- Fork the repository and create a feature branch:
git checkout -b feat/your-feature. - Follow the existing code style —
rustfmtfor Rust,gofmtfor Go, ESLint/Prettier for TypeScript. - Add or update tests for any new behaviour.
- Open a pull request with a clear description of the change.
This project is MIT licensed. See LICENSE for details.