Repository navigation
feat: secondary market trade history, treasury management, and issuer verification contracts - #676
Merged
Conversation
Contributor
✅ PR Ready for ReviewDue to a recent malware incident affecting our repositories, all PRs are required to pass automated security checks before being reviewed for merging. This PR has passed all automated checks:
A maintainer will review and merge this PR shortly. |
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
Three new independent Soroban contracts, each implementing one assigned issue end to end with its own storage, errors, events, and test module, matching the workspace's existing accreditation-registry contract's modular structure.
closes #642
closes #644
closes #645
Changes
#642: contracts/secondary-trade-history, a new contract recording executed secondary market trade prices for invoice fractions. record_trade(invoice_id, price, amount, timestamp), get_price_history(invoice_id, limit) (newest first), get_last_price(invoice_id). Storage is pruned to the most recent 100 trades per invoice. record_trade is gated to a single authorized recorder address (set at initialize, changeable by the admin), since an unrestricted writer would let anyone inject fabricated prices into on-chain price discovery data. Confirmed this is genuinely new functionality by auditing the existing secondary-market and secondary-market-oracle contracts first: secondary-market has no trade-price recording at all, and secondary-market-oracle's existing get_price_history/record_listing_price tracks ask/listing prices (pre-sale), not executed trades, a different concept from what this issue asks for.
#644: contracts/treasury-management, a new contract consolidating protocol fee inflows. receive_fee(source, amount) attributes incoming fees per source; allocate(destination, amount, purpose) is admin-only and records a paginated allocation log; get_treasury_balance() returns the total plus a per-source breakdown (tracked via an explicit known-sources list, since Soroban storage has no key enumeration); get_allocation_history(offset, limit) paginates the log. Confirmed the existing fee-treasury contract is a different, epoch-based batch-distribution design (collect_fee/distribute/get_distribution by epoch) rather than this issue's ad hoc per-source/per-allocation model, so this is genuinely separate functionality, not a duplicate.
#645: contracts/invoice-issuer-verification, a new contract for admin-granted issuer verification badges. grant_verification(admin, issuer_wallet, tier, expiry_timestamp) with three tiers (BasicVerified, EnhancedVerified, Institutional); revoke_verification(admin, issuer_wallet) immediately removes the record so is_verified reflects the revocation in the same transaction; is_verified(issuer_wallet) returns verified/tier/expiry, with an expired verification read-time-evaluated as not verified rather than needing a separate expiry sweep. No existing contract in the workspace implements anything like this.
Test plan
Each contract has its own
src/test.rscovering the happy path, every admin/unauthorized-caller boundary, every documented error condition, and the events each mutating function emits (decoded from their raw XDR topics/data, matching the existing accreditation-registry test's pattern).Ran the real test suite for all three (
cargo test -p <crate>, single-job to accommodate limited local memory): 15/15 passing for invoice-issuer-verification, 12/12 for secondary-trade-history, 13/13 for treasury-management. Also ran a combinedcargo checkacross all three together with zero errors, andcargo fmtto match the workspace's formatting.One real bug was found and fixed during this work, not just a passed-on assumption:
VerificationStatus's initial design usedOption<VerificationTier>for the no-verification case, which failed to compile under#[contracttype](the trait bound ScVal: TryFrom<&Option<VerificationTier>> is not satisfied), since a custom#[repr(u32)]enum doesn't currently round-trip throughOptionin this soroban-sdk version. Restructured to a non-optional tier with a documented sentinel value for the unverified case instead, confirmed working by the full test suite.