Skip to main content

Escrow

When a thread is opened against an escrow-enabled inbox, the sender's payment is held in the inbox's associated token account instead of being transferred immediately. The funds stay locked until both parties approve the release, or until a time lock expires.

See Payment Rules for how to set up an escrow-enabled inbox.

Escrow state

After loading a thread, the escrowPayment field reflects current escrow state:

await thread.load();
const escrow = thread.Thread.escrowPayment;

if (escrow) {
console.log(escrow.senderApproval); // has sender approved?
console.log(escrow.receiverApproval); // has receiver approved?
console.log(escrow.released); // have funds been released?
console.log(escrow.releaseTime); // unix timestamp, or null
}

ThreadEscrowInfo

type ThreadEscrowInfo = {
senderApproval: boolean;
receiverApproval: boolean;
releaseTime: number | null; // unix timestamp, null until both approve
released: boolean;
amount: BN;
mint: PublicKey;
tokenProgram: TokenProgramType;
escrow: Escrow; // contains releaseSeconds
};

Approving

Either side calls approveEscrow() to signal approval. Once both sides have approved, the release time is set and the funds become withdrawable after releaseSeconds.

const { receipt } = await thread.approveEscrow();

Returns Promise<TxReceiptWithClient<ThreadClient>>


Withdrawing

Once the escrow is released (both approvals given and release time passed), the receiver calls withdrawEscrow to claim the funds.

const { receipt } = await thread.withdrawEscrow();

Pass an explicit token account to receive the funds, or omit to default to the receiver's ATA:

await thread.withdrawEscrow({ receiverTokenAccount: myTokenAccount });

Returns Promise<TxReceiptWithClient<ThreadClient>>


Typical flow

Sender opens thread → funds locked in escrow

Receiver reviews conversation

Both call approveEscrow() → releaseTime is set

After releaseSeconds elapses

Receiver calls withdrawEscrow() → funds transferred

If the receiver never approves, the sender can reclaim by calling approveEscrow() alone once the time lock expires (exact behaviour is enforced on-chain by the program rules).