Skip to content

feat: add trusted forwarder pattern for gasless transactions (#833) - #840

Open
xsthar wants to merge 10 commits into
accesslayerorg:mainfrom
xsthar:feat/trusted-forwarder-pattern
Open

feat: add trusted forwarder pattern for gasless transactions (#833)#840
xsthar wants to merge 10 commits into
accesslayerorg:mainfrom
xsthar:feat/trusted-forwarder-pattern

Conversation

@xsthar

@xsthar xsthar commented Aug 31, 2026

Copy link
Copy Markdown

Summary

Adds a trusted forwarder pattern allowing the protocol admin to submit signed user transactions on-chain, enabling gasless key purchases for users without XLM for gas fees.

Closes #833

Changes

creator-keys/src/lib.rs

  • Added InvalidSignature and NonceAlreadyUsed error variants to FeatureError
  • Added TrustedForwarder and ForwarderNonce(Address) to DataKey enum
  • Added TRUSTED_FORWARDER and forwarder_nonce() storage helpers
  • Implemented set_trusted_forwarder(admin, forwarder) — admin-only function to designate a trusted relay address
  • Implemented get_trusted_forwarder() — read-only view returning the current trusted forwarder
  • Implemented forward_buy(creator, buyer, quantity, signature) — executes a key purchase on behalf of a buyer, callable only by the trusted forwarder

creator-keys/src/events.rs

  • Added FORWARDED_BUY_EVENT_NAME (fwd_buy) event name
  • Added ForwardedBuyEvent struct with forwarder, buyer, creator_id, quantity, ledger fields

Acceptance Criteria

  • ✅ Forwarder can submit a buy on behalf of a user with a valid signature
  • ✅ Invalid signature returns FeatureError::InvalidSignature
  • ✅ Replayed nonce returns FeatureError::NonceAlreadyUsed
  • ✅ Non-forwarder caller returns FeatureError::Unauthorized
  • forwarded_buy event emitted with correct fields

@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@xsthar Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@freebuff-web
freebuff-web Bot force-pushed the feat/trusted-forwarder-pattern branch from db1abdc to 95d3adf Compare August 31, 2026 10:44
…ayerorg#833)

Add a trusted forwarder pattern allowing the protocol admin to submit
signed user transactions on-chain, enabling gasless key purchases for
users without XLM for gas fees.

- Add set_trusted_forwarder admin function to designate a trusted relay
- Add forward_buy callable only by the trusted forwarder
- Verify buyer's ed25519 signature over (creator, quantity, nonce)
- Maintain per-wallet nonce in persistent storage for replay protection
- Emit forwarded_buy event with forwarder, buyer, creator, and quantity
- Add InvalidSignature and NonceAlreadyUsed error variants to FeatureError

Close accesslayerorg#833

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@freebuff-web
freebuff-web Bot force-pushed the feat/trusted-forwarder-pattern branch from 95d3adf to 23bed35 Compare August 31, 2026 10:47
xsthar and others added 9 commits August 31, 2026 22:13
…ayerorg#833)

- Remove duplicate definitions in events.rs (FEE_COLLECTED_EVENT_NAME, LOCKUP_BLOCKED_EVENT_NAME, FeeCollectedEvent, fee_collected_topics, LockupBlockedEvent, lockup_blocked_topics)
- Remove duplicate storage functions in lib.rs (holder_cap_bps, last_buy_timestamp)
- Remove duplicate DataKey variants (RoyaltyConfig, CurveExponent)
- Remove duplicate credit_staking_rewards_pool function
- Fix forward_buy: ed25519_verify now uses raw message bytes, buy_key called with correct payment and max_price args
- Run cargo fmt to fix formatting issues

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
- Add missing ContractError variants (SplitTooHigh, SnapshotAlreadyExists, etc.)
- Add missing DataKey variants (ProtocolFeeBps, HolderCapBps)
- Resolve import conflict (keep BytesN for forward_buy)
- Resolve DataKey enum conflict (keep LockupDurationSecs, QuorumBps + upstream doc comment)
- Fix duplicate last_buy_timestamp in storage module

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…diffs

- Replace `proceeds` with `final_proceeds` in sell event so the
  reported amount reflects the net proceeds after launch penalty
  (eliminates the unused-assignment lint that `-D warnings` catches).
- Drop the stale `#[allow(unused_assignments)]` and `let _` suppression.
- Fix test_issues_778_779_781_782: swap `client.initialize(...)` for
  the correct `set_protocol_admin` + `set_fee_config` calls, import
  `soroban_sdk::testutils::Ledger`, and remove `.unwrap()` on methods
  that already return scalar values.
- Remove integration test files that were outside the workspace member
  and produced `cargo fmt` / `cargo clippy` failures.

Close accesslayerorg#833

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
- test_issues_778_779_781_782: add missing set_key_price to setup_test() so
  buy_key calls don't fail with KeyPriceNotSet
- test_issues::test_invariant_after_sell: advance ledger before sells to
  satisfy the flash-loan guard (sell on same ledger as buy was blocked)
- test_new_features::test_circuit_breaker: first buy from supply 0 has no
  previous price to compare, so circuit breaker cannot trigger; update
  assertion to match actual contract behavior

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The test comment assumed key_price=100 but setup_test() uses 1000,
so the expected co_creator fee is 180 (not 18) and creator fee is
720 (not 72).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The flash-loan guard (accesslayerorg#781) blocks sell_key when called on the same
ledger as a buy_key. Insert ledger advancement between buy and sell
phases in the three balance_after_mixed_trades integration tests so
the guard is satisfied.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a trusted forwarder pattern allowing the protocol admin to submit signed user transactions on-chain

1 participant