> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inkwell.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Life of a pay run

> Hire, fund, approve, crank, withdraw, disclose. Six beats, with the on-chain instruction behind each.

> **CONFIDENTIAL & PROPRIETARY © 2026 Inkwell Finance, Inc. All Rights Reserved.**
>
> This document is for informational purposes only and does not constitute legal, tax, or investment advice, nor an offer to sell or a solicitation to buy any security or other financial instrument. Any examples, structures, or flows described here are design intent only and may change.

> [!NOTE]
>
> **Pre-alpha.** Encrypt's pre-alpha devnet does no real encryption. Where
> this page says "ciphertext", read "plaintext in a ciphertext account"
> until Encrypt Alpha 1. See [Overview](https://docs.inkwell.finance/dagon/payroll/overview.md).

Six beats, from a salary leaving HR's machine to a payslip landing with a
lender.

## 00 · Setup (once)

Any payer calls `create_company(company_id, authority)`, with `authority`
set to the multisig's vault PDA. This creates the Company PDA, the vault
token account (owned by the Company PDA) and a treasury ciphertext holding
0\. The multisig does not sign this step.

Policy starts empty: no auditor, no operator, no salary cap. The
multisig's first proposal sets it with `update_policy(auditor, salary_cap,
paused)` and, optionally, `set_operator(operator)`.

## 01 · Hire

HR encrypts each new or changed salary off-chain with Encrypt
`CreateInput`, authorized to the payroll program. Encrypt returns a 32-byte
ciphertext handle.

Only the handle goes into the proposal and on-chain. The plaintext salary
never touches the chain or the proposal.

## 02 · Fund

The multisig sends the payroll mint from its treasury to the company's
vault token account. It is a plain SPL transfer, and it can ride in the
same proposal as the run.

Anyone then calls `sync_treasury`. It credits the difference between the
vault's token balance and the last recorded balance into the encrypted
treasury, through the deposit graph. Payments refuse to run while any
deposit sits unsynced.

## 03 · Approve

One multisig proposal per period:

1. `add_employee(wallet)` × N, each carrying one salary handle. Use
   `update_salary`, `approve_bonus` or `set_employee_active` for changes.
2. `open_pay_run(period, budget)`. The `budget` is the run's public total
   ceiling. The run snapshots the company's current `salary_cap` (the
   per-payment cap) and its active headcount.

Put hires **before** `open_pay_run`. A hire made while a run is already
open waits for the next run.

Every instruction in this proposal takes fixed-width arguments and needs
no extra signer. The vault can be both the authority and the rent payer.
Signers see wallets, handles, the period and the budget. They never see a
salary.

## 04 · Crank

Anyone drives the run, in five steps. If the authority set an `operator`,
only that key may submit the payments in step 4.

1. `sync_treasury`, if new funds arrived.
2. `init_employee_ledger` for each new hire. It creates the encrypted wage
   balance from a public 0.
3. `prepare_pay_run`. It turns the public budget and cap into ciphertexts
   and creates the encrypted `flagged` counter at 0.
4. `process_payment` × N, plus `process_bonus` for each approved bonus.
5. `close_pay_run`. Anyone may close once the paid count reaches the
   headcount snapshot. The authority may close earlier.

Each payment runs the pay graph inside FHE:

```text theme={null}
ok   = treasury >= amount  &  remaining >= amount  &  amount <= cap
paid = ok ? amount : 0
→ treasury - paid,  balance + paid,  remaining - paid,  flagged + !ok
```

A payment that would overdraw the treasury, exceed the run budget or
exceed the cap moves nothing and increments the encrypted `flagged`
counter. Success is encrypted, so the employee is still marked paid for
that run. See [Guardrails and limitations](https://docs.inkwell.finance/dagon/payroll/guardrails-and-limitations.md).

The crank never sees a plaintext amount. Its payer needs SOL and an
Encrypt fee deposit.

## 05 · Withdraw

The employee calls `employee_withdraw(amount)` and names an SPL token
account of the payroll mint as recipient. The withdraw graph debits the
encrypted balance only if it covers `amount`, and writes
`paid ∈ {amount, 0}` to a fresh ciphertext.

1. `request_withdrawal_decryption`. For 150 slots after the debit only the
   initiator may call it. After that, anyone may.
2. The Encrypt decryptor reveals `paid`, and only `paid`. The remaining
   balance stays encrypted.
3. `complete_withdrawal`, permissionless. If `paid == amount`, the program
   transfers `amount` from the vault to the recipient. Otherwise it adds
   `paid` back to the balance inside FHE. A stale decryption answer is
   harmless: it adds back 0, or restores the debit.

Withdrawals keep working when the company is paused or the employee is
deactivated. If the payout account is frozen or closed, the employee can
swap it with `retarget_withdrawal`.

## 06 · Disclose

`grant_view(target)` copies one encrypted figure into a new ciphertext
authorized to a named `viewer`. The viewer reads it privately through
Encrypt `ReadCiphertext`, re-encrypted to their key. Nothing is decrypted
on-chain.

| Grantor | May grant |
| - | - |
| Authority | Any figure, to anyone |
| Auditor | Any figure, to the auditor only |
| Employee | Their own salary or balance, to anyone |

An employee proves income to a lender or landlord this way. An auditor
pulls the treasury, a run's remaining budget or its flagged count. The
grant itself (grantor, viewer, source handle) is public; the value is not.

***

Returning excess treasury follows the same exit path: the multisig calls
`approve_treasury_withdrawal(amount, recipient)` (`amount = 0` revokes),
and a crank runs `begin_treasury_withdrawal`, which is blocked while a run
is open, then the same decrypt and complete steps.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.