The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.
Invariant: nothing touches pubnet until the GO/NO-GO gate passes, and every step has a
rollback. Mainnet is OFF by default - the cutover is “turn the deliberate opt-in on, watched”,
and the rollback is “turn it back off.”
Owner: buckspay eng lead, On-call: the rotation named in the team runbook (PagerDuty),
Security sign-off: per Audit prep.
Every row inherits the controls in the base checklist above (spend caps, kill-switch, token
allow-list, redacted observability) - these rows add only what the extended surface introduces.
Item
Owner
Verify
Multicall router pinned on pubnet + parity
eng
Pubnet-installed router address == the SDK pin; pnpm --filter @buckspay/accounts exec vitest run batch-entry + bash scripts/check-pin-parity.sh pass
Session policy-account Wasm pinned
eng
pnpm --filter @buckspay/accounts exec vitest run policy-account passes (the on-chain spend-limit + allowlist authorizer hash is pinned)
Contract decision gates GO
eng
bash scripts/check-contract-decisions.sh exits 0 (the gas-forwarder / batch-router / policy-signer decisions are GO + fixtures pinned)
Fee token on the relay allow-list
eng
Only Circle’s pubnet USDC SAC is accepted as the gas fee token, so gas: { mode: "token" } cannot forward an arbitrary token
Signer-proxy secrets server-side
security
web3auth client secret + the OTP backend secret are in the server vault, NOT in any bundle; POST /auth/social + POST /auth/email are reachable only through the app BFF (@buckspay/nextjs)
Channel-account pool funded + boot-validated
ops
The parallel channel accounts exist on pubnet, are funded above the floor, and are validated at facilitator boot; per-channel low-balance alerts armed
Cross-feature smoke green
eng
BUCKSPAY_E2E_MAINNET=1 BUCKSPAY_E2E=1 pnpm e2e runs the session + batch + gas-in-token smoke green with tiny funds
Reverse the cutover with no fund loss (pubnet config is OFF by default, so rollback = “turn
the deliberate flag back off”):
Flip the opt-in off. SDK: stop passing allowMainnet: true (browser) / unset
BUCKSPAY_ALLOW_MAINNET (Node) -> resolveNetwork("pubnet", ...) throws again. Facilitator:
set STELLAR_NETWORK=testnet / disable the pubnet config -> the relay refuses
pubnet payloads.
Drain in-flight intents. Let signed, unexpired auth entries settle or expire
(signatureExpirationLedger bounds them); do not accept new pubnet relays (kill-switch).
Revert the docs “supported” change if the GA changeset already shipped - publish a
follow-up patch re-gating note (mainnet remains technically opt-in; the docs walk it back to
“experimental” until re-cutover).
Re-point clients to testnet and confirm no pubnet traffic reaches the facilitator.
The pubnet sponsor holds only operational float, never custody.
Funding source: the buckspay treasury account (named in the ops vault), NOT a user account.
Threshold + target: refill when sponsor XLM < SPONSOR_MIN_XLM (the low-balance auto-pause
floor); top up to the configured target balance (≈ N days of expected gas).
Transfer: the ops owner submits a payment from the treasury to the sponsor G... for the
top-up amount; record the tx hash in the ops log.
Confirm: after the refill confirms, verify the low-balance alert clears and
the facilitator resumes relays (auto-pause lifts once balance ≥ floor).
Severities: SEV-1 (sponsor draining / funds at risk), SEV-2 (relays failing / degraded),
SEV-3 (elevated errors, no fund risk).
Escalation: on-call -> eng lead -> security sign-off. Page on SEV-1/2.
First five minutes: (1) trip the kill-switch (emergency pause above); (2) assess the
sponsor balance + spend-cap counters; (3) check facilitator logs for the offending
intent (PII-free structured records - chain/token/outcome, hashed address tags);
(4) snapshot RPC/ledger state for the post-mortem.
Comms: status update to the incident channel every 30 min until resolved; customer-facing
note if user funds were affected.
Post-incident: a written review within 48h (timeline, root cause, the guard that should have
caught it, the follow-up). The relayer-trust + sponsor-exposure surfaces are in the
threat model.
The human/machine boundary is explicit: Claude prepares + stages; the maintainer publishes.
Claude - ensure a changeset exists for every change since the last release
(.changeset/mainnet-ga.md + any others) and stage it.
Claude / CI - run the go/no-go gate: bash scripts/release-gate.shmust exit 0 (all
hard guards PASS); bash scripts/check-cutover-runbook.sh -> exit 0; bash scripts/check-feature-docs.sh
-> exit 0; the guarded mainnet smoke green (BUCKSPAY_E2E_MAINNET=1 BUCKSPAY_E2E=1 pnpm e2e).
Security sign-off finalized. This is the GO/NO-GO gate above.
MAINTAINER (user) - run pnpm changeset version (computes the lockstep bump + CHANGELOGs -
never hand-edit a version), then pnpm -r build + pnpm -r publish --dry-run (confirm each
tarball is dist/-only), then pnpm changeset publish + git push --follow-tags. Claude
never runs version/publish - it is outward, irreversible, and needs npm auth (see
Versioning and migration).
Flip pubnet on per the pre-flight + GO gate; watch the sponsor balance + spend caps
for the first window; keep the kill-switch one command away.
Bringing up gas-in-token, atomic batch, sessions, social/email login, and the parallel
channel pool is additive to the base cutover - the GO/NO-GO gate, kill-switch, and rollback
above are unchanged and now cover the new flows. Sequence the additions; do not weaken the gate.
New endpoints (POST /fee/quote, POST /auth/social, POST /auth/email) - enable per the
extended pre-flight. Each inherits the base controls (spend caps, kill-switch, token allow-list,
redacted observability); it does not get a parallel control plane. The /auth/* routes are
reachable only through the app BFF (@buckspay/nextjs) - provider secrets stay server-side,
never in a browser or mobile bundle.
Pinned contracts - confirm the pubnet-installed Multicall router address and the
policy-account (session authorizer) Wasm hash match the SDK pins, with the same pin-parity
discipline as the passkey smart-account hash. A mismatch is a NO-GO trigger. The FeeForwarder
is facilitator-side (returned by /fee/quote); its fee token must be on the relay allow-list.
Channel-account pool - bring the pool up funded and boot-validated; it is transparent to the
SDK (parallel throughput, no API surface). Watch the per-channel balances alongside the sponsor
for the first window.
Rollback addendum - disabling the extended surface = unset the FeeForwarder / Multicall /
channel config + the /auth/* routes (the relay then refuses token-gas / batched / auth payloads);
the sponsored single-call path keeps working. The kill-switch still stops all pubnet relays in
seconds.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Buckspay SDK","description":"Gasless smart-wallet SDK for Stellar (Soroban) USDC payments - web and mobile.","colors":{"primary":"#1884FF","light":"#21CBF3","dark":"#1884FF"},"logo":{"light":"https://mintcdn.com/buckspay/npvFrjcwne30-E69/logo/buckspay-light.png?fit=max\u0026auto=format\u0026n=npvFrjcwne30-E69\u0026q=85\u0026s=8ea8e7682265d39c221fe2366f04b7d6","dark":"https://mintcdn.com/buckspay/npvFrjcwne30-E69/logo/buckspay.png?fit=max\u0026auto=format\u0026n=npvFrjcwne30-E69\u0026q=85\u0026s=fca5f0b7359fb8a30e6a23f336ca0ada"},"favicon":"https://mintcdn.com/buckspay/npvFrjcwne30-E69/images/favicon.svg?fit=max\u0026auto=format\u0026n=npvFrjcwne30-E69\u0026q=85\u0026s=f8185102fd9b76e5100ef92e303b0761","appearance":{"default":"dark"},"background":{"color":{"dark":"#0A0D10"}},"navbar":{"links":[{"href":"https://github.com/bucks-pay/buckspay-sdk","label":"GitHub"}]},"footer":{"socials":{"github":"https://github.com/bucks-pay/buckspay-sdk"}},"search":{"prompt":"Search or ask the Buckspay SDK docs"},"styling":{"codeblocks":"dark","latex":false},"contextual":{"options":["copy","view","chatgpt","claude","cursor","vscode"],"display":"header"},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"buckspay","hasAudioNarration":false,"actualSubdomain":"buckspay","customDomains":["docs.buckspay.xyz"],"gitSource":{"type":"github","owner":"bucks-pay","repo":"buckspay-sdk","deployBranch":"main","contentDirectory":"docs","isPrivate":true,"mountPath":"","label":""},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6ae95b4dcb76ddd761cc4fdc:success","clientVersion":"0.0.4102","searchFilterCounts":[{"language":"default","tag":"Guides","count":36},{"language":"default","tag":"SDK Reference","count":13},{"language":"default","tag":"API Reference","count":12},{"language":"default","tag":"Features","count":9},{"language":"default","tag":"Production","count":7},{"language":"default","tag":"Signers","count":6},{"language":"default","tag":"Concepts","count":5},{"language":"default","tag":"Platforms","count":5},{"language":"default","tag":"Security","count":5},{"language":"default","tag":"Get Started","count":4}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"production/mainnet-cutover","slug":"/production/mainnet-cutover","pageMetadata":{"title":"Mainnet cutover runbook","description":"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.","href":"/production/mainnet-cutover"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,em:`em`,hr:`hr`,li:`li`,ol:`ol`,p:`p`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{Heading,Table,Warning}=_components;if(!Heading)_missingMdxReference(`Heading`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Invariant:`}),` nothing touches pubnet until the GO/NO-GO gate passes, and every step has a\nrollback. Mainnet is OFF by default - the cutover is “turn the deliberate opt-in on, watched”,\nand the rollback is “turn it back off.”`]})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Owner:`}),` buckspay eng lead, `,_jsx(_components.strong,{children:`On-call:`}),` the rotation named in the team runbook (PagerDuty),\n`,_jsx(_components.strong,{children:`Security sign-off:`}),` per `,_jsx(_components.a,{href:`/production/security/audit-prep`,children:`Audit prep`}),`.`]}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`pre-flight-checklist`,children:`Pre-flight checklist`}),`\n`,_jsxs(_components.p,{children:[`Every row maps to a concrete verification command. `,_jsx(_components.strong,{children:`All must be green before the GO/NO-GO gate.`})]}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Item`}),_jsx(_components.th,{children:`Owner`}),_jsx(_components.th,{children:`Verify`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Release gate PASS`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`bash scripts/release-gate.sh`}),` exits 0 (all hard guards PASS)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Secrets rotated`}),_jsx(_components.td,{children:`security`}),_jsxs(_components.td,{children:[`Sponsor secret + facilitator API key rotated post-incident; old keys revoked; `,_jsx(_components.code,{children:`bash scripts/check-no-committed-env.sh`}),` exits 0 (no tracked `,_jsx(_components.code,{children:`.env*`}),`, sponsor ≠ leaked `,_jsx(_components.code,{children:`G`}),`)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Sponsor funded + low-balance alert armed`}),_jsx(_components.td,{children:`ops`}),_jsxs(_components.td,{children:[`Pubnet sponsor XLM ≥ the configured floor (`,_jsx(_components.code,{children:`SPONSOR_MIN_XLM`}),`); the low-balance alert fires below it (tested in staging)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`OZ Wasm installed on pubnet + pin parity`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[`Pubnet-installed Wasm hash == `,_jsx(_components.code,{children:`OZ_SMART_ACCOUNT_WASM_HASH`}),`; `,_jsx(_components.code,{children:`node scripts/verify-wasm-hash.mjs`}),` + `,_jsx(_components.code,{children:`bash scripts/check-pin-parity.sh`}),` pass`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Dedicated RPC`}),_jsx(_components.td,{children:`ops`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`SOROBAN_RPC_URL_PUBNET`}),` points at a dedicated/consistent provider (NOT a public load balancer); a health probe returns the latest ledger`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`USDC allow-list set`}),_jsx(_components.td,{children:`eng`}),_jsx(_components.td,{children:`Only Circle’s pubnet USDC SAC is accepted by the facilitator relay allow-list`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Spend caps + kill-switch armed`}),_jsx(_components.td,{children:`ops`}),_jsx(_components.td,{children:`Per-tx + rolling spend caps configured; the kill-switch is reachable and tested in staging`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Guarded mainnet smoke green`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`BUCKSPAY_E2E_MAINNET=1 BUCKSPAY_E2E=1 pnpm e2e`}),` runs `,_jsx(_components.strong,{children:`both`}),` pubnet smokes green with tiny funds (0.0001 USDC)`]})]})]})]}),`\n`,_jsx(Heading,{level:`3`,id:`extended-surface-gas-in-token-/-batch-/-sessions-/-login-/-parallel`,children:`Extended surface (gas-in-token / batch / sessions / login / parallel)`}),`\n`,_jsx(_components.p,{children:`Every row inherits the controls in the base checklist above (spend caps, kill-switch, token\nallow-list, redacted observability) - these rows add only what the extended surface introduces.`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Item`}),_jsx(_components.th,{children:`Owner`}),_jsx(_components.th,{children:`Verify`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Multicall router pinned on pubnet + parity`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[`Pubnet-installed router address == the SDK pin; `,_jsx(_components.code,{children:`pnpm --filter @buckspay/accounts exec vitest run batch-entry`}),` + `,_jsx(_components.code,{children:`bash scripts/check-pin-parity.sh`}),` pass`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Session policy-account Wasm pinned`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`pnpm --filter @buckspay/accounts exec vitest run policy-account`}),` passes (the on-chain spend-limit + allowlist authorizer hash is pinned)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Contract decision gates GO`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`bash scripts/check-contract-decisions.sh`}),` exits 0 (the gas-forwarder / batch-router / policy-signer decisions are GO + fixtures pinned)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Fee token on the relay allow-list`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[`Only Circle’s pubnet USDC SAC is accepted as the gas fee token, so `,_jsx(_components.code,{children:`gas: { mode: \"token\" }`}),` cannot forward an arbitrary token`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Signer-proxy secrets server-side`}),_jsx(_components.td,{children:`security`}),_jsxs(_components.td,{children:[`web3auth client secret + the OTP backend secret are in the server vault, NOT in any bundle; `,_jsx(_components.code,{children:`POST /auth/social`}),` + `,_jsx(_components.code,{children:`POST /auth/email`}),` are reachable `,_jsx(_components.strong,{children:`only`}),` through the app BFF (`,_jsx(_components.code,{children:`@buckspay/nextjs`}),`)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Channel-account pool funded + boot-validated`}),_jsx(_components.td,{children:`ops`}),_jsx(_components.td,{children:`The parallel channel accounts exist on pubnet, are funded above the floor, and are validated at facilitator boot; per-channel low-balance alerts armed`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Cross-feature smoke green`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`BUCKSPAY_E2E_MAINNET=1 BUCKSPAY_E2E=1 pnpm e2e`}),` runs the session + batch + gas-in-token smoke green with tiny funds`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Feature docs + examples present`}),_jsx(_components.td,{children:`eng`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`bash scripts/check-feature-docs.sh`}),` exits 0 (every feature guide page + compiled example present, coverage table complete)`]})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`go-/-no-go-gate`,children:`GO / NO-GO gate`}),`\n`,_jsx(_components.p,{children:`The single decision point.`}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`GO only if ALL hold:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Every pre-flight row is checked green.`}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`bash scripts/release-gate.sh`}),` exits 0 (all hard guards PASS).`]}),`\n`,_jsx(_components.li,{children:`The guarded mainnet smoke (classic + contract) is green.`}),`\n`,_jsxs(_components.li,{children:[`Two named approvers have signed: the `,_jsx(_components.strong,{children:`eng owner`}),` and the `,_jsx(_components.strong,{children:`security sign-off`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`NO-GO if ANY of these is true`}),` (explicit triggers):`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`release-gate.sh`}),` FAILs.`]}),`\n`,_jsx(_components.li,{children:`Either mainnet smoke is red.`}),`\n`,_jsx(_components.li,{children:`Pubnet sponsor XLM below the floor.`}),`\n`,_jsxs(_components.li,{children:[`Pubnet Wasm hash ≠ `,_jsx(_components.code,{children:`OZ_SMART_ACCOUNT_WASM_HASH`}),` (pin mismatch).`]}),`\n`,_jsx(_components.li,{children:`USDC allow-list unset (facilitator would sponsor an arbitrary token).`}),`\n`,_jsx(_components.li,{children:`Kill-switch unreachable / untested.`}),`\n`]}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Approver`}),_jsx(_components.th,{children:`Role`}),_jsx(_components.th,{children:`Date`}),_jsx(_components.th,{children:`GO / NO-GO`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.em,{children:`(pending)`})}),_jsx(_components.td,{children:`eng owner`}),_jsx(_components.td,{}),_jsx(_components.td,{})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.em,{children:`(pending)`})}),_jsx(_components.td,{children:`security sign-off`}),_jsx(_components.td,{}),_jsx(_components.td,{})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`rollback`,children:`Rollback`}),`\n`,_jsxs(_components.p,{children:[`Reverse the cutover with `,_jsx(_components.strong,{children:`no fund loss`}),` (pubnet config is OFF by default, so rollback = “turn\nthe deliberate flag back off”):`]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Flip the opt-in off.`}),` SDK: stop passing `,_jsx(_components.code,{children:`allowMainnet: true`}),` (browser) / unset\n`,_jsx(_components.code,{children:`BUCKSPAY_ALLOW_MAINNET`}),` (Node) -> `,_jsx(_components.code,{children:`resolveNetwork(\"pubnet\", ...)`}),` throws again. Facilitator:\nset `,_jsx(_components.code,{children:`STELLAR_NETWORK=testnet`}),` / disable the pubnet config -> the relay refuses\npubnet payloads.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Drain in-flight intents.`}),` Let signed, unexpired auth entries settle or expire\n(`,_jsx(_components.code,{children:`signatureExpirationLedger`}),` bounds them); do not accept new pubnet relays (kill-switch).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Revert the docs “supported” change`}),` if the GA changeset already shipped - publish a\nfollow-up `,_jsx(_components.code,{children:`patch`}),` re-gating note (mainnet remains technically opt-in; the docs walk it back to\n“experimental” until re-cutover).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Re-point clients to testnet`}),` and confirm no pubnet traffic reaches the facilitator.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`sponsor-refill-procedure`,children:`Sponsor-refill procedure`}),`\n`,_jsxs(_components.p,{children:[`The pubnet sponsor holds `,_jsx(_components.strong,{children:`only operational float`}),`, never custody.`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Funding source:`}),` the buckspay treasury account (named in the ops vault), NOT a user account.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Threshold + target:`}),` refill when sponsor XLM \u003c `,_jsx(_components.code,{children:`SPONSOR_MIN_XLM`}),` (the low-balance auto-pause\nfloor); top up to the configured target balance (≈ N days of expected gas).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Transfer:`}),` the ops owner submits a payment from the treasury to the sponsor `,_jsx(_components.code,{children:`G...`}),` for the\ntop-up amount; record the tx hash in the ops log.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Confirm:`}),` after the refill confirms, verify the low-balance alert `,_jsx(_components.strong,{children:`clears`}),` and\nthe facilitator resumes relays (auto-pause lifts once balance ≥ floor).`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`emergency-pause-kill-switch`,children:`Emergency pause (kill-switch)`}),`\n`,_jsx(_components.p,{children:`Immediately stop pubnet relays without a full rollback (seconds, reversible).`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Trip it:`}),` `,_jsx(_components.code,{children:`POST /admin/relays/pause`}),` with `,_jsx(_components.code,{children:`x-admin-api-key`}),` - or set\n`,_jsx(_components.code,{children:`RELAYS_ENABLED=false`}),` and restart. `,_jsx(_components.code,{children:`/relay`}),` then returns `,_jsx(_components.code,{children:`503 relays_paused`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Who:`}),` any on-call engineer with the admin key (SEPARATE from the relay `,_jsx(_components.code,{children:`API_KEY`}),`).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Propagation:`}),` effective immediately on the instance(s); confirm across all replicas.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Verify tripped:`}),` a pubnet relay attempt is refused with `,_jsx(_components.code,{children:`503 relays_paused`}),`; `,_jsx(_components.code,{children:`submitStellarTransfer`}),`\nis never reached.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Pause vs rollback:`}),` pause is reversible in seconds (`,_jsx(_components.code,{children:`/admin/relays/resume`}),`); rollback is the\nfull cutover reversal above. Pause first, then decide.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`incident-response`,children:`Incident response`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Severities:`}),` SEV-1 (sponsor draining / funds at risk), SEV-2 (relays failing / degraded),\nSEV-3 (elevated errors, no fund risk).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Escalation:`}),` on-call -> eng lead -> security sign-off. Page on SEV-1/2.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`First five minutes:`}),` (1) `,_jsx(_components.strong,{children:`trip the kill-switch`}),` (emergency pause above); (2) assess the\nsponsor balance + spend-cap counters; (3) check facilitator logs for the offending\nintent (PII-free structured records - chain/token/outcome, hashed address tags);\n(4) snapshot RPC/ledger state for the post-mortem.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Comms:`}),` status update to the incident channel every 30 min until resolved; customer-facing\nnote if user funds were affected.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Post-incident:`}),` a written review within 48h (timeline, root cause, the guard that should have\ncaught it, the follow-up). The relayer-trust + sponsor-exposure surfaces are in the\n`,_jsx(_components.a,{href:`/production/security/threat-model`,children:`threat model`}),`.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`go-live-sequence-ga`,children:`Go-live sequence (GA)`}),`\n`,_jsxs(_components.p,{children:[`The human/machine boundary is explicit: `,_jsx(_components.strong,{children:`Claude prepares + stages; the maintainer publishes.`})]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Claude`}),` - ensure a changeset exists for every change since the last release\n(`,_jsx(_components.code,{children:`.changeset/mainnet-ga.md`}),` + any others) and stage it.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Claude / CI`}),` - run the go/no-go gate: `,_jsx(_components.code,{children:`bash scripts/release-gate.sh`}),` `,_jsx(_components.strong,{children:`must exit 0`}),` (all\nhard guards PASS); `,_jsx(_components.code,{children:`bash scripts/check-cutover-runbook.sh`}),` -> exit 0; `,_jsx(_components.code,{children:`bash scripts/check-feature-docs.sh`}),`\n-> exit 0; the guarded mainnet smoke green (`,_jsx(_components.code,{children:`BUCKSPAY_E2E_MAINNET=1 BUCKSPAY_E2E=1 pnpm e2e`}),`).\nSecurity sign-off finalized. This is the GO/NO-GO gate above.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`MAINTAINER (user)`}),` - run `,_jsx(_components.code,{children:`pnpm changeset version`}),` (computes the lockstep bump + CHANGELOGs -\nnever hand-edit a `,_jsx(_components.code,{children:`version`}),`), then `,_jsx(_components.code,{children:`pnpm -r build`}),` + `,_jsx(_components.code,{children:`pnpm -r publish --dry-run`}),` (confirm each\ntarball is `,_jsx(_components.code,{children:`dist/`}),`-only), then `,_jsx(_components.code,{children:`pnpm changeset publish`}),` + `,_jsx(_components.code,{children:`git push --follow-tags`}),`. `,_jsx(_components.strong,{children:`Claude\nnever runs version/publish`}),` - it is outward, irreversible, and needs npm auth (see\n`,_jsx(_components.a,{href:`/production/versioning-and-migration`,children:`Versioning and migration`}),`).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Flip pubnet on`}),` per the pre-flight + GO gate; watch the sponsor balance + spend caps\nfor the first window; keep the kill-switch one command away.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`extended-surface-go-live`,children:`Extended surface go-live`}),`\n`,_jsxs(_components.p,{children:[`Bringing up gas-in-token, atomic batch, sessions, social/email login, and the parallel\nchannel pool is `,_jsx(_components.strong,{children:`additive`}),` to the base cutover - the GO/NO-GO gate, kill-switch, and rollback\nabove are unchanged and now cover the new flows. Sequence the additions; do not weaken the gate.`]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`New endpoints`}),` (`,_jsx(_components.code,{children:`POST /fee/quote`}),`, `,_jsx(_components.code,{children:`POST /auth/social`}),`, `,_jsx(_components.code,{children:`POST /auth/email`}),`) - enable per the\nextended pre-flight. Each inherits the base controls (spend caps, kill-switch, token allow-list,\nredacted observability); it does not get a parallel control plane. The `,_jsx(_components.code,{children:`/auth/*`}),` routes are\nreachable `,_jsx(_components.strong,{children:`only`}),` through the app BFF (`,_jsx(_components.code,{children:`@buckspay/nextjs`}),`) - provider secrets stay server-side,\nnever in a browser or mobile bundle.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Pinned contracts`}),` - confirm the pubnet-installed `,_jsx(_components.strong,{children:`Multicall`}),` router address and the\n`,_jsx(_components.strong,{children:`policy-account`}),` (session authorizer) Wasm hash match the SDK pins, with the same pin-parity\ndiscipline as the passkey smart-account hash. A mismatch is a `,_jsx(_components.strong,{children:`NO-GO`}),` trigger. The FeeForwarder\nis facilitator-side (returned by `,_jsx(_components.code,{children:`/fee/quote`}),`); its fee token must be on the relay allow-list.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Channel-account pool`}),` - bring the pool up funded and boot-validated; it is transparent to the\nSDK (parallel throughput, no API surface). Watch the per-channel balances alongside the sponsor\nfor the first window.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Rollback addendum`}),` - disabling the extended surface = unset the FeeForwarder / Multicall /\nchannel config + the `,_jsx(_components.code,{children:`/auth/*`}),` routes (the relay then refuses token-gas / batched / auth payloads);\nthe sponsored single-call path keeps working. The kill-switch still stops `,_jsx(_components.strong,{children:`all`}),` pubnet relays in\nseconds.`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":"dark","config":{},"pageMetadata":{"title":"Mainnet cutover runbook","description":"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.","href":"/production/mainnet-cutover"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Pre-flight checklist","slug":"pre-flight-checklist","depth":2,"children":[{"title":"Extended surface (gas-in-token / batch / sessions / login / parallel)","slug":"extended-surface-gas-in-token-/-batch-/-sessions-/-login-/-parallel","depth":3,"children":[]}]},{"title":"GO / NO-GO gate","slug":"go-/-no-go-gate","depth":2,"children":[]},{"title":"Rollback","slug":"rollback","depth":2,"children":[]},{"title":"Sponsor-refill procedure","slug":"sponsor-refill-procedure","depth":2,"children":[]},{"title":"Emergency pause (kill-switch)","slug":"emergency-pause-kill-switch","depth":2,"children":[]},{"title":"Incident response","slug":"incident-response","depth":2,"children":[]},{"title":"Go-live sequence (GA)","slug":"go-live-sequence-ga","depth":2,"children":[]},{"title":"Extended surface go-live","slug":"extended-surface-go-live","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"buckspay","siteName":"Buckspay SDK","title":"Mainnet cutover runbook - Buckspay SDK","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-07-01T01:48:46.641Z","originalFileLocation":"production/mainnet-cutover.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Buckspay SDK\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Mainnet cutover runbook - Buckspay SDK\">\u003cmeta data-mint-head property=\"og:description\" content=\"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Buckspay SDK\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.buckspay.xyz/production/mainnet-cutover\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://buckspay.mintlify.site/_mintlify/api/og/v2?division=Production\u0026amp;title=Mainnet+cutover+runbook\u0026amp;description=The+deliberate%2C+reversible%2C+audited+procedure+to+enable+Stellar+pubnet+for+the+Buckspay+SDK+and+facilitator.\u0026amp;theme=35af4ee300a5cd95d7ae32a8\u0026amp;signature=8eb23b8ff70eae1f87475e72651b5b243d30dabb496baa50e53b6de2e79c10f8\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Mainnet cutover runbook - Buckspay SDK\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://buckspay.mintlify.site/_mintlify/api/og/v2?division=Production\u0026amp;title=Mainnet+cutover+runbook\u0026amp;description=The+deliberate%2C+reversible%2C+audited+procedure+to+enable+Stellar+pubnet+for+the+Buckspay+SDK+and+facilitator.\u0026amp;theme=35af4ee300a5cd95d7ae32a8\u0026amp;signature=8eb23b8ff70eae1f87475e72651b5b243d30dabb496baa50e53b6de2e79c10f8\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/buckspay/HQ53bdLVcWcry6ev/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Buckspay SDK\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#1884FF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.buckspay.xyz/production/mainnet-cutover\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/production/mainnet-cutover.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.buckspay.xyz/#organization\",\"name\":\"Buckspay SDK\",\"url\":\"https://docs.buckspay.xyz\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/buckspay/npvFrjcwne30-E69/logo/buckspay-light.png?fit=max\u0026auto=format\u0026n=npvFrjcwne30-E69\u0026q=85\u0026s=8ea8e7682265d39c221fe2366f04b7d6\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.buckspay.xyz#website\",\"name\":\"Buckspay SDK\",\"url\":\"https://docs.buckspay.xyz\",\"publisher\":{\"@id\":\"https://docs.buckspay.xyz/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.buckspay.xyz/production/mainnet-cutover#webpage\",\"url\":\"https://docs.buckspay.xyz/production/mainnet-cutover\",\"name\":\"Mainnet cutover runbook\",\"description\":\"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.\",\"dateModified\":\"2026-07-01T01:48:46.641Z\",\"isPartOf\":{\"@id\":\"https://docs.buckspay.xyz#website\"},\"breadcrumb\":{\"@id\":\"https://docs.buckspay.xyz/production/mainnet-cutover#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.buckspay.xyz/production/mainnet-cutover#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Buckspay SDK\",\"item\":\"https://docs.buckspay.xyz\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mainnet cutover runbook\",\"item\":\"https://docs.buckspay.xyz/production/mainnet-cutover\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.buckspay.xyz/production/mainnet-cutover#article\",\"headline\":\"Mainnet cutover runbook\",\"name\":\"Mainnet cutover runbook\",\"description\":\"The deliberate, reversible, audited procedure to enable Stellar pubnet for the Buckspay SDK and facilitator.\",\"url\":\"https://docs.buckspay.xyz/production/mainnet-cutover\",\"mainEntityOfPage\":{\"@id\":\"https://docs.buckspay.xyz/production/mainnet-cutover#webpage\"},\"dateModified\":\"2026-07-01T01:48:46.641Z\",\"publisher\":{\"@id\":\"https://docs.buckspay.xyz/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.buckspay.xyz#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Buckspay SDK\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Buckspay SDK\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/production/mainnet-cutover.md","siteName":"Buckspay SDK","nav":{"global":null,"tabs":[{"tab":"Guides","groups":[{"group":"Get Started","pages":[{"title":"Buckspay SDK","href":""},{"title":"Quickstart","href":"/get-started/quickstart"},{"title":"Installation","href":"/get-started/installation"},{"title":"Which package do I need?","href":"/get-started/which-package"}]},{"group":"Concepts","pages":[{"title":"Gasless on Stellar","href":"/concepts/gasless-on-stellar"},{"title":"Account models","href":"/concepts/account-models"},{"title":"Prepare -> Sign -> Send","href":"/concepts/prepare-sign-send"},{"title":"Facilitator and BFF","href":"/concepts/facilitator-and-bff"},{"title":"Networks","href":"/concepts/networks"}]},{"group":"Signers","pages":[{"title":"Signers","href":"/signers/overview"},{"title":"Wallets Kit","href":"/signers/wallets-kit"},{"title":"Passkey","href":"/signers/passkey"},{"title":"Social login","href":"/signers/social-login"},{"title":"Email OTP","href":"/signers/email-otp"},{"title":"Native passkey","href":"/signers/native-passkey"}]},{"group":"Features","pages":[{"title":"Feature coverage","href":"/features/index"},{"title":"Gasless modes","href":"/features/gasless-modes"},{"title":"Gas in token","href":"/features/gas-in-token"},{"title":"Atomic batch","href":"/features/atomic-batch"},{"group":"Sessions","pages":[{"title":"Sessions","href":"/features/sessions/overview"},{"title":"Spend limit policy","href":"/features/sessions/spend-limit"},{"title":"Allowlist policy","href":"/features/sessions/allowlist"}]},{"title":"Onboarding","href":"/features/onboarding"},{"title":"Swaps","href":"/features/swaps"}]},{"group":"Platforms","pages":[{"title":"Platforms","href":"/platforms/index"},{"title":"Web - @buckspay/react","href":"/platforms/web-react"},{"title":"React Native - @buckspay/react-native","href":"/platforms/react-native"},{"title":"Node / Core - @buckspay/core","href":"/platforms/node-core"},{"title":"Next.js BFF - @buckspay/nextjs","description":"App Router route factories that keep the facilitator API key and provider secrets server-side behind same-origin BFF routes.","href":"/platforms/nextjs-bff"}]},{"group":"Production","pages":[{"title":"Mainnet cutover runbook","href":"/production/mainnet-cutover"},{"group":"Security","pages":[{"title":"Threat model","description":"STRIDE-style analysis of the six security surfaces in the Buckspay SDK.","href":"/production/security/threat-model"},{"title":"Audit prep","href":"/production/security/audit-prep"},{"title":"Secret rotation runbook","href":"/production/security/secret-rotation"},{"title":"Contract provenance","href":"/production/security/contract-provenance"},{"title":"Key handling","href":"/production/security/key-handling"}]},{"title":"Versioning and migration","href":"/production/versioning-and-migration"}]}]},{"tab":"SDK Reference","pages":[{"title":"SDK Reference","href":"/sdk-reference/core/src"}]},{"tab":"API Reference","pages":[{"title":"API Reference","href":"/api-reference"}]}]},"basePath":"","title":"Mainnet cutover runbook - Buckspay SDK","buildId":"dpl_596ePT575z4qnAFksq1biRW97aLY","deploymentId":"dpl_596ePT575z4qnAFksq1biRW97aLY","dynamics":[],"chunks":[]}