Skip to content

feat(salary): implement batch update for employee salary commitments - #40

Open
sudo-robi wants to merge 5 commits into
zkpayroll:mainfrom
sudo-robi:feat/salary-commitment-batch
Open

feat(salary): implement batch update for employee salary commitments#40
sudo-robi wants to merge 5 commits into
zkpayroll:mainfrom
sudo-robi:feat/salary-commitment-batch

Conversation

@sudo-robi

Copy link
Copy Markdown
Contributor

feat(salary): implement batch update of commitments

Summary

This PR introduces the batch_update_commitments entrypoint to the salary_commitment contract. For companies with numerous employees, issuing individual transactions to update each salary commitment was inefficient. This allows an admin to update multiple employee salary commitments in a single transaction by passing a batch array, significantly reducing network transaction overhead and fee consumption.

Closes #

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing behaviour)
  • ZK circuit change (requires new trusted setup / ptau ceremony)
  • Refactor (no functional changes)
  • Documentation / comments only
  • CI/CD or tooling change

Description of Changes

  • salary_commitment/src/lib.rs: Added the batch_update_commitments entrypoint which iterates over a vector of (Address, BytesN<32>).
  • Storage: Updates existing DataKey::Commitment(employee) storage slots. For each valid update, it saves the new hash, assigns the current ledger timestamp to updated_at, and increments the commitment version.
  • Validation: Enforces strict existence checks. If any employee in the batch array does not have a preexisting commitment, the entire batch transaction aggressively panics and reverts with "Commitment not found".
  • Cargo.toml: Exported the testutils feature natively to allow upstream workspace testing.
  • Tests: Added comprehensive unit tests targeting both the happy path (test_batch_update_commitments) and the failure bounds (test_batch_update_fails_if_missing).

Checklist

General

  • My code follows the project's Rust style guidelines (cargo fmt --check passes)
  • I have performed a self-review of my own code
  • I have added comments for any non-obvious logic
  • I have updated relevant documentation (README.md, CONTRIBUTING.md, inline docs)
  • My changes do not introduce new compiler warnings (cargo clippy passes)
  • I have added tests that cover my changes
  • All existing tests pass locally (cargo test)

Smart Contracts (if applicable)

  • I have measured and documented gas / resource usage for new or changed entry-points
    • CPU instructions (before / after):
    • Memory bytes (before / after):
    • Ledger entries read/written (before / after):
    • Estimated XLM fee (before / after):
  • I have verified there are no storage layout regressions (state rent impact assessed)
  • I have checked for integer overflow / underflow and used checked arithmetic
  • Authorization checks (require_auth, require_auth_for_args) are correct and tested
  • No sensitive data (salaries, blinding factors, private keys) is emitted in events or exposed in storage

ZK Circuits (if applicable)

  • Circuit compiles without errors: circom <circuit>.circom --r1cs --wasm --sym
  • Witness generation succeeds for test inputs
  • Proof generation and verification pass end-to-end
  • New trusted setup (phase 2 ptau) is required: Yes / No
    • If yes, link to the ceremony artifacts:
  • Constraint count change documented:
    • Before:
    • After:
  • Verifier Solidity/Rust contract regenerated (if verifying key changed)

Security

  • I have considered potential attack vectors relevant to this change
    • Re-entrancy (not applicable on Soroban, but noted for audit completeness)
    • Front-running / MEV risks
    • Proof malleability (for ZK changes)
    • Commitment binding / hiding properties preserved (for commitment changes)
  • No hardcoded secrets, keys, or sensitive configuration values in code
  • Dependencies added/updated have been reviewed for known vulnerabilities (cargo audit)

Testing Evidence

cargo test -p salary_commitment --features testutils



running 4 tests
test tests::test_store_commitment ... ok
test tests::test_nullifier ... ok
test tests::test_update_commitment ... ok
test tests::test_double_nullifier_fails - should panic ... ok
test tests::test_batch_update_commitments ... ok
test tests::test_batch_update_fails_if_missing - should panic ... ok

test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s


- Added batch_update_commitments entrypoint iterating over a vector of (Address, BytesN<32>) to avoid multiple transaction calls.
- Updated Cargo.toml to add 'testutils' feature.
- Added comprehensive unit tests test_batch_update_commitments and test_batch_update_fails_if_missing.
Copilot AI review requested due to automatic review settings February 26, 2026 07:54
@drips-wave

drips-wave Bot commented Feb 26, 2026

Copy link
Copy Markdown

Hey @sudo-robi! 👋 It looks like this PR isn't linked to any issue.

If this PR is for one of the issues assigned to you as part of a Wave, please link it to ensure your contribution is tracked properly. You can do this by adding a keyword to the PR description (e.g., Closes #123), or by clicking a button below:

Issue Title
#22 [Contract] Implement payment_executor: Batch Process Payroll Execution Link to this issue
#28 [Circuits] Implement Circuit compilation and trusted setup scripts Link to this issue
#19 [Contract] Implement salary_commitment: Batch update of commitments Link to this issue
#8 [Testing] Security: Rate limiting and reentrancy checks on payment execution Link to this issue

ℹ️ Learn more about linking PRs to issues

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new batch entrypoint to the salary_commitment Soroban contract to update multiple employees’ commitment hashes in a single transaction, reducing per-employee transaction overhead.

Changes:

  • Introduces batch_update_commitments that iterates through (Address, BytesN<32>) updates and persists new commitment data while bumping version.
  • Adds unit tests for the batch happy path and the missing-commitment failure case.
  • Exposes a crate-level testutils feature to enable soroban-sdk/testutils for upstream/workspace testing.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
contracts/salary_commitment/src/lib.rs Adds the batch update entrypoint and corresponding unit tests.
contracts/salary_commitment/Cargo.toml Exposes a testutils feature for consumers/tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread contracts/salary_commitment/src/lib.rs Outdated
Comment on lines +79 to +83
/// Batch update existing salary commitments
pub fn batch_update_commitments(
env: Env,
updates: soroban_sdk::Vec<(Address, BytesN<32>)>,
) {

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

batch_update_commitments performs privileged state changes but does not enforce any authorization. The PR description says an admin should be able to update multiple employees in one transaction, but as written any caller can update any employee’s commitment hashes. Add an auth check (e.g., require auth from an admin/owner address stored in contract state, or otherwise gate updates) and cover the unauthorized case in tests.

Copilot uses AI. Check for mistakes.
Comment on lines +94 to +97
existing.commitment = new_commitment;
existing.updated_at = timestamp;
existing.version += 1;

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

existing.version += 1 can overflow (and this workspace enables overflow-checks = true in release), which would abort the transaction once the counter reaches u32::MAX. Use checked arithmetic and a clear failure mode (or widen the type) so versioning can’t unexpectedly trap.

Copilot uses AI. Check for mistakes.
Comment on lines +240 to +261
#[test]
#[should_panic(expected = "Commitment not found")]
fn test_batch_update_fails_if_missing() {
let env = Env::default();
let contract_id = env.register_contract(None, SalaryCommitmentContract);
let client = SalaryCommitmentContractClient::new(&env, &contract_id);

let emp_valid = Address::generate(&env);
let emp_missing = Address::generate(&env);

client.store_commitment(&emp_valid, &BytesN::from_array(&env, &[1u8; 32]));

let updates = soroban_sdk::Vec::from_array(
&env,
[
(emp_valid.clone(), BytesN::from_array(&env, &[10u8; 32])),
(emp_missing.clone(), BytesN::from_array(&env, &[20u8; 32])),
]
);

client.batch_update_commitments(&updates);
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_batch_update_fails_if_missing asserts the panic message, but it doesn’t verify the key behavioral guarantee described in the PR (“entire batch transaction … reverts”). Add an assertion after the failed call (e.g., re-read emp_valid’s commitment) to ensure no partial update is persisted when one element in the batch is missing.

Copilot uses AI. Check for mistakes.

@romeoscript romeoscript left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI workflow is currently failing due to cargo fmt. Please run cargo fmt locally to format the code correctly and push the changes:

cargo fmt

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

@sudo-robi this PR currently has merge conflicts.

Please resolve the conflicts before it can be merged automatically.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants