EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-8492: Settlement Deductions for Task Escrows

A fixed policy that an escrow asks at every payout how much to withhold for third parties, without being able to stall settlement

Authors
Created2026-11-09
Discussion Linkhttps://ethereum-magicians.org/t/erc-8492-settlement-deductions-for-task-escrows/30323
Requires

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#2157PR open

EIP-GPT summary

Contents
AbstractMotivationSpecification1. Terms2. Conformance3. Policy interface4. Escrow interface5. Escrow requirements6. Policy requirements7. Reference policy profile (OPTIONAL)RationaleBackwards CompatibilityTest CasesReference ImplementationSecurity ConsiderationsCopyright

Abstract

This ERC lets an escrow that pays for work withhold part of each payout for third parties (a tax, a referral fee, a loan repayment) without knowing any of their rules, and without letting any of them delay the payout. It specifies:

  1. a deduction policy interface: the escrow names one policy for its whole lifetime, tells it about every new task, and at every payout asks it for a single number, the amount it takes;
  2. an escrow side: two calls, two getters, one credit ledger and two events, with guarantees that make a policy safe to plug in: the payee of each payout is fixed before it, the policy always runs on a fixed gas budget that no caller can starve, a failing or invalid policy settles the payout in full, refunds never reach the policy, and no deduction recipient is called during settlement;
  3. an OPTIONAL reference policy profile: a public tax schedule locked per task at creation, and referral fees and repayments that only the payee can assign on its own payouts and only their recipient can release, all under one cap.

Motivation

On-chain escrows pay for work: task tenders that escrow a bounty and pay a fulfiller on acceptance, and job escrows such as ERC-8183 that release a budget to a provider when an evaluator completes the job. At the moment of payment, more parties than the payee often have a claim on the money:

  • Public services. A network that funds shared infrastructure (dispute resolution, monitoring, public data) from a small tax on settled work needs the tax to reach every payout made through its escrow, at a rate fixed when the task was created.
  • Referrals. A payee that won a job through a referrer owes it a fee, most naturally as a share of each payment.
  • Credit. A lender that advances working capital against a task the payee has already won needs to be repaid out of that task's payment before the payee receives it: receivables financing. A lender only advances against an assignment the payee cannot undo.

Existing escrows offer two options. They pay the payee in full and leave every such claim to the payee's goodwill, or they charge one fee that an administrator sets. Hooks chosen per job by the client can be left out by the client, and a hook that reverts blocks the job by design. Neither gives a tax that neither the task creator nor the payee can switch off for payouts made through the escrow, a repayment a lender can rely on, or a guarantee that the payee is paid even when the deduction logic fails.

This ERC separates the two concerns. The escrow guarantees when and how safely the policy is asked, and that what it takes is set aside without calling anyone. The policy decides how much and for whom. The escrow does not grow when new kinds of deductions appear, and one policy design can serve any conforming escrow; each escrow deploys its own instance.

Illustrative flows (informative):

  • A task market deploys its escrow with a policy that reads a public tax schedule. A task created while the rate is 1% pays 1% of every payout to the market's treasury, even if the rate later changes; a task created after the change pays the new rate.
  • A payee wins a task worth 100 and needs 30 to buy compute. It assigns a fixed 30 of its payouts on that task to a lender, which reads the assignment and advances the money. When the task pays, the lender's 30 is set aside before the payee receives the rest.
  • A policy has a bug and starts reverting. Every payout from then on settles in full and emits DeductionsSkipped; no payee waits for a fix.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

1. Terms

  • Escrow: a contract that holds funds for tasks and pays them out on settlement.
  • Task: a unit of funded work in an escrow, identified by taskId.
  • Asset: the currency a task pays in: address(0) for the chain's native currency, otherwise an ERC-20 token.
  • Payout: the moment the escrow pays, or credits, escrowed funds to the party being paid for work on the task, identified within the task by settlementId. A task MAY have many payouts; a settlement that pays several parties is one payout per party. Transfers of a fee the escrow itself charges, refunds, returns of unspent funds, and withdrawals of credit (section 4) are not payouts.
  • Payee: the recipient of a payout.
  • Amount: what the escrow would pay the payee for a payout if it had no policy, after any fee the escrow itself charges.
  • Refund: a return of escrowed funds that is not a payout, to whoever funded or owns the task.
  • Policy: a contract implementing ISettlementDeductions (section 3).
  • Deduction: the part of a payout the policy takes, d.
  • Credit: an amount the escrow holds for an account on a task until that account withdraws it.

