Repository navigation
Phala Pay 0.9.0
Upgrading from 0.8.x
- Breaking: rollback is restore-only: no rollback to 0.8.3; restore required. Keep a
pre-upgrade backup and follow the restore runbook; no 0.8.x rollback is
supported. - Breaking: migrate route
pricingtoprice, configure independent observation RPC groups
and the Base sequencer gate, and replace restricted price sources. See the
configuration migration. - Set up an independent maintenance key in attested
maintenance_keysand the deployment
Environment before using planned upgrade admission. Follow
maintenance key setup, including
the explicit first-rollout bootstrap procedure. - Breaking: migrate JavaScript imports to the three packages using the
import table below; review Python's typed
transport errors and stricter validation before upgrading. - Pin every SDK to the service version:
@phala/pay,@phala/pay-react,@phala/pay-server, and
phala-paymust all use 0.9.0 with service 0.9.0.
Added
- Planned upgrade admission uses an audited, process-owned mutation pause with an expiring lease.
New mutations return503 service_maintenancewithRetry-After; reads and in-flight work
continue. Deployment health checks resume admission, with failure cleanup, automatic expiry,
and a manual-clear runbook. Business pauses remain
in effect. Deploy artifacts and the job summary record sampled first-failed/first-healthy
downtime. - Independent maintenance signing keys and key IDs: attested
maintenance_keysauthorize only
instance pause/resume; other admin routes return audited403 permission_denied. Full
operator admin authority remains outside deployment CI. - Sentry business alerts for webhook backlog and stalled delivery, internal signer/egress
failures, stale RPO heartbeats, overdue treasury/refund work, and ingress certificate expiry.
Probes emit on state transitions with hourly reminders and log recovery without an event.
Outbox alerts detect overdue processing and exclude known failing merchant endpoints; backlog
warnings require at least two eligible endpoints. Staging synthetic alert commands and a
production DSN preflight check support verification. - Capacity alerts for pgdata/observability disk usage at 75%/90%, pending WAL size/age, and stale
probes. Data retention remains seven years, with documented safe disk-pressure response. - Licence-free
uniswap_v2_twapPHA/WETH × Chainlink ETH/USD pricing, pinned to one A/B-agreed
Ethereum block. One-minute samples persist across restarts; prices require a continuous window
of at least thirty minutes, with liquidity, spot divergence, freshness and sample jump guard
rails and distinct price refusal alerts. PHA defaults use TWAP/Kraken: value at
min(TWAP, current spot) × ETH/USD and compare current Uniswap spot × ETH/USD against current
Kraken PHA/USD. Default spot/TWAP divergence is 3%, pausing faster moves; the stricter policy
starts a new thirty-minute observation window. PHA remains staging-only because no second
Allowed independent source exists; production stablecoin routes are unaffected. - Migration compatibility floors and checksum checks for N-1 rollback, verified against the
actual previous-release image. 0.9.0 establishes the compatibility-ledger protocol with an
explicit legacy bootstrap boundary; the restore-only declaration below governs this upgrade.
Changed
- Breaking: replace route
pricingwith explicitpricestablecoin sources or ordered
volatile primary/check/FX lists. The legacy parser remains available for one migration window
and emits the new shape; mixed schemas and restricted legacy sources fail validation. Replace Coin Metrics
with reviewed Chainlink/exchange sources, configure mainnet A/B observation groups and testnet
markers, and add the Base sequencer gate. Stablecoin defaults use only Allowed on-chain
Chainlink data; production rejects PermissionRequired/Prohibited sources. See the
migration guide. - Price sources fail over independently within ordered roles and fail closed on insufficient
evidence. Stablecoins credit exactly $1 only with a fresh in-band observation and no fresh
depeg; volatile assets require two agreeing independent companies. Chainlink freshness allows
the pinned heartbeat plus 600 seconds without weakening completeness, agreement or peg gates. - WAL-G uploads, backup listings and restores have separate configurable deadlines and retry
budgets. Timed-out recovery fetches abort recovery instead of promoting a partial restore. - Ingress TCP connect/client/server timeouts are 5s/30s/30s. Production preflight enforces Sentry
configuration; capacity thresholds use the shared business alert emitter. Deploy stages and
network calls have elapsed-time deadlines with timeout diagnostics. - Expand-only migration
20261029000000_uniswap_twapadds immutable observation history without
changing payment tables or permissions. Scale migrations20261029030000–20261029030005add
two cursor tables and five indexes without changing existing rows or constraints. Their
compatibility ledger retains floor20261028000002: compatible protocol-aware binary rollback
uses the previous config and retains observations. This does not permit rollback to 0.8.x. - Local SDK sandbox and CVM rehearsals use disposable TLS ingress with a run-scoped certificate,
preserving HTTPS validation and normal system trust roots. Hermetic local Chainlink, Uniswap
and exchange fixtures support price rehearsal.
Fixed
- Price RPC groups tolerate small pinned-read head regressions and fail over within a group.
- Image builds retry once without caches for recognized Actions cache transport failures only;
cache export failures no longer fail builds, and diagnostics remain available. - Backup health requires a current-timeline base backup and fresh WAL data, backlog and LSN
progress; old backlog uploads cannot refresh recovery age. First base backups retry with
capped backoff until successful. - Failed critical restore checks block acceptance and unfreeze. An explicit administrator
override requires a reason and is recorded atomically in audit history. - Local restore drills use disposable Sepolia and Base Sepolia Anvil chains with distinct A/B
RPC endpoints and contract fixtures. They enforce the 60-second RPO from failure to the last
replayed committed marker, including upload latency; RTO includes unfreeze and a successful
merchant API request. - API body reads are bounded to 5 seconds and request processing to 25 seconds; health checks
have independent capacity and a 2-second database deadline. API connections have a 30-second
read idle timeout and a 60-second hard lifetime, bounding incomplete headers and keep-alive work. - Scan all issued addresses, including retired addresses, in durable pages of 1,000. Finalized
and confirmation cursors advance only after every address page commits. Reconciliation uses
persistent rotating pages for historical credit, derivation, custody, and flush-link checks,
with a bounded 4,000-entry derivation cache and concurrent query indexes. Post-restore row checks
still traverse the complete ledger.
Breaking (operators)
- 0.9.0: no rollback to 0.8.3; restore required. No rollback to any 0.8.x release:
use the pre-upgrade backup and restore runbook. Route configuration and
SDK changes also prevent rollback. 0.9.0 is the first compatibility-ledger protocol release;
from 0.10.0 onward, real N-1 rollback is enforced unless an operator declaration and a raised
compatibility floor require restoration. N-1 is always the latest stable release.
JS SDK (@phala/pay, @phala/pay-react, @phala/pay-server)
Added
- Opt-in
upgradeTolerancein@phala/pay-serverfor GET and idempotent POST retries across
maintenance, connection failures, and gateway 502/503/504 for up to five minutes. Explicit
deadlines and cancellation remain effective; keys and bodies stay fixed. Browser core checkout
and React deposit address polling preserve their last view through outages and show a neutral
reconnecting state. - Merchant server client at
@phala/pay-server: all OpenAPI resources, typed parameters/responses,
verified quote/address results, two-variablePhalaPay.fromEnv(), frozen pins parse/encode,
bound Ed25519 webhooks andcheckoutParamswith browser-exportedCheckoutParams. - Deadline-bounded transport with attempt timeouts, jitter, Retry-After, frozen POST idempotency,
redirect refusal, lossless integer validation, cancellation and typed redacted errors. - Pure
depositNetAmount/balanceDeltahelpers with monotone ledger convergence and strict
validation, covering all five shared fixture groups. @phala/pay-server/helpersfor keyless address, webhook and offline sweep builders. Existing
server helper exports remain available;ForwarderResponsenames the generated API forwarder
whileForwarderretains its legacy contract-pins type.
Changed
-
Breaking: the JavaScript SDK is now three packages.
@phala/payis framework-free browser
code,@phala/pay-reactcontains the React components andstyles.css, and@phala/pay-server
contains the merchant client and server helpers. Migrate the removed entry points as follows:Old import New import @phala/pay/react@phala/pay-react@phala/pay/styles.css@phala/pay-react/styles.css@phala/pay/server@phala/pay-server@phala/pay/server/helpers@phala/pay-server/helpersInstall the new package explicitly at the service version.
@phala/payhas no React peer
dependency or server/key-handling code. -
Breaking:
@phala/pay-serverrejects browser-like environments before reading credentials.
Move browser offline helper imports to@phala/pay-server/helpers. Node.js >=20.3, Bun and
Deno server runtimes are supported when fetch, AbortSignal.any and WebCrypto are available.
The browser core entry and existing checkout props remain keyless. -
Breaking: duplicate webhook signing headers and non-exact UTF-8 bodies are rejected. The
legacyWebhookSignatureErrorexport is an alias ofSignatureVerificationError.
Python SDK (phala-pay)
Added
- Pins-based
PhalaPayconfiguration andfrom_env(), bound webhook verification, checkout
parameters, and paginated address validation. Checkout handoffs bind the originating verified
quote and revalidate its address. - Pure ledger helpers validate snapshots and merge cumulative refunds and reversals without
floats or input mutation. Unknown webhook types are ignored while their raw objects remain
available. - Opt-in
upgrade_toleranceat client construction and per resource call for GET and replayable
idempotent POST retries through maintenance, network/attempt timeouts, and gateway 502/503/504
(including HTML) for at most five minutes. Explicit deadlines stay hard limits, body/key stay
fixed, and interrupts or replayed errors terminate retries. Interactive defaults remain
15 seconds per attempt, four attempts, and 60 seconds total.
Changed
- Breaking: transport failures are wrapped in typed SDK errors; update handlers that catch
underlying transport exceptions. Diagnostics redact API keys and client secrets. - Breaking: enforce immutable canonical pins, API key checksums, origin and response identity
checks, and checkout handoffs from the originating verified quote. Redirects and invalid
pagination are rejected; callers relying on previously accepted invalid inputs must migrate. - Use one transport path for POST replay, explicit per-call controls, deadline and body timeouts,
bounded jitter and Retry-After; borrowed transports retain their original ownership.
SDKs
@phala/pay 0.9.0, @phala/pay-react 0.9.0, and @phala/pay-server 0.9.0 on npm;
phala-pay 0.9.0 on PyPI.
Verify
deploy/verify-release.sh
checks this release as Deploy does (self-hosting guide).