feat: add WALLET_OPERATIONS feature flag for the sunset - #1183
Merged
Merged
Conversation
Gate signup, send, receive and Lightning Address receives behind one
positive flag so the wallet can be wound down on a deadline and single
users can be re-enabled afterwards to withdraw their funds.
- migration: WALLET_OPERATIONS row (enabled, rules {}), restrictive insert
policy on wallet.users, security definer wallet.user_exists helper, and
the GUEST_SIGNUP policy recreated with the same existing-user guard so
it stops locking out existing guests
- client: closed signup page and guarded signup actions, home buttons
disabled with a notice, client middleware on the /send and /receive
route trees, public token claim disabled, marketing CTAs fall back to
login, missing flag rows fall back to defaults
- server: LUD-16 and LUD-06 return a sunset error while the flag is off
- protected layout signs out a new user that the insert policy rejects
and redirects to /home with a message
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Updates to Preview Branch (feat/sunset-feature-flag) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
jbojcic1
approved these changes
Sep 17, 2026
gudnuf
reviewed
Sep 17, 2026
| <Button className="w-full px-7 py-6 text-lg">Send</Button> | ||
| </LinkWithViewTransition> | ||
| <ActionButton to="/send" disabled={!walletOperationsEnabled}> | ||
| Send |
Contributor
There was a problem hiding this comment.
should we be disabling send? I was thinking we just disable receive so that people can still withdraw?
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds one positive feature flag,
WALLET_OPERATIONS, that gates signup, send, receive and Lightning Address receives.true(the default) means the wallet works as today. For the sunset, the flag is switched to "enabled for nobody". Individual users can then be added torules.user_idsso they can log in and withdraw.The flag is positive because the existing rules engine (
wallet.is_feature_enabled) can only turn a flag on for specific users. A negative "SUNSET" flag could not express per-user exemptions.Runbook
Do not use
enabled = falsefor the deadline: flipping it back on later without rules would re-open the wallet for everyone. Lightning Address receives stay off for exempted users too, because the server evaluates the flag without a user.What changes while the flag is off
Signup
/signupshows a closed message and no signup buttons. Login page and login form hide the "Sign up" link.signUpand guest creation inuseAuthActionsthrow aDomainError(guards the action itself).wallet.usersrejects new users. This also covers a first-time Google login, which otherwise creates a wallet through the protected layout. The layout catches the rejection, signs the auth user out and redirects to/homewith a toast.Send and receive
clientMiddlewareon_protected.send.tsxand_protected.receive.tsxredirects every route in those trees to/with a toast. This covers deep links, scan results, contacts, gift cards, transaction "pay again" links and the logged-in token claim page.Lightning Address
/.well-known/lnurlp/:username) and LUD-06 callback return{"status":"ERROR","reason":"Agicash is shutting down and no longer accepts payments."}.Migration notes
supabase/migrations/20260917120000_add_wallet_operations_feature_flag.sqladds the flag row, the insert policy and asecurity definerhelperwallet.user_exists(uuid).on conflict do updatepath, so a plain insert policy also fires for every existing user's login-time upsert. The existingRequire email when GUEST_SIGNUP disabledpolicy has this flaw: withGUEST_SIGNUPoff, existing guest users cannot load the wallet (verified locally). Both policies now pass when the user row already exists. Revert that part if you prefer to keep this PR narrow.publicandanon.Verification
bun run fix:all,bun run typecheck(all packages) andbun run test(133 pass) are green.bun run buildsucceeds, including the prerendered/home.upsert_user_with_accountsRPC (SQLSTATE 42501), exempted new user accepted, existing guest accepted and new guest rejected withGUEST_SIGNUPoff,anoncannot calluser_exists./homeshows only "Log in";/signupshows the closed message;/loginhides the signup link; logged-in home shows the notice with disabled Receive/Send; in-app navigation to/sendredirects to/with the toast.Not included (candidates for the same flag)
Buy (creates a receive invoice through Cash App), internal transfers between own accounts (
/transfer/*), adding Cashu accounts and gift cards, and gift card offers. Each can reuserequireWalletOperationswith one export line per layout route.🤖 Generated with Claude Code