2. Conformance

An escrow conforms if it implements section 4 and meets every requirement of section 5. A policy conforms if it implements section 3 and meets every requirement of section 6.

The reference policy profile (section 7) is OPTIONAL. A policy MAY implement it; a policy that claims it MUST meet every rule of section 7.

Support for ERC-165 is OPTIONAL. An escrow that supports it SHOULD report ISettlementCredit; a policy that supports it SHOULD report ISettlementDeductions, and a policy that claims the profile SHOULD also report ISettlementDeductionPolicy.

3. Policy interface

interface ISettlementDeductions {
    /// Called by the escrow when a task is created.
    function onTaskCreated(uint256 taskId, address asset, uint256 amountPerSettlement) external;

    /// Called by the escrow before every payout to `payee` on `taskId`.
    /// Returns the total taken out of `amount`; the escrow pays `payee` the rest.
    function deductions(uint256 taskId, uint256 settlementId, address payee, uint256 amount)
        external returns (uint256 total);
}

amountPerSettlement is informational: the expected size of one payout, or zero if the escrow does not know it in advance.

4. Escrow interface

interface ISettlementCredit {
    event SettlementDeducted(uint256 indexed taskId, uint256 indexed settlementId,
                             address indexed policy, uint256 amount);
    event DeductionsSkipped(uint256 indexed taskId, uint256 indexed settlementId);

    /// The amount held for `account` on `taskId`.
    function creditOf(uint256 taskId, address account) external view returns (uint256);

    /// Transfers the whole credit of `account` on `taskId` to `account`.
    function withdrawCredit(uint256 taskId, address account) external;

    /// The policy named for the escrow's lifetime, or zero if it has none.
    function deductionPolicy() external view returns (address);

    /// The fixed gas budget `G` with which the escrow calls the policy.
    function deductionGas() external view returns (uint256);
}

5. Escrow requirements

  1. One policy for life. An escrow MUST either have no policy or name exactly one, fixed for the escrow's lifetime. It MUST NOT let any party choose, replace or bypass the policy per task. An escrow SHOULD refuse, at deployment, a policy account that has no code or holds an EIP-7702 delegation indicator, since code can later be set on, or replaced behind, such an account.
  2. Task creation. taskId MUST identify one task for the escrow's lifetime. When a task is created, the escrow MUST call onTaskCreated(taskId, asset, amountPerSettlement) on the policy, exactly once for that task and before any payout on it. If the call reverts, task creation MUST revert. The task's asset MUST be the asset passed and MUST NOT change.
  3. Every payout, no refund. Before every payout, on every path that pays a payee (including default and timeout paths), the escrow MUST call deductions(taskId, settlementId, payee, amount) on the policy. The escrow MUST NOT call deductions for a refund. settlementId MUST be unique within the task. The escrow MAY skip the call when the policy's account has no code; the answer is then invalid (requirement 5).
  4. Fixed gas budget. The escrow MUST make the call with a gas limit G that is constant for the escrow. Before the call, the escrow MUST revert unless gasleft() exceeds G * 64 / 63 plus the gas it needs to make the call, including any cold access to the policy's account, so that the policy always receives the full G.
  5. Valid answer. The answer is valid if and only if the call succeeded, returned exactly 32 bytes, and the returned value d satisfies d <= amount. If the answer is not valid, the escrow MUST pay the payee the full amount and MUST emit DeductionsSkipped(taskId, settlementId). A failing or invalid policy MUST NOT prevent the payout. The escrow SHOULD copy no more than 32 bytes of return data, so that the cost of the call is bounded by G.
  6. Crediting. If the answer is valid and d > 0, the escrow MUST add d to the policy's credit on the task, MUST emit SettlementDeducted(taskId, settlementId, policy, d), and MUST pay the payee amount - d. Credited funds MUST stay in the escrow and MUST NOT be used for any other purpose until withdrawn.
  7. Withdrawal. withdrawCredit(taskId, account) MUST be callable by anyone, MUST transfer the whole credit of account on taskId, in the task's asset, to account only, and MUST set that credit to zero. It MAY revert when that credit is zero.
  8. No other calls. During a payout the escrow MUST NOT call any address on the policy's behalf other than the policy itself.
  9. Fixed payee. The payee of each payout MUST be fixed by the escrow's state before the payout, for example as the address that submitted the work being paid, or as the payee named when the task was created. A function that makes a payout MUST NOT take the payee as an argument, and once fixed, the payee of that work MUST NOT be changeable by any party.
  10. Publication. deductionPolicy() MUST return the policy of requirement 1, or zero. deductionGas() MUST return G.
  11. Undeliverable payouts. If transferring amount - d to the payee fails, the escrow SHOULD credit it to the payee, to be withdrawn with withdrawCredit, rather than revert. Any address can refuse native currency, and a payout that always reverts leaves the payer only a refund, which carries no deductions.

6. Policy requirements

  1. onTaskCreated and deductions MUST revert unless called by the policy's escrow. onTaskCreated MUST revert for a taskId it has already been called with.
  2. deductions MUST NOT make a CALL, CALLCODE or STATICCALL to any account other than a precompile, MUST NOT create an account, and MUST NOT SELFDESTRUCT. It MAY DELEGATECALL only to code that itself meets this requirement, so a policy behind a proxy conforms only if every implementation it can point to does (see Security Considerations on mutable policies).
  3. deductions SHOULD complete within the escrow's gas budget in every state that any party can create, and SHOULD bound its loops accordingly.
  4. A policy that pays recipients out of withdrawn credit MUST NOT pay out, for any task, more than has been withdrawn from the escrow for that task, and MUST pay in the asset passed to onTaskCreated for that task. Because withdrawal is permissionless (section 5, requirement 7), the policy MUST account for credit withdrawn by any caller, for example as the total it was credited on the task minus creditOf(taskId, policy). Such a policy MUST count only answers that the escrow credits; in particular it MUST NOT answer more than amount, since an invalid answer is not credited (section 5, requirement 5). This requirement applies to assets that deliver the amount transferred; a policy MAY refuse other assets at task creation.
  5. No storage creation. deductions MUST NOT write any storage slot that is zero before the payout, and so creates no storage. Slots it updates can be allocated in advance, in onTaskCreated or when the state that needs them is set up. Under some gas schedules, creating storage can be charged outside the gas limit of a call, so the escrow's G would not bound it (see Rationale).

7. Reference policy profile (OPTIONAL)

interface ITaxSchedule {
    /// The tax on payouts in `asset`: the treasury it goes to and its rate in basis points.
    function taxOf(address asset) external view returns (address treasury, uint16 bps);
}

interface ISettlementDeductionPolicy is ISettlementDeductions {
    struct Assignment {
        address recipient;
        uint16 bps;        // a share of every payout, or
        uint256 remaining; // what is left of a fixed sum; both zero once finished
    }

    event TaxLocked(uint256 indexed taskId, address indexed treasury, uint16 bps);
    event PaymentAssigned(uint256 indexed taskId, address indexed payee,
                          address indexed recipient, uint16 bps, uint256 amount);
    event PaymentReleased(uint256 indexed taskId, address indexed payee, address indexed recipient);
    event Deducted(uint256 indexed taskId, uint256 indexed settlementId,
                   address indexed recipient, uint256 amount);
    event Claimed(uint256 indexed taskId, address indexed recipient, uint256 amount);

    function escrow() external view returns (address);
    function taxSchedule() external view returns (ITaxSchedule);
    function maxDeductionBps() external view returns (uint16);
    function lockedTaxOf(uint256 taskId) external view returns (address treasury, uint16 bps);
    function assignmentsOf(uint256 taskId, address payee) external view returns (Assignment[] memory);

