Skip to content

feat: optimize registry serialization and sep12 upload flow#675

Open
success-OG wants to merge 1 commit into
ceejaylaboratory:mainfrom
success-OG:feat/reset
Open

feat: optimize registry serialization and sep12 upload flow#675
success-OG wants to merge 1 commit into
ceejaylaboratory:mainfrom
success-OG:feat/reset

Conversation

@success-OG

Copy link
Copy Markdown

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

@drips-wave

drips-wave Bot commented Jun 27, 2026

Copy link
Copy Markdown

@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! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant