UNPKG

ox

Version:

Ethereum Standard Library

275 lines (254 loc) 8.34 kB
import * as AbiEvent from '../core/AbiEvent.js' import * as AbiParameters from '../core/AbiParameters.js' import type * as Address from '../core/Address.js' import type * as Errors from '../core/Errors.js' import type * as Hex from '../core/Hex.js' import type { Compute } from '../core/internal/types.js' /** * A TIP-1028 receive-policy claim receipt: the ABI-encoded `ClaimReceiptV1` * witness emitted when an inbound transfer or mint violates the recipient's * receive policy. * * This is the canonical, on-chain representation – the value passed to the * `ReceivePolicyGuard`'s `claim` and `burn` functions. Use `decode` to read its * fields. */ export type ReceivePolicyReceipt = Hex.Hex /** Reason an inbound transfer or mint was blocked by a receive policy. */ export type BlockedReason = 'none' | 'tokenFilter' | 'receivePolicy' /** Kind of inbound operation that was blocked. */ export type Kind = 'transfer' | 'mint' /** A decoded {@link ox#ReceivePolicyReceipt.ReceivePolicyReceipt}. */ export type Decoded = Compute<{ /** Receipt layout version. */ version: number /** TIP-20 token holding the blocked funds. */ token: Address.Address /** Recovery authority captured when the operation was blocked. */ recoveryAuthority: Address.Address /** Original sender (transfer) or issuer (mint). */ originator: Address.Address /** Addressed recipient (may be a virtual address). */ recipient: Address.Address /** Block timestamp when the operation was blocked. */ blockedAt: bigint /** Guard nonce assigned when the operation was blocked. */ blockedNonce: bigint /** Reason the operation was blocked. */ blockedReason: BlockedReason /** Whether the blocked operation was a transfer or mint. */ kind: Kind /** Application memo. */ memo: Hex.Hex }> /** @internal */ const blockedReasons = ['none', 'tokenFilter', 'receivePolicy'] as const /** @internal */ const kinds = ['transfer', 'mint'] as const /** * ABI parameters for the `ClaimReceiptV1` witness. * * @internal */ const parameters = [ { type: 'tuple', components: [ { name: 'version', type: 'uint8' }, { name: 'token', type: 'address' }, { name: 'recoveryAuthority', type: 'address' }, { name: 'originator', type: 'address' }, { name: 'recipient', type: 'address' }, { name: 'blockedAt', type: 'uint64' }, { name: 'blockedNonce', type: 'uint64' }, { name: 'blockedReason', type: 'uint8' }, { name: 'kind', type: 'uint8' }, { name: 'memo', type: 'bytes32' }, ], }, ] as const /** * `TransferBlocked` event emitted by the `ReceivePolicyGuard`. * * @internal */ const transferBlocked = AbiEvent.from( 'event TransferBlocked(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint256 amount, uint8 receiptVersion, bytes receipt)', ) /** * Decodes a {@link ox#ReceivePolicyReceipt.ReceivePolicyReceipt} (ABI-encoded * `ClaimReceiptV1` witness) into its fields. * * [TIP-1028](https://docs.tempo.xyz/protocol/tips/tip-1028) * * @example * ```ts twoslash * import { ReceivePolicyReceipt } from 'ox/tempo' * * const decoded = ReceivePolicyReceipt.decode('0x...') * ``` * * @param receipt - The receive-policy receipt. * @returns The decoded fields. */ export function decode(receipt: ReceivePolicyReceipt): Decoded { const [decoded] = AbiParameters.decode(parameters, receipt) return { version: decoded.version, token: decoded.token, recoveryAuthority: decoded.recoveryAuthority, originator: decoded.originator, recipient: decoded.recipient, blockedAt: decoded.blockedAt, blockedNonce: decoded.blockedNonce, blockedReason: blockedReasons[decoded.blockedReason] ?? 'none', kind: kinds[decoded.kind] ?? 'transfer', memo: decoded.memo, } } export declare namespace decode { type ErrorType = AbiParameters.decode.ErrorType | Errors.GlobalErrorType } /** * Encodes decoded fields into a * {@link ox#ReceivePolicyReceipt.ReceivePolicyReceipt}. Inverse of `decode`. * * [TIP-1028](https://docs.tempo.xyz/protocol/tips/tip-1028) * * @example * ```ts twoslash * // @noErrors * import { ReceivePolicyReceipt } from 'ox/tempo' * * const decoded = ReceivePolicyReceipt.decode('0x...') * const receipt = ReceivePolicyReceipt.encode(decoded) * ``` * * @param decoded - The decoded fields. * @returns The receive-policy receipt. */ export function encode(decoded: Decoded): ReceivePolicyReceipt { return AbiParameters.encode(parameters, [ { version: decoded.version, token: decoded.token, recoveryAuthority: decoded.recoveryAuthority, originator: decoded.originator, recipient: decoded.recipient, blockedAt: decoded.blockedAt, blockedNonce: decoded.blockedNonce, blockedReason: blockedReasons.indexOf(decoded.blockedReason), kind: kinds.indexOf(decoded.kind), memo: decoded.memo, }, ]) } export declare namespace encode { type ErrorType = AbiParameters.encode.ErrorType | Errors.GlobalErrorType } /** * Normalizes a {@link ox#ReceivePolicyReceipt.ReceivePolicyReceipt} from either * an encoded receipt (passthrough) or decoded fields. * * [TIP-1028](https://docs.tempo.xyz/protocol/tips/tip-1028) * * @example * ```ts twoslash * // @noErrors * import { ReceivePolicyReceipt } from 'ox/tempo' * * // From an encoded receipt (passthrough). * const a = ReceivePolicyReceipt.from('0x...') * * // From decoded fields. * const b = ReceivePolicyReceipt.from( * ReceivePolicyReceipt.decode('0x...') * ) * ``` * * @param value - An encoded receipt or decoded fields. * @returns The receive-policy receipt. */ export function from( value: ReceivePolicyReceipt | Decoded, ): ReceivePolicyReceipt { if (typeof value === 'string') return value return encode(value) } export declare namespace from { type ErrorType = encode.ErrorType | Errors.GlobalErrorType } /** * Extracts the {@link ox#ReceivePolicyReceipt.ReceivePolicyReceipt} from a * `ReceivePolicyGuard` `TransferBlocked` log. * * Throws if the log is not a `TransferBlocked` event. Use * `fromTransactionReceipt` to extract every blocked transfer in a transaction * (which skips unrelated logs). * * [TIP-1028](https://docs.tempo.xyz/protocol/tips/tip-1028) * * @example * ```ts twoslash * // @noErrors * import { ReceivePolicyReceipt } from 'ox/tempo' * * const receipt = ReceivePolicyReceipt.fromLog(log) * ``` * * @param log - A `TransferBlocked` log (`data` & `topics`). * @returns The receive-policy receipt. */ export function fromLog(log: fromLog.Log): ReceivePolicyReceipt { const { receipt } = AbiEvent.decode(transferBlocked, log) return receipt } export declare namespace fromLog { type Log = AbiEvent.decode.Log type ErrorType = AbiEvent.decode.ErrorType | Errors.GlobalErrorType } /** * Extracts every {@link ox#ReceivePolicyReceipt.ReceivePolicyReceipt} from a * transaction receipt's logs. * * A single transaction may block multiple inbound transfers (e.g. a batched * transfer to several recipients), so this returns an array – one entry per * `TransferBlocked` log, in log order. Returns an empty array when no transfers * were blocked. * * [TIP-1028](https://docs.tempo.xyz/protocol/tips/tip-1028) * * @example * ```ts twoslash * // @noErrors * import { ReceivePolicyReceipt } from 'ox/tempo' * * const receipts = * ReceivePolicyReceipt.fromTransactionReceipt(receipt) * // @log: ['0x...'] (pass each to `claim` / `burn`) * ``` * * @param receipt - The transaction receipt (or any object with `logs`). * @returns The receive-policy receipts, one per blocked transfer. */ export function fromTransactionReceipt( receipt: fromTransactionReceipt.Receipt, ): readonly ReceivePolicyReceipt[] { const selector = AbiEvent.getSelector(transferBlocked) const receipts: ReceivePolicyReceipt[] = [] for (const log of receipt.logs ?? []) { if (log.topics[0] !== selector) continue receipts.push(fromLog(log)) } return receipts } export declare namespace fromTransactionReceipt { type Receipt = { /** Logs emitted by the transaction. */ logs?: readonly AbiEvent.decode.Log[] | undefined } type ErrorType = | AbiEvent.getSelector.ErrorType | fromLog.ErrorType | Errors.GlobalErrorType }