    function assignPayment(uint256 taskId, address recipient, uint16 bps, uint256 amount) external;
    function release(uint256 taskId, address payee) external;
    function owedOf(uint256 taskId, address recipient) external view returns (uint256);
    function claim(uint256 taskId, address recipient) external;
}
  1. Tax. The policy MAY name one ITaxSchedule, fixed for its lifetime and returned by taxSchedule(), which returns zero if there is none. In onTaskCreated it MUST read taxOf(asset) once and lock the result for the task, returned by lockedTaxOf, emitting TaxLocked if the rate is nonzero; later changes to the schedule MUST NOT affect that task. A rate of zero means no tax. A nonzero rate with a zero treasury MUST make task creation revert.
  2. Assignments. assignPayment(taskId, recipient, bps, amount) MUST bind only payouts to msg.sender. Exactly one of bps (a share of every payout) and amount (a fixed sum repaid across payouts until exhausted) MUST be nonzero. recipient MUST NOT be zero or msg.sender. The payee MUST NOT be able to revoke or reduce an assignment. The policy MUST cap the number of active assignments per payee and task, MUST emit PaymentAssigned, and MUST return the payee's assignments, in the order they are served, from assignmentsOf. Finished (exhausted or released) assignments MAY be removed from that list, keeping the order of the rest.
  3. Release. release(taskId, payee) MUST end every active assignment of payee's payouts on taskId whose recipient is msg.sender, MUST revert if there is none, and MUST emit PaymentReleased. No one else can release an assignment. A recipient holding several assignments on the same payee and task releases them together.
  4. Cap. The policy MUST have a fixed cap, returned by maxDeductionBps(). The total of all deductions on one payout MUST NOT exceed amount * maxDeductionBps / 10000. The tax is taken first, then the payee's assignments in the order made. A fixed sum cut short by the cap MUST carry its remainder to the payee's next payout on the same task. A tax rate above the cap, and an assignment rate above the cap, MUST revert.
  5. Accounting. Each nonzero share MUST be added to owedOf(taskId, recipient) and MUST emit Deducted. Amounts round down. The policy MUST allocate, in onTaskCreated and assignPayment, every balance that deductions adds to; a claim MUST leave those slots allocated; and a finished assignment MUST NOT be written again (section 6, requirement 5). deductions MUST revert for a task that onTaskCreated has not been called for, so that the escrow settles that payout in full.
  6. Claim. claim(taskId, recipient) MUST be callable by anyone, MUST first withdraw the policy's credit on taskId from the escrow if any, MUST pay recipient its whole owedOf in the task's asset and to recipient only, MUST set it to zero, and MUST emit Claimed. The policy MUST accept the chain's native currency, which the escrow, or a vault it pays out of, sends when credit is withdrawn. escrow() returns the only address allowed to call the hooks.

Rationale

One number, not a list. The escrow learns only the total it must set aside; dividing it among recipients happens in the policy. This keeps the escrow side to a few dozen lines, which matters for escrows already close to the 24,576-byte contract size limit, and it keeps the escrow's storage and event surface independent of how many kinds of deduction exist. Returning a list of (recipient, amount) pairs was considered and rejected: it moves the policy's bookkeeping into every escrow.

Credit, not push. What the policy takes is credited and withdrawn later, the same pattern escrows already use for payouts whose recipient refuses them. No treasury, referrer or lender is called during settlement, so none of them can block it or re-enter it. The receive hooks of ERC-777 showed what follows when settlement depends on the recipient's code.

One policy per escrow, for life. A tax that the task creator can switch off is voluntary. Naming the policy at the escrow level, and locking per-task terms at creation, makes the deduction a property of the market a task is posted in; anyone who does not want it posts elsewhere. Per-job hooks chosen by the client, the alternative, cannot carry a tax.

Creation may revert, payouts may not. A policy may refuse a task at creation, for example when the tax schedule asks for more than the cap, because no work has been done and the funder can still go elsewhere. Once work is being paid for, liveness takes precedence: an invalid or failing policy settles in full and leaves a record (DeductionsSkipped). Reverting instead would let one policy bug freeze every payout in the escrow.

Guaranteed gas. Under the 63/64 rule of EIP-150, a caller could otherwise pass just enough gas for the policy call to fail while the payout still succeeds, settling in full and skipping a lender. With the check, a failure inside the full budget is a genuine policy failure.

No storage at payout. Gas schedules that meter the creation of storage apart from execution gas, such as EIP-8037, break the guarantee for a policy that creates storage. Under EIP-8037, when a transaction's gas limit exceeds the per-transaction execution limit, the excess forms a state-gas reservoir that passes to a called contract in full, beyond the gas limit of the call. Below that limit, a few new slots cost more than a modest G, and the payout settles without its deductions; above it, whoever sends the transaction decides whether the creation can be paid. A policy that only updates storage allocated in advance uses execution gas alone, which G bounds under either schedule. A larger G, or a minimum G fixed in this ERC, would still depend on future prices.

