Instawards: pay_batch SAC settlement, Ed25519 oracle hardening, Bulk Pay dashboard - #5
Merged
Merged
Conversation
…, Bulk Pay UI Deliverables 1-3 of the Instawards sprint, validated on Stellar Testnet. Contract (D1 - token transfer integration): - PaymentSchedule gains `token: Address`, so one batch settles multiple assets (USDC + native XLM proven on Testnet). CoreFlowEscrow.token removed. - Custody funds and refunds per distinct asset: one transfer per token rather than one per payee. - `pay_batch` replaces `finalize_payment`, which is retained as a delegating alias so the live Mainnet ABI and existing dashboard client keep working. Contract (D2 - oracle verification): - `verify_oracle_work` / `track_nonce` extracted. Signature is now verified BEFORE the nonce is consumed; previously a garbage signature could burn an escrow's nonce sequence. - `pay_batch` returns ProofMissing unless every payment carries a verified oracle attestation. Both approvals could previously settle a batch with zero attestations, so the "funds move only against proof of work" property was procedural rather than enforced. - `rotate_oracle_key` revokes previously verified proofs, since a rotation implies the retired key may be compromised. - `SignersNotDistinct` rejects manager == finance_approver at creation and at settlement; identical signers made the dual-approval gate vacuous. Build (blocking, pre-existing): - rust-toolchain.toml pins 1.85.0. soroban-sdk 20.5.0 fails to compile on newer rustc (ethnum E0512) and fails to resolve on older cargo (zeroize edition2024). - Target moved to wasm32v1-none. wasm32-unknown-unknown under 1.85 emits reference-types and the Soroban host rejects the upload with Error(WasmVm, InvalidAction). The contract was undeployable before this. Tooling and dashboard (D3): - scripts/oracle-cli.mjs signs the 32-byte per-payment message the contract reconstructs, one signature per payee with sequential nonces. - scripts/generate-testnet-batches.mjs drives full lifecycles for bulk validation. - /bulk-pay: CSV upload, payee preview, role-based dual signing. Approval badges read on-chain state via get_escrow rather than local React state, which would show green without any on-chain approval. - /api/submit-batch returns oracle signatures from the live nonce watermark. CI: - Adds a Rust job (cargo test --locked + wasm32v1-none build). No Rust test has ever run in CI. Trigger extended to instawards/** or the branch never builds. Tests: 40 Rust (was 29), 79 TypeScript. Cross-language conformance test asserts CLI signature bytes are accepted on-chain. Testnet evidence: docs/evidence/TESTNET_VALIDATION.md, 50 hashes in docs/evidence/all_50_hashes.txt. Contract: CCVIQZLSJIPSCFH2QGPKN5IOAA5ZQ4DOD4HLBZFMYKXPRAMCIOZGFJDF Not validated: the Freighter signing path has never been executed in a browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Deliverables 1–3 of the 30-day Instawards sprint, validated on Stellar Testnet.
Contract:
CCVIQZLSJIPSCFH2QGPKN5IOAA5ZQ4DOD4HLBZFMYKXPRAMCIOZGFJDFReviewer evidence
docs/evidence/TESTNET_VALIDATION.mddocs/evidence/all_50_hashes.txtdocs/DEVELOPER_GUIDE.mddocs/evidence/DEMO_VIDEO_CHECKLIST.mdRepresentative transactions:
pay_batch— USDC + XLM in one transactionpay_batch— dual-signed by two distinct keysfinance_approve— separate finance keyrotate_oracle_keyD1 — Token transfer integration
PaymentSchedulecarries a per-payeetoken: Address, so one batch settles multiple assets. Custody is funded and refunded per distinct asset (one transfer per token, not per payee).pay_batchreplacesfinalize_payment, which remains as a delegating alias so the live Mainnet ABI and existing client keep working.Verified on Testnet: custody funded with two transfers (500000000 USDC + 100000000 native), settled with two transfers, custody drained to
0in both assets.D2 — Ed25519 oracle verification
pay_batchreturnsProofMissingunless every payment carries a verified attestation. Both approvals could previously settle a batch with zero oracle attestations — the "funds move only against proof of work" property was procedural, not enforced.rotate_oracle_keyrevokes previously verified proofs, since rotation implies the retired key may be compromised.SignersNotDistinctrejectsmanager == finance_approverat creation and settlement.scripts/oracle-cli.mjssigns the 32-byte per-payment message, one signature per payee with sequential nonces.D3 — Bulk Pay dashboard
/bulk-pay: CSV upload, payee preview, role-based dual signing, transaction status.Approval badges read on-chain state via
get_escrow, not React state.manager_approveandfinance_approveare separate on-chain transactions; local state would render green with no on-chain approval and settlement would fail with#5.Build fix (was blocking, pre-existing)
The contract could not be deployed at all before this PR:
rustc 1.85 emits reference-types into
wasm32-unknown-unknown. Fixed by targetingwasm32v1-none.rust-toolchain.tomlpins 1.85.0 — the only version that works, since soroban-sdk 20.5.0 fails to compile on newer rustc (ethnumE0512) and fails to resolve on older cargo (zeroizeedition2024).CI
Adds a Rust job (
cargo test --locked+wasm32v1-nonebuild). No Rust test has ever run in CI. Trigger extended toinstawards/**, without which this branch never builds.Tests
Includes a cross-language conformance test asserting the CLI's signature bytes are accepted on-chain, so encoding drift fails in CI rather than as an opaque Testnet rejection.
Not yet done
#5,#15, retired-key rejection) are simulation-rejected and have no on-chain hashes — reviewers reproduce them by re-running the documented commands.ESCROW_IDis hardcoded in/bulk-pay; should become a selector.🤖 Generated with Claude Code