Lewati ke konten utama

Changelog

All notable changes to the PAY.ID ecosystem across packages, contracts, and frontend.


May 2026

✨ New Features

1. V4 Dashboard Redesign (Inspired)

The entire V4 app UI has been redesigned with a clean, card-based layout inspired by modern fintech apps (concept). Changes span across 5 components:

  • Dashboard (frontend/example-product/src/components/v4/Dashboard.tsx)

    • Stealth Balance Card — gradient green (#00D084) with prominent USD display, QR button
    • Token List — ETH, USDC, PDT with individual balance items
    • Demo Token Banner — green info card: "We've sent you this to experience how seamless PAY.ID withdrawals are"
    • Your Personal Link — PayID card with avatar, copy/QR/share actions
    • Quick Actions — Send, Receive, History with rounded-2xl icon buttons
    • Activity Feed — tab filters (All / Incoming / Outgoing), Export CSV button, avatar per transaction
  • ReceivePage (frontend/example-product/src/components/v4/ReceivePage.tsx)

    • QR Card — gradient green with centered QR code
    • PayID Card — copyable link with avatar and action buttons
    • Wallet Address — expandable section with ChevronRight
  • HistoryPage (frontend/example-product/src/components/v4/HistoryPage.tsx)

    • Summary Cards — gradient red (Sent) & green (Received) with rounded-[20px]
    • Search Bar — input with Search icon
    • Tab Filters — All / Incoming / Outgoing
    • Transaction List — Avatar + detail + status badge + amount
  • SettingsPage (frontend/example-product/src/components/v4/SettingsPage.tsx)

    • Profile Card — gradient green with avatar besar dan PayID
    • Theme Toggle — modern switch
    • Settings List — color-coded icons (blue, yellow, green, purple)
    • Disconnect — red card with warning style
  • AppLayout (frontend/example-product/src/components/v4/AppLayout.tsx)

    • Logo — "pay.id" dengan BETA badge
    • Nav Items — rounded-xl active state, clean spacing
    • Bottom CTA — "PAY.ID is currently in beta" dengan avatar stack
    • Links — Docs, X (Twitter)

2. VRAN — Vindex Reputation & Anti-Scam Network

A new decentralized trust layer for PAY.ID and other Web3 protocols.

  • packages/contracts/contracts/VindexRegistry.sol

    • Reputation scores (0–1000, default 500)
    • Staked reporting with evidence hash (IPFS/Arweave CID)
    • Web of Trust consensus — reports valid after ≥3 high-reputation (≥700) confirmations
    • Auto-blacklist when reputation drops below 100
    • Slash false reporters — stake returned to victim, reputation penalty
    • Role-based access: DEFAULT_ADMIN_ROLE, ENGINE_ROLE, SENTINEL_ROLE
  • packages/payid-react/src/hooks/useReputation.ts

    • useReputation({ registryAddress, target }){ score, isBlacklisted, isTrusted }
    • useCanReport({ registryAddress }) → check if wallet can submit report
    • useVranConfig({ registryAddress }) → read minStake and consensusThreshold

3. QRIS / Bank Bridge Extension v1.1

The fiat integration spec has been expanded from a brief memo to a full implementation guide.

  • Extended Context Schema — FiatContext with rail, psp, mcc, terminalId, currency
  • 6 new rule examples — min amount, PSP allowlist, currency restriction, MCC blocklist, QRIS-only, combined policy
  • PSP Adapter Pattern — FiatAdapter class reference implementation
  • Bank Verification Endpoint — verifyPaymentProof() reference code
  • Failure Semantics table — fail-closed for all edge cases
  • Regulatory Alignment — AML/KYC complementarity, data privacy, licensing
  • 5-Phase Roadmap — QRIS MVP → Multi-PSP → VRAN → SWIFT/SEPA → CBDC

4. 0G Resolver Hardening

The 0G storage resolver is now configurable via SDK instead of relying solely on a global variable.

  • ResolverOptions type — { zgIndexerUrl?: string }
  • resolveRule(source, options?) accepts optional ResolverOptions
  • URL priority: options.zgIndexerUrlglobalThis.PAYID_ZGS_INDEXER_URL → default https://indexer-testnet.0g.ai
  • PayIDClient and PayIDServer constructors accept resolverOptions
  • Factory functions updated: createPayIDClient({ resolverOptions }), createPayIDServer({ resolverOptions })
  • ResolverOptions exported from payid package index

🐛 Bug Fixes

  • VRAN IPFS upload — Fixed useIPFSUpload calling a non-existent placeholder endpoint (api.payid-vran.ipfs.nftstorage.link/upload). Now uses Pinata v3 API (uploads.pinata.cloud/v3/files) with VITE_PINATA_JWT auth, consistent with the rest of the codebase.
  • Reputation page navigation — Replaced window.location.href (full page reload) with <Link> from @tanstack/react-router for the Report Address and Confirm Report buttons on ReputationPage.tsx, enabling SPA navigation.
  • Tailwind CSS lint warnings — Converted bracket opacity syntax (bg-white/[0.03]) to new Tailwind v4 syntax (bg-white/3) across all V4 components
  • LandingPageV4 TypeScript error — Fixed ease type in fadeUp() transition (array → 'easeOut' as const)
  • v3/AppLayout warning — Fixed md:ml-[200px]md:ml-50
  • cursor-pointer — Added to all clickable items (buttons, cards, tabs) across V4 components

📁 Files Changed

frontend/example-product/src/components/v4/Dashboard.tsx
frontend/example-product/src/components/v4/ReceivePage.tsx
frontend/example-product/src/components/v4/HistoryPage.tsx
frontend/example-product/src/components/v4/SettingsPage.tsx
frontend/example-product/src/components/v4/AppLayout.tsx
frontend/example-product/src/components/v4/SendFlow.tsx
frontend/example-product/src/components/v4/LandingPageV4.tsx
frontend/example-product/src/components/v4/theme.tsx
frontend/example-product/src/components/v3/AppLayout.tsx
packages/contracts/contracts/VindexRegistry.sol [NEW]
packages/payid-react/src/hooks/useReputation.ts [NEW]
docs/bank-qris-extension.md [UPDATED]
docs/reputation_system_draft.md [EXISTS]
packages/sdk-core/src/resolver/resolver.ts
packages/sdk-core/src/resolver/types.ts
packages/sdk-core/src/core/client/client.ts
packages/sdk-core/src/core/server/server.ts
packages/sdk-core/src/factory.ts
packages/sdk-core/src/index.ts

Additional May 2026 Updates

5. FiatAdapter SDK Implementation

  • packages/sdk-core/src/adapters/fiatAdapter.ts — Reference implementation for QRIS/PSP integration
  • Exports: FiatAdapter, QRISPayload, FiatEvaluationResult
  • Methods: evaluatePayment(), buildContext()

6. VRAN Hook Context Integration

  • useReputation({ target }) — now reads vindexRegistry from PayIDContext automatically
  • useCanReport() — checks if connected wallet can submit staked reports
  • useVranConfig() — reads minStake and consensusThreshold
  • All hooks exported from payid-react

7. V4 Dashboard Reputation Card

  • frontend/example-product/src/components/v4/Dashboard.tsx
  • Displays live reputation score with color-coded badge (Trusted / Neutral / Blacklisted)
  • Shows between Quick Actions and Activity Feed

8. AttestationVerifier Integration (Main Payment Flow)

  • AttestationVerifier is now wired into usePayIDFlow
  • Pre-flight on-chain verification: calls verifyAttestationBatch(attestationUIDs, payer) before submitting payment
  • Attestation check is fail-closed: if requiresAttestation is true and verification fails, the payment is rejected
  • attestationUIDs passed through to payNative / payERC20 contract calls
  • Admin page: useAttestationVerifier hook for verifier initialization and management (/v4/app/admin)

9. Frontend Documentation

  • docs/integration/platform-payid-bridge.md — New doc page for Platform × PAY.ID seamless composition
  • docs/integration/platform-adapters.md — New doc page for Plug-and-Play Adapters
  • docs/integration/bank-qris-bridge.md — New doc page for Bank/QRIS Bridge
  • docs/integration/vran-reputation.md — New doc page for VRAN
  • docs/changelog.md — This changelog page
  • docs/intro.md — Updated with "What's New" section
  • docs/advanced-usage.md — Added DAO Payroll, Batch Payment, Time-Lock Vesting, and Plug-and-Play Adapters sections

10. Platform Adapters (Plug-and-Play SDK)

  • packages/payid-react/src/adapters/types.ts — Adapter interfaces: IReputationAdapter, IEscrowAdapter
  • packages/payid-react/src/adapters/default.ts — Default adapters wrapping VindexRegistry and EscrowMilestone
  • packages/payid-react/src/adapters/noop.ts — No-op adapters return safe defaults instead of throwing
  • packages/payid-react/src/PayIDProvider.tsx — New typed context:
    • ReputationModule: { adapter: IReputationAdapter, info: { label, source, active } }
    • EscrowModule: { adapter: IEscrowAdapter, info: { label, source, active } }
    • 3-tier resolution: injected → contract → noop
    • No union types, no casting — hooks use reputation.adapter directly
  • packages/payid-react/src/hooks/useReputation.ts — Source-based routing:
    • source === 'injected' → call adapter.getReputation()
    • source === 'contract' → use wagmi useReadContract
    • source === 'noop' → return safe defaults
  • Context exposes features: { reputation, escrow } for conditional UI

11. Platform × PAY.ID Bridge (Composite Adapters)

  • packages/payid-react/src/adapters/composite/platform-composite.ts — Composite adapter implementations:
    • CompositeReputationAdapter: Blends platform reputation (60%) + PAY.ID VRAN (40%) into composite score
    • PlatformEscrowAdapter: Bridges any platform's escrow to IEscrowAdapter interface
    • createCompositeIntegration(): One-liner factory for full Platform × PAY.ID setup
  • Fail-closed by default: if VRAN blacklists, composite score is blocked regardless of platform score
  • Configurable weights: platformWeight + vranWeight for different trust models
  • Escrow policy-gating: PAY.ID rules evaluate before platform milestone actions

12. Adapter System Refinements (Async + React Query + Fallback + Middleware)

  • P1 — Async Consistency: All adapter methods now return Promise<...> uniformly. No more sync/async union types (Promise<T> | T). Updated IReputationAdapter, IEscrowAdapter, and all implementations (noop, default, composite, fallback, middleware).
  • P2 — React Query Integration: Injected adapters now use useQuery from @tanstack/react-query instead of manual useEffect + useState. Benefits: caching by queryKey, deduping across components, background refetch, stale-while-revalidate.
  • P3 — Fallback Chain + Write Hook Routing:
    • FallbackReputationAdapter / FallbackEscrowAdapter: Try primary adapter first; on failure, automatically fall back to secondary. Perfect for progressive adoption (e.g. 10% platform users + 90% VRAN).
    • useSubmitReport and useConfirmReport now route writes through the adapter system. Injected adapters with submitReport/confirmReport are called via useMutation; contract path still uses wagmi useWriteContract.
  • P4 — Adapter Middleware: New withMiddlewareReputation() and withMiddlewareEscrow() wrappers. Add cross-cutting concerns to any adapter:
    • Logging: Every call logged with timing (ms)
    • Retry: Exponential backoff retry on transient failures
    • Timeout: Auto-abort calls hanging > 10s
    • Customizable: log, retry, timeout, logger options

13. Escrow Hooks & Complete Adapter Routing

  • useEscrow hooks (new):
    • useUserEscrows({ user? }) — Read escrows with useQuery (injected path) or contract iteration (contract path)
    • useCreateEscrow() — Create escrow, routes through adapter.createEscrow() or useWriteContract
    • useSubmitMilestone() — Submit deliverable evidence
    • useReleaseMilestone() — Release payment
    • useDisputeEscrow() — Raise dispute
    • useResolveRefund() — Resolve with refund
    • useAutoRefund() — Trigger auto-refund after deadline
    • All write hooks use useMutation for injected path, useWriteContract for contract path
  • useReport routed through adapter: If injected adapter implements getReport, useReport({ reportId }) calls adapter.getReport() via useQuery. Otherwise falls back to contract reports(reportId).
  • reportCount added to VranConfigResult: Optional field so adapters can expose total report count. All implementations updated (noop, default, composite).
  • Example app nav: AppLayout.tsx now shows escrow nav item conditionally via features.escrow

14. useSuccessfulReports Adapter Routing + Shared TxHookResult

  • getSuccessfulReports added to IReputationAdapter: Optional adapter method for reading successful report counts. Implemented in default, composite, fallback, and middleware adapters.
  • useSuccessfulReports routed through adapter system: Injected path uses adapter.getSuccessfulReports() via useQuery; contract path reads from successfulReports(address). Return shape now includes error field.
  • TxHookResult extracted to shared types: Single source of truth in src/types/index.ts. Removed duplicate definitions from useReputation.ts, useEscrow.ts, usePayID.ts, and useAIAgentRules.ts. Exported from package public API.

15. Dead Code Cleanup + Consistency Fixes

  • TxHookResult deduplication completed: Also removed from useAIAgentRegistry.ts (was missed in #14). All 4 write-hook files now import from shared src/types/index.ts.
  • adapters/index.ts barrel file removed: No internal or external consumers existed; all imports use direct submodule paths (./adapters/default, ./adapters/noop, etc.).
  • useReport return shape fixed: Contract path now returns error (from useReadContract) instead of hardcoded null, matching the injected path and all other read hooks.
  • DefaultReputationAdapter.getConfig fixed: Now reads reportCount from contract (reportCount()) instead of hardcoding 0. ABI updated to include reportCount view function.

16. Trust Threshold Hardcoding Fixed

  • trustThreshold added to VranConfigResult: Optional field exposing the trust threshold used for isTrusted computation. Defaults to 700 if not tracked.
  • DefaultReputationAdapter: Added trustThreshold constructor parameter (default 700). getReputation() uses this.trustThreshold instead of hardcoded 700. getConfig() returns the threshold.
  • useContractReputation: Removed extra isTrusted contract call. Now computes isTrusted = score >= DEFAULT_TRUST_THRESHOLD && !isBlacklisted locally — one fewer contract call.
  • useContractCanReport: Reads minReporterReputation from contract instead of hardcoding 100. Uses the live contract value for threshold comparison.
  • useContractVranConfig / useInjectedVranConfig: Now return trustThreshold in their result shapes.
  • All adapters updated: Noop, composite, fallback, and middleware adapters all pass through trustThreshold.

17. DefaultEscrowAdapter.createEscrow Placeholder Fixed

  • createEscrow now returns real escrowId: Parses EscrowCreated event from transaction receipt instead of returning hardcoded 0n. Event ABI added to inline EscrowMilestoneAbi. Throws descriptive error if event not found.

18. Documentation: Phantom Integration Example

  • platform-adapters.md: Added complete end-to-end Section 4 — "Phantom Example: Your Own Contracts + PAY.ID Hooks". Covers:
    • PhantomReputationAdapter + PhantomEscrowAdapter implementations
    • PayIDProvider wiring with mixed contracts (Phantom reputation/escrow + PAY.ID payment)
    • UI examples: ReputationPanel (useReputation, useCanReport, useVranConfig) and EscrowPanel (useUserEscrows, useCreateEscrow, useSubmitMilestone, useReleaseMilestone)

19. RPC Batching Optimization (Multicall)

  • useContractReputation: Batched 2 separate useReadContract calls (getReputation + isBlacklisted) into single useReadContracts multicall — 1 RPC request instead of 2.
  • useContractCanReport: Batched 2 separate useReadContract calls (getReputation + minReporterReputation) into single useReadContracts multicall.
  • useContractVranConfig: Batched 4 separate useReadContract calls (minStake + consensusThreshold + minReporterReputation + reportCount) into single useReadContracts multicall — 1 RPC request instead of 4.
  • useContractUserEscrows: Replaced N+1 loop of individual readContract calls with publicClient.multicall — all escrows(i) calls batched into 1 RPC request.
  • DefaultEscrowAdapter.getUserEscrows: Same multicall optimization applied at adapter level.

Impact: For a typical page load (reputation + canReport + vranConfig + escrow list), RPC requests drop dari ~7+ menjadi ~3 (1 per batched group + 1 nextEscrowId + 1 for other unbatched calls).


Usage Examples

Using Custom 0G Indexer

import { createPayIDClient } from 'payid';

const client = createPayIDClient({
resolverOptions: {
zgIndexerUrl: 'https://my-custom-indexer.0g.ai',
},
});

Checking Reputation Before Payment (with Context)

import { useReputation } from 'payid-react';

function PayButton({ merchantAddress }: { merchantAddress: string }) {
// Automatically reads vindexRegistry from <PayIDProvider>
const { isBlacklisted, isTrusted, score } = useReputation({
target: merchantAddress as `0x${string}`,
});

if (isBlacklisted) return <button disabled>🚫 Merchant Blacklisted</button>;
if (!isTrusted) return <button disabled>⚠️ Low Reputation ({score})</button>;

return <button>Pay Now</button>;
}

Fiat Adapter for QRIS

import { FiatAdapter } from 'payid';

const adapter = new FiatAdapter();

const { allowed, proof, reason } = await adapter.evaluatePayment(
{
amount: '150000',
currency: 'IDR',
merchantId: 'MID123',
pspCode: 'BANK_ABC',
},
'https://rules.example.com/merchant-rules.json',
walletSigner,
{
verifyingContract: '0x...',
ruleAuthority: '0x...',
chainId: 31337,
},
);

SDK Enhancements (May 2026)

1. PayID Name Resolution API — Reverse Lookup

Resolve wallet addresses back to human-readable PayIDs.

import { reverseResolvePayID, batchReverseResolve } from 'payid';

// Single lookup
const result = await reverseResolvePayID('0x1234567890123456789012345678901234567890', {
registryUrl: 'https://registry.pay.id/v1',
});
console.log(result?.payId); // "alice.pay.id"

// Batch lookup (for contact lists / tx history)
const map = await batchReverseResolve(['0x1234...', '0xabcd...']);

2. Offline-First IndexedDB Cache

Rules, contacts, drafts, and history cached locally for offline use.

import { contactCache, draftCache, ruleCache, getCacheStats } from 'payid';

// Cache a contact
await contactCache.set({
payId: 'alice.pay.id',
address: '0x1234...',
name: 'Alice',
addedAt: Date.now(),
});

// Create offline draft (syncs when online)
await draftCache.set({
toPayId: 'bob.pay.id',
amount: '100',
asset: 'USDC',
status: 'draft',
createdAt: Date.now(),
updatedAt: Date.now(),
});

// Check cache stats
const stats = await getCacheStats();
console.log(`${stats.contacts} contacts, ${stats.drafts} drafts`);

3. SDK CLI Tool

Deploy rules and verify proofs from the command line.

# Deploy a rule JSON to IPFS + register on-chain
npx payid deploy-rule ./my-rule.json \
--authority 0xRuleAuthority \
--chain 31337 \
--key $PRIVATE_KEY \
--rpc http://127.0.0.1:8545 \
--output result.json

# Verify a Decision Proof by txHash
npx payid verify-proof 0xabc123... \
--verifier 0xPayIDVerifier \
--rpc http://127.0.0.1:8545 \
--signer 0xExpectedSigner

Frontend & Smart Contract Features (May 2026)

1. Multi-Currency Display

Toggle between USD / IDR / ETH in real-time on the Send Flow amount input.

import { useMultiCurrency } from './hooks/useMultiCurrency';

const { displayCurrency, convert, format, toggle } = useMultiCurrency();
// ≈ Rp 525.000.000 shown below amount input

2. Transaction Simulation Preview

Client-side simulation before signing: checks balance, fees, and rules.

import TransactionSimulation from './components/v4/TransactionSimulation';

<TransactionSimulation
amount="0.05"
asset="ETH"
currentBalance="1.25"
onComplete={(result) => console.log(result.decision)}
/>;

3. Policy Marketplace UI

Browse and subscribe to rule templates: Freelancer Safe Pay, Parental Control, Business Hours, DAO Payroll, etc.

Route: /v4/app/marketplace

4. VRAN Reputation Badge

Dashboard shows reputation score with color-coded badges:

  • Green (800+): Trusted
  • Yellow (500-799): Neutral
  • Red (<500): Low reputation
  • Blacklisted: Warning banner before sending

5. Push Notifications

Web Push API integration with Service Worker for payment alerts.

const { subscribe, state, sendLocalNotification } = usePushNotifications();

6. Advanced Tools (Batch, Recurring, Escrow, Vesting)

Interactive UI for all new smart contract extensions.

Route: /v4/app/tools

Tabs:

  • Batch Pay — Multi-recipient ETH/ERC20 payroll
  • Recurring — Subscription creation with max amount & period
  • Escrow — Milestone-based freelancer escrow
  • Vesting — Time-locked token vesting with cliff

Smart Contract Extensions (May 2026)

1. Batch Payment (PayWithPayIDBatch.sol)

Execute multiple ETH or ERC20 payments in a single transaction.

function batchPayETH(
PayIDVerifier.Decision[] calldata decisions,
bytes[] calldata sigs,
bytes32[][] calldata attestationUIDs
) external payable

2. Recurring Payments (RecurringPayments.sol)

Subscription billing with pre-approved max amounts per period.

function createSubscription(
address receiver,
address asset,
uint256 maxAmount,
uint256 period
) external returns (uint256 subId)

function charge(uint256 subId, Decision, sig, attestationUIDs) external

3. Escrow with Milestones (EscrowMilestone.sol)

Freelancer escrow with VRAN arbiter confirmation for each milestone.

function createEscrow(
address freelancer,
address asset,
uint256[] calldata amounts,
string[] calldata descriptions,
uint256 deadline
) external payable

function releaseMilestone(uint256 escrowId, uint256 index) external onlyArbiter

4. Time-Locked Vesting (TimeLockVesting.sol)

Token vesting with cliff and linear release. Integrates with rule engine env.timestamp.

function createSchedule(
address beneficiary,
address asset,
uint256 totalAmount,
uint256 startTime,
uint256 cliff,
uint256 duration,
bool revocable,
address revoker
) external payable

function release(uint256 scheduleId) external

Off-Chain Keeper / Cron (May 2026)

Schedules need an off-chain trigger because blockchains do not run cron natively.

Script: packages/contracts/scripts/keeper.ts

What it does

  • Recurring — scans subscriptions; calls charge() when nextChargeTime <= now
  • Vesting — scans schedules; calls release() when releasable > 0
  • Escrow — scans escrows; calls autoRefund() when deadline <= now

Run locally

cd packages/contracts
PRIVATE_KEY=0x... RPC_URL=http://127.0.0.1:8545 \
bun run keeper --chainId 31337

Options

  • --dry-run — scan only, no transactions
  • --once — single pass, then exit
  • default — loops every 60 seconds

Production deployment

For production, deploy this script as:

  • Gelato Relay / Web3 Functions
  • Chainlink Automation (upkeep)
  • AWS Lambda + EventBridge (cron)
  • Self-hosted Bun service with systemd / PM2