A payee fixed before the payout. Assignments bind the payee's address. If the payout itself could name the payee, the payer could pay the same person at a fresh address and skip every assignment, a lender's included. Escrows commonly fix the payee anyway, as the address that submitted the work or the one named in the task; requirement 9 makes it a condition for taking a policy. It does not stop a payer and a payee who cooperate from abandoning the task and settling another way; see Security Considerations.

Undeliverable payouts are credited. Since EIP-7702, any address can run code and refuse native currency. If a refused transfer reverted the payout, a payee with an assignment could refuse every payout and leave the payer only the refund, which skips the assignment. Crediting the payee keeps the payout, and its deductions, going through.

Policy and budget on chain. Payees and lenders are asked to read an escrow's policy and its gas budget before relying on it. Requirement 10 lets them, and lets anyone check that a policy's worst case fits the escrow's G.

Payee consent for assignments, recipient consent for release. Referral fees and repayments are the payee's own decisions, so only the payee can create them. The payee cannot withdraw them, because a lender only advances money against an assignment that cannot be withdrawn after the advance. The recipient can release them, because the protection exists for the recipient: a lender repaid another way, or a referrer that waives its fee, must be able to let the payee go, and the slot it frees can be used for new financing.

Relation to existing work. ERC-8183 lets an administrator set a platform fee, in basis points, paid to a configurable treasury on completion and never on refund, and lets the client set hooks per job. The fee is one rate, which the administrator can change at any time, including for jobs already funded, and its hooks may revert to block an action by design. This ERC moves the fee into an external policy with per-task locking and payee assignments, and keeps payouts live when the policy fails. ERC-2981 reports royalty information that a marketplace may choose to honour; deductions here are enforced by the escrow. Repay-first routing at the level of an agent's revenue address works on all of an agent's income; this ERC works on one escrowed task, which is what a lender advancing against a specific won task needs. The two compose.

Backwards Compatibility

This ERC adds to an escrow; an escrow without a policy behaves as before. It conflicts with escrow standards that fix the amount the payee receives. ERC-8183's complete releases the escrow to the provider minus an optional platform fee, and the token-bound task tender draft pays the full reward per completion and limits what leaves its vault to payouts and refunds. An implementation of either standard together with this one pays the payee amount - d and keeps d in the escrow as credit until it is withdrawn. Such a standard therefore needs an explicit allowance for a settlement deduction: a fee taken only on payout, never on refund. Escrows that already keep a ledger of undeliverable payouts can serve creditOf and withdrawCredit from it.

Test Cases

