feat: optimize registry serialization and sep12 upload flow#675
Open
success-OG wants to merge 1 commit into
Open
feat: optimize registry serialization and sep12 upload flow#675success-OG wants to merge 1 commit into
success-OG wants to merge 1 commit into
Conversation
|
@success-OG 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! 🚀 |
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
This PR delivers four related improvements across the AnchorPoint registry contract and SEP-12 backend: lower on-chain storage cost for registry data, a testable storage-provider initialization layer, support for pre-signed upload references in KYC submission, and continued support for legacy multipart file uploads.
Closes #568
closes #560
closes #555
closes #556
Task 1 — Optimize Gas Consumption in Registry Contract Serialization (#568)
Problem
The registry contract stored ContractInfo with redundant and inefficient serialization. contract_type was saved inside every record even though it is already the storage map key (DataKey::Contract(contract_type)). Field order was also not optimized for Soroban XDR encoding.
Solution
Introduced StoredContractInfo for on-chain persistence with a gas-friendly layout:
Fixed-size fields grouped first: address, previous_version, deployed_at, active
Variable-length version string last
contract_type removed from stored data
Kept public ContractInfo for query APIs, rehydrating contract_type from the lookup key when reading
Updated all write paths (register_contract, activate_contract, deactivate_contract) to persist StoredContractInfo
Updated all read paths (get_contract, get_active_contracts, get_upgrade_history) to map stored data back to ContractInfo
Why this matters
Less data written per registration/update means lower gas cost on Soroban, with no change to external query behavior.
Files changed
contracts/registry/src/lib.rs
How to test
cargo check --manifest-path contracts/Cargo.toml
cd contracts/registry && cargo test
Task 2 — Unit Tests for StorageProvider Initialization (#560)
Problem
StorageProvider only had a basic mock implementation. There was no factory, no config validation, and no tests for initialization failures.
Solution
Added StorageProviderConfig, StorageProviderError, and validateStorageProviderConfig()
Added createStorageProvider() factory supporting:
mock — in-memory provider for dev/test
s3 — requires bucket + region
gcs — requires bucket
Added storageConfigFromEnv() to build config from environment variables
Implemented S3StorageProvider and GcsStorageProvider with constructor-time validation
Added storage-provider.service.test.ts with 15 tests covering:
Valid mock/S3/GCS configs
Missing provider
Unsupported provider
Missing bucket
Missing S3 region
Factory creation
Env parsing
Mock provider URL generation and upload tracking
Why this matters
Storage backend selection now fails fast with clear errors before runtime upload operations, and behavior is covered by unit tests.
Files changed
backend/src/services/storage-provider.service.ts
backend/src/services/storage-provider.service.test.ts
Task 3 — Integrate upload-ids into PUT /sep12/customer (#555)
Problem
Clients could request pre-signed upload URLs and confirm uploads, but PUT /sep12/customer did not accept upload references. KYC submission only supported direct multipart file uploads.
Solution
Added resolveCustomerDocuments() in Sep12Controller
Clients can submit document references using fields named {field_name}_upload_id
Example: id_photo_front_upload_id: ""
For each upload ID, the handler:
Loads the record from uploadStore
Returns 400 if missing, expired, or not COMPLETED
Returns 403 if the upload belongs to a different account
Resolves the record to its storageKey
Resolved storage keys are passed to kycProvider.submitCustomer() and stored in encrypted extraFields
Upload ID fields are stripped from normal KYC payload fields
Improved upload URL flow to persist storageKey via uploadStore.setStorageKey()
Example request
PUT /sep12/customer
{
"account": "G...",
"first_name": "Jane",
"last_name": "Doe",
"id_photo_front_upload_id": "completed-upload-uuid"
}
Files changed
backend/src/api/controllers/sep12.controller.ts
backend/src/services/upload-store.service.ts
Task 4 — Maintain Backward Compatibility for Multipart Form-Data Uploads (#556)
Problem
Introducing upload IDs must not break existing clients that still upload files directly through Multer.
Solution
Kept existing route: PUT /sep12/customer with upload.any() middleware
resolveCustomerDocuments() supports both paths:
New path: {field}_upload_id → cloud storageKey
Legacy path: multipart file → local file path
If both are provided for the same field, upload ID wins and the multipart file is ignored
Both paths produce the same downstream behavior:
Same submitCustomer() document map shape
Same encrypted DB payload structure
Same 202 PROCESSING response