Description
The audit log system in crates/api/src/audit.rs currently records wallet, withdrawal, and auth actions. Gas sponsorship introduces three new auditable categories:
- Sponsorship configuration changed (enabled/disabled, fee cap or budget updated).
- A sponsored transaction was submitted (with outcome: confirmed or failed).
- Sponsorship rejected due to policy (invalid XDR, forbidden op type, budget exceeded).
Every one of these events must appear in the audit log so account owners can review exactly when and by whom gas sponsorship was used or misconfigured.
Requirements and Context
- Add a new
SPONSORSHIP constant to the audit category list in crates/api/src/audit.rs (alongside the existing WITHDRAWAL, WALLET, etc.).
- All three event types must capture:
user_id (derived from the API key's wallet owner), ip_address (from request headers), action string (human-readable), category: SPONSORSHIP, and target (set to the wallet_id).
- For rejected requests (bad XDR, budget exceeded) the audit entry must be recorded even though the HTTP response is an error — so abuse attempts leave a trail.
- The
record function signature in crates/api/src/audit.rs already accepts these fields; no new Store methods are needed.
Suggested Execution
Branch: feat/gas-sponsorship/audit-logging
Implement Changes
- Add to
crates/api/src/audit.rs:
pub mod category {
pub const SPONSORSHIP: &str = "sponsorship";
// existing constants remain unchanged
}
- In
crates/api/src/routes/sponsor.rs, call crate::audit::record for:
- Successful submission:
"sponsored a transaction (confirmed)" or "sponsored a transaction (failed)".
- Policy rejection:
"sponsor request rejected: <reason>" where reason is one of xdr_invalid, op_not_allowed, budget_exceeded, sponsorship_disabled.
- In
crates/api/src/routes/sponsorship.rs, call crate::audit::record on every successful PUT: "updated sponsorship config (enabled: <true|false>)".
- Audit recording is best-effort — wrap each call in the existing
let _ = ... pattern so failures never propagate to the caller.
Test and Commit
- Tests in
crates/api/tests/api_tests.rs:
audit_records_sponsorship_config_change — PUT sponsorship config; query audit logs for category sponsorship and assert the action string is present.
audit_records_rejected_sponsor_request — send invalid XDR; assert a sponsor request rejected: xdr_invalid log entry was created.
audit_records_confirmed_sponsored_tx — run the happy path; assert a sponsored a transaction (confirmed) entry.
- Run
cargo test -p octo-api.
Example Commit Message
feat(api): add SPONSORSHIP audit log category and record all sponsor events
Records config changes, submission outcomes, and policy rejections in the
audit log. Rejected requests also generate entries so abuse attempts are
always traceable.
Guidelines
- The audit entry for a rejected request must be recorded before returning the error response.
- Do not log the raw XDR in the audit action string — it may be large; log the inner tx hash if available after parsing, otherwise just the rejection reason.
- Reference this issue with
Closes #<issue-number> in the PR description.
Description
The audit log system in
crates/api/src/audit.rscurrently records wallet, withdrawal, and auth actions. Gas sponsorship introduces three new auditable categories:Every one of these events must appear in the audit log so account owners can review exactly when and by whom gas sponsorship was used or misconfigured.
Requirements and Context
SPONSORSHIPconstant to the audit category list incrates/api/src/audit.rs(alongside the existingWITHDRAWAL,WALLET, etc.).user_id(derived from the API key's wallet owner),ip_address(from request headers),actionstring (human-readable),category: SPONSORSHIP, andtarget(set to thewallet_id).recordfunction signature incrates/api/src/audit.rsalready accepts these fields; no new Store methods are needed.Suggested Execution
Branch:
feat/gas-sponsorship/audit-loggingImplement Changes
crates/api/src/audit.rs:crates/api/src/routes/sponsor.rs, callcrate::audit::recordfor:"sponsored a transaction (confirmed)"or"sponsored a transaction (failed)"."sponsor request rejected: <reason>"where reason is one ofxdr_invalid,op_not_allowed,budget_exceeded,sponsorship_disabled.crates/api/src/routes/sponsorship.rs, callcrate::audit::recordon every successful PUT:"updated sponsorship config (enabled: <true|false>)".let _ = ...pattern so failures never propagate to the caller.Test and Commit
crates/api/tests/api_tests.rs:audit_records_sponsorship_config_change— PUT sponsorship config; query audit logs for categorysponsorshipand assert the action string is present.audit_records_rejected_sponsor_request— send invalid XDR; assert asponsor request rejected: xdr_invalidlog entry was created.audit_records_confirmed_sponsored_tx— run the happy path; assert asponsored a transaction (confirmed)entry.cargo test -p octo-api.Example Commit Message
Guidelines
Closes #<issue-number>in the PR description.