Interface identifiers (as computed by Solidity's type(I).interfaceId, which excludes inherited functions): ISettlementDeductions = 0x77f547ff; ISettlementCredit = 0x3a440a3e; ISettlementDeductionPolicy = 0x80ba847a (its own functions only); ITaxSchedule = 0xbbb356a6.

Event topics. SettlementDeducted(uint256,uint256,address,uint256) = 0xd6a50990fa5d56f79112ecd39bb97ad451c1b9cea471098009151950b037826d; DeductionsSkipped(uint256,uint256) = 0x12518d49b1ef011e575513a1e510df3de4f1682fcef7750bea4d80717e6e54d1.

Worked example. Reference policy with maxDeductionBps = 5000, tax 1% locked at creation; the payee assigned a 2% referral fee to a referrer and a fixed 30 to a lender, in that order. One payout of 100:

recipientdeductionowedOf after
treasury (tax 1%)11
referrer (referral fee 2%)22
lender (fixed 30)3030
policy credit in the escrow33—
payee67—

After claim for all three recipients, the policy and the escrow hold nothing for the task.

Cap carry-over. maxDeductionBps = 3000, tax 1%, a fixed 50 assigned to a lender. Three payouts of 100 return 30 (tax 1, repayment 29), 22 (tax 1, repayment 21), and 1 (tax only); the lender's owedOf is 50 and its assignment has 0 remaining.

Tax locking. A task created at 1% pays 1% after the schedule moves to 9%; a task created after the change pays 9%. A schedule above the cap makes task creation revert. A second onTaskCreated for the same taskId reverts.

Escrow behaviour. A policy that reverts, or answers more than amount, results in the full payout and DeductionsSkipped. So does a policy that reverts with 300 KB of return data, and the payout then costs no more than with a policy that does the same work and returns nothing. A refund calls no policy. For every gas limit, a payout either reverts or includes the deductions; none settles without them. An assignment made by any address other than the payee does not affect the payee's payouts. A payout goes to the payee fixed by the escrow's state before it; the escrow offers no way to name another. A payout on a task the policy was never told about, or with a policy address that has no code, settles in full with DeductionsSkipped. A payout whose transfer the payee refuses is credited to the payee, and its deductions are credited as usual.

Storage. No payout writes a storage slot of the reference policy that was zero before the payout: not the first payout, not later ones, not after every recipient has claimed, and not when an assignment runs out or is released.

Withdrawal by anyone. If a third party calls withdrawCredit(taskId, policy) on the escrow before any claim, every recipient on that task can still claim in full.

Invariants. Under any sequence of the actions above: the escrow holds exactly what is still escrowed plus what is credited; for every task, what was deducted equals what is owed plus what has been claimed; the policy holds exactly what has been withdrawn and not yet claimed; and every claim of a nonzero owedOf by a recipient that accepts the asset succeeds.

Release. With a 1% tax and a 2% referral fee as the only assignment, after the referrer releases it a payout of 100 deducts only the tax (1). With four assignments of which one is exhausted and one released, a fifth assignment is accepted and is served after the two remaining ones.

Reference Implementation

A reference implementation is provided under the assets of this proposal:

  • Interfaces: ISettlementDeductions.sol (sections 3 and 4), ISettlementDeductionPolicy.sol and ITaxSchedule.sol (section 7).
  • Policy: SettlementDeductionPolicy.sol, the reference policy profile, with at most four active assignments per payee and task.
  • Escrow: ExampleEscrow.sol, the smallest escrow meeting section 5: the creator names the payee when creating a task, pays the task out in one or several payouts, and may refund the rest. It uses G = 300000. The reference policy's worst case (tax and four fixed-sum assignments to distinct recipients) uses about 107,000 gas under the current gas schedule and about 173,000 under EIP-8037 and EIP-8038, all of it updates of storage allocated in advance.

The implementation was developed against tests covering the cases above under both gas schedules, fuzz tests of the arithmetic, and invariant tests that run random sequences of creation, assignment, partial payouts, refunds, third-party withdrawals, claims, releases and rate changes. The escrow side has also been added to an existing task-tender contract (about 70 lines, with a thin companion contract that deploys the reference policy); that contract stays below the contract size limit.

Security Considerations

The policy is trusted by the escrow's deployer, not by payees. A conforming policy can take up to the whole of a payout. Payees should read an escrow's policy, and its cap, before working through it; the reference profile's fixed cap exists for this reason.

Mutable policies, schedules and escrows. Section 5, requirement 1, fixes the policy's address, not its code. A policy behind an upgradeable proxy, one whose rules an owner can change, or an account with an EIP-7702 delegation, which its key holder can re-point or clear, can change what every open task pays or stop all deductions; payees should treat such a policy as mutable, and a policy that wants to be relied on should be immutable. An escrow behind an upgradeable proxy can likewise replace or bypass its policy, change its payee rules or redirect credit; requirement 1 then holds only as long as the upgrade authority allows. A tax schedule is different by design: the reference profile locks the rate per task, so whoever controls the schedule can change only what future tasks pay, and never beyond the cap. It can, however, stop new tasks from being created, by returning a rate above the cap, a zero treasury, or reverting; payouts on existing tasks are unaffected. Deployers should use a schedule whose controls bound these cases.

Schedule changes around task creation. Because the rate is locked when a task is created, whoever controls the schedule can raise the rate just before a task is created and lower it just after, locking the higher rate into that task, up to the cap. Schedules should make a rate change take effect only after a public notice period, and payees and lenders should read lockedTaxOf before working or lending.

Grandfathered rates. A task keeps the rate locked at its creation for as long as it lasts. An escrow whose tasks can stay open indefinitely, take new funds or new work, or change hands lets a task created at a low rate carry that rate into work done long after a higher rate applies to new tasks. Escrows used with a tax should bound how long a task can take payouts.

Native currency. A policy that withdraws credit in the chain's native currency must be able to receive it from wherever the escrow pays it out; otherwise its own withdrawals fail and its recipients cannot be paid, although payouts to payees are unaffected. Native currency sent to the policy by anyone else belongs to no task and cannot be claimed.

Starvation. See section 5, requirement 4, and its rationale. Escrows must size G so that the policy's worst case fits, with room for future gas repricing: if a network upgrade made the policy exceed G, every payout would settle in full and skip its deductions. Storage creation is the clearest case, which is why section 6, requirement 5, keeps it out of deductions. The escrow's own writes during a payout, such as the policy's credit, fall outside G; they make the payout cost more but cannot make it skip the deductions. The reference policy bounds its loop with the assignment cap.

Gas limits of payout transactions. A payout needs more gas than it uses. The check of section 5, requirement 4, requires G * 64 / 63 to be left before the policy is called, but the policy usually uses far less than G and the rest is returned. A transaction gas limit derived from the gas a payout used, as some tools set by default, can fall below the check, and the payout reverts. Callers should take the limit from eth_estimateGas, which searches for a limit at which the transaction succeeds, or use a fixed limit that covers G and the rest of the payout. Such a revert is safe: nothing is paid and no deduction is skipped.

Return data. A policy can revert with a large amount of return data. An escrow that copies all of it pays for the copy outside G, which can make a payout that passed the gas check run out of gas. Hence the recommendation in section 5, requirement 5, to copy at most 32 bytes.

Re-entrancy. The policy is called inside settlement. Escrows should guard settlement against re-entry; the policy may not make external calls in deductions (section 6, requirement 2). The reference policy guards claim, because the asset's transfer during withdrawal could otherwise call back into it.

Cross-task funds and permissionless withdrawal. A policy holds funds for many tasks. Section 6, requirement 4, prevents one task's recipients from being paid with another task's money. A policy that counted only the withdrawals it made itself would be open to a cheap attack: anyone calls withdrawCredit for the policy, the money arrives uncounted, and the task's deductions can never be claimed. The reference policy therefore derives what it has received from the escrow's own ledger. It assumes the asset delivers the amount transferred, and that the escrow credits the policy exactly what it deducted (section 5, requirement 6). The second holds only because the policy never answers more than amount (section 6, requirement 4): a policy that counted an invalid answer would count credit it never received. It also relies on each task being announced once with a fixed asset (section 5, requirement 2): a task announced again in another asset could be paid out of other tasks' funds. Fee-on-transfer and rebasing assets are not supported: with them, any withdrawal delivers less than the ledger shows, and the shortfall could be paid from another task's funds. Deployers should not create tasks in such assets on an escrow with a policy.

Recipients and policies that cannot receive. A recipient that reverts on receipt, or that the asset's issuer blocks, cannot be paid its share, and its share cannot be redirected. The same holds for a payee whose payout was credited because it could not receive (section 5, requirement 11): if it can never receive the asset, its credit stays locked, so a payee named by mistake costs the payer that payout. If the issuer blocks the policy itself, no deduction in that asset can be withdrawn, for any task; payouts to payees continue in full.

Order of assignments. Assignments are served in the order made, within the cap. A lender advancing against a task should read all of the payee's existing assignments on that task first, since earlier ones are paid before it and may use up the cap.

Identity of the payee. Assignments bind an address, and section 5, requirement 9, fixes the address each payout goes to. They cover payouts on that task to that address, nothing more. Refunds are never deducted (section 5, requirement 3), so a payer and a payee who cooperate can refund or cancel the task and settle another way, for example through a new task for a fresh address; a payee can also do its next piece of work under another address. Work can also be rejected and refunded within an escrow's own rules, and in some escrows the payer itself decides acceptance. A lender should check that the assigning address is the one the escrow will pay, should check when the escrow lets the payer reject, refund or cancel, and should lend only as far as those rules protect it. A payee that repays a lender directly should obtain the release first or in the same transaction; a payout in between would pay the lender again.

Rounding. Basis-point arithmetic rounds down, in the payee's favour. A payout small enough that a share rounds to zero carries no deduction for that share, so an escrow that lets a party choose the size of each payout should set a minimum payout.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth