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.
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.
00 · Setup (once)
Any payer callscreate_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 EncryptCreateInput, 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 callssync_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:add_employee(wallet)× N, each carrying one salary handle. Useupdate_salary,approve_bonusorset_employee_activefor changes.open_pay_run(period, budget). Thebudgetis the run’s public total ceiling. The run snapshots the company’s currentsalary_cap(the per-payment cap) and its active headcount.
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 anoperator,
only that key may submit the payments in step 4.
sync_treasury, if new funds arrived.init_employee_ledgerfor each new hire. It creates the encrypted wage balance from a public 0.prepare_pay_run. It turns the public budget and cap into ciphertexts and creates the encryptedflaggedcounter at 0.process_payment× N, plusprocess_bonusfor each approved bonus.close_pay_run. Anyone may close once the paid count reaches the headcount snapshot. The authority may close earlier.
flagged
counter. Success is encrypted, so the employee is still marked paid for
that run. See Guardrails and limitations.
The crank never sees a plaintext amount. Its payer needs SOL and an
Encrypt fee deposit.
05 · Withdraw
The employee callsemployee_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.
request_withdrawal_decryption. For 150 slots after the debit only the initiator may call it. After that, anyone may.- The Encrypt decryptor reveals
paid, and onlypaid. The remaining balance stays encrypted. complete_withdrawal, permissionless. Ifpaid == amount, the program transfersamountfrom the vault to the recipient. Otherwise it addspaidback to the balance inside FHE. A stale decryption answer is harmless: it adds back 0, or restores the debit.
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.
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.