# Partial Settlement: Vouchers ## Purpose `settle` lets a provider receive client-authorized partial payment before the job is finally completed. It is intended for long-running or milestone-based jobs where the client wants to release value incrementally without closing the job. The goal is to standardize the release and accounting primitive, not to lock ACP into one static fee model. Fee handling can remain ACP-native, receiver-managed, or integration-specific as long as the settlement amount and escrow accounting semantics are clear. ## Function Shape ```solidity settle(jobId, cumulativeAmount, voucherSig, optParams) ``` The provider submits a client-signed voucher authorizing the cumulative gross amount that may have been settled for the job so far. ## Required Semantics - Only the provider can call `settle`. - The job must already be funded and still active. - The job must not be expired. - The voucher must be signed by the client. - `cumulativeAmount` must increase monotonically. - Any voucher with `cumulativeAmount <= settledAmount` must be rejected. This makes previously signed smaller amounts stale once a higher cumulative settlement has been executed. - `cumulativeAmount` must not exceed the job budget. - The job remains active after settlement; `settle` does not complete or close the job. ## Accounting Model `settledAmount` tracks the cumulative gross amount released from escrow. Each settlement pays only the new delta: ```text delta = cumulativeAmount - settledAmount ``` After settlement: ```text settledAmount = cumulativeAmount remainingEscrow = budget - settledAmount ``` Final completion, rejection, and refund flows should operate only on `remainingEscrow`. ## Sequence ```mermaid sequenceDiagram participant C as Client participant AC as ACP participant P as Provider participant E as Evaluator C->>AC: createJob(provider, evaluator, expiry, ...) P->>AC: setBudget(jobId, token, budget, "0x") C->>AC: fund(jobId, budget, "0x") Note over AC: settledAmount = 0 C-->>P: signs Voucher(jobId, cumulativeAmount, optParams) P->>AC: settle(jobId, cumulativeAmount, voucherSig, optParams) Note over AC: verify voucher Note over AC: delta = cumulativeAmount - settledAmount AC->>P: transfer provider net amount Note over AC: settledAmount = cumulativeAmount Note over AC: job remains active P->>AC: submit(jobId, deliverable, "0x") E->>AC: complete(jobId, reason, "0x") Note over AC: releases only budget - settledAmount ``` ## ACP Contract Changes Supporting `settle` requires the core ACP contract to track one new per-job value: ```text settledAmount ``` This value starts at `0` and is updated only by successful settlement. The contract also needs to adjust existing flows: - `complete` should release only `budget - settledAmount`. - `reject` should refund only `budget - settledAmount`. - `claimRefund` should refund only `budget - settledAmount`. - settlement events should expose both the new cumulative amount and the delta paid. - voucher verification should bind the job, cumulative amount, and any settlement-specific parameters. ## Fee Discussion Points The main unresolved policy question is how fees should apply to partial settlement. The goal is customisability: ACP should define when value can be released and how settlement is accounted for, while integrations can choose the fee model that fits their use case. Options under discussion: - reserve evaluator and platform fees upfront, then cap provider settlement against the remaining provider-available budget - charge both evaluator and platform fees pro rata on each settlement delta - charge platform fees pro rata, but defer evaluator fees until final evaluation - charge no fees during partial settlement and apply fees only on final completion