Repository navigation
Port Spender program into Bridge Cards - #43
Closed
Brennan Lamey (brennanjl) wants to merge 13 commits into
Closed
Brennan Lamey (brennanjl) wants to merge 13 commits into
Brennan Lamey (brennanjl) wants to merge 13 commits into
Conversation
Adds spender's delegation model directly to bridge-cards, eliminating
the need for a separate spender program or a CPI bridge.
New state (seed "spender_state", separate from BridgeCardsState):
- SpenderState: governor, manager, debitor, pauser, paused
New PDAs:
- MerchantDelegateState [merchant_delegate, merchant_id:[u8;32]]
- DelegateDestinationState [merchant_destination, merchant_id:[u8;32], ata]
New instructions:
- initialize_spender_state, update_{governor,manager,debitor,paused,pauser}
- setup_merchant_delegate (bulk-init destinations via remaining accounts)
- add_delegate_destination, close_delegate_destination
- transfer_using_single_delegate: SPL-approve-based transfer
- transfer_using_subscription_delegate: fixed/recurring delegation CPI
Also upgrades Anchor 0.31 → 1.0 and Rust 1.85 → 1.89 (required by
subscriptions crate's transitive Solana SDK 3.x dependencies). Existing
debit_user and add_or_update_* instructions are unchanged.
The integration test crate compiles but requires further migration from
litesvm 0.6→0.12 APIs; library unit tests (7) all pass.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
- Replace litesvm_token::spl_token_2022::id() with anchor_spl::token_2022::ID - Replace litesvm_token::spl_token_2022::state::Account with spl_token::state::Account (safe for non-extended accounts; same on-chain layout) - Remove spl-token-2022 v5 dep (zeroize conflict with litesvm); use anchor_spl re-export instead All 46 integration tests and 7 unit tests pass. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
…ntrol fix - Add transfer_using_legacy_delegate: bridges old user-delegate PDAs with new global access control; validates destination via spender-style allowlist, init_if_needed on UserDelegateState, IS pausable, no velocity controls - Fix update_paused: pauser/admin/governor can pause; only admin/governor can unpause - Fix debit_user: remove velocity checks (validate_debit_and_update); keep exact account interface and mut constraint for prod continuity; note it is not pausable - Add update_spender_admin: two-party admin rotation for SpenderState - Add LegacyDelegateTransfer and SpenderAdminUpdated events - Add Unauthorized error code Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Groups instructions that should not be used for new work (debit_user, initialize, add_or_update_*, update_admin, close_account) into a legacy/ submodule. All still re-exported at the crate level so existing behavior is unchanged; 46 tests pass. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Documents what is net-new vs. ported vs. legacy, the two access control systems, state accounts, transfer paths side by side, migration steps, and Anchor version upgrade notes. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Replaces the program-keypair signer check with a constraint that the existing BridgeCardsState admin signs. This ties SpenderState bootstrap to the party already in control of the program, preventing an unauthorized actor from initializing the new role hierarchy. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Reflects new dual-system architecture: spender role hierarchy alongside legacy path, updated PDA table, transfer path comparison table, removed velocity controls section, links to SPENDER_MIGRATION.md. Client integration code unchanged (user approval flow is the same). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
MEDIUM: Add legacy_merchant_id to MerchantDelegateState - setup_merchant_delegate now accepts legacy_merchant_id: u64 (0 = no legacy binding) - transfer_using_legacy_delegate validates merchant_delegate_state.legacy_merchant_id == merchant_id preventing a compromised debitor from routing a user's approval for Merchant A to destinations allowlisted under Merchant B Event: add admin to SpenderStateInitialized so off-chain indexers can reconstruct the initial admin without a separate source Tests (54 total, all passing): - transfer_using_legacy_delegate: success, init_if_needed, cross-merchant attack blocked, wrong debitor rejected, paused rejected - update_paused: admin can pause/unpause, pauser can pause but not unpause, stranger cannot pause - debit_user: update velocity-control tests to reflect removal of those checks Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Derives the SpenderState PDA inline in the legacy handler and rejects any attempt to close it, preventing the BridgeCardsState admin from accidentally or maliciously bricking the spender system. Adds test to confirm the guard fires. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
1. setup_merchant_delegate: track only newly-initialized destinations in event. Previously re-iterated all chunks post-loop, so skipped (already-initialized) destinations appeared in initial_destinations of MerchantDelegateAdded. 2. legacy/close_account: fix lamport ordering regression and add self-closure guard. Save lamports in local before zeroing; zero source before adding to recipient. Add constraint account_to_close != payer to prevent self-closure that would leave the account with empty data but non-zero lamports. 3. transfer_using_single_delegate + transfer_using_legacy_delegate: guard against receiver_ata == user_ata. A self-transfer is a no-op on balance but drains the SPL delegate allowance and emits a zero-amount event. New SelfTransfer error. 4. add_delegate_destination: init_if_needed -> init. Re-calling for an already- allowlisted destination now fails explicitly instead of silently emitting a duplicate DelegateDestinationAdded event that confuses indexers. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Mirrors the check already present in transfer_using_single_delegate and transfer_using_legacy_delegate. A debitor passing the same account for delegator_ata and receiver_ata would drain the subscription allowance without moving funds. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Consistent with every other update_* instruction that validates the incoming role address against Pubkey::default(). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
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.
Upgrade Bridge Cards Solana program to inherit Spender Program functionality while keeping debit_user running without downtime. See investigation 2c9b8501 for full design notes.