Skip to main content

tempo_contracts/precompiles/
receive_policy_guard.rs

1pub use IReceivePolicyGuard::{
2    IReceivePolicyGuardErrors as ReceivePolicyGuardError,
3    IReceivePolicyGuardEvents as ReceivePolicyGuardEvent,
4};
5use alloy_primitives::{Address, B256, U256};
6use alloy_sol_types::SolValue;
7
8crate::sol! {
9    #[derive(Debug, PartialEq, Eq)]
10    #[sol(abi)]
11    interface IReceivePolicyGuard {
12        enum InboundKind {
13            TRANSFER,
14            MINT
15        }
16
17        /// @notice Claim receipt for one blocked inbound transfer or mint.
18        /// @dev `recipient` is the addressed `to` value and may be virtual. The corresponding
19        ///      `receiver` emitted in events is the resolved account/master where funds settle.
20        struct ClaimReceiptV1 {
21            /// @notice Receipt layout version. Must equal `1` for this struct.
22            uint8 version;
23            /// @notice TIP-20 token whose blocked funds are held by the guard.
24            address token;
25            /// @notice Address with the authority to claim the blocked funds.
26            address recoveryAuthority;
27            /// @notice Original sender/originator of the blocked transfer or mint.
28            address originator;
29            /// @notice Addressed recipient from the inbound operation; may be a virtual address.
30            address recipient;
31            /// @notice Block timestamp when the inbound operation was blocked.
32            uint64 blockedAt;
33            /// @notice Guard nonce assigned when the inbound operation was blocked.
34            uint64 blockedNonce;
35            /// @notice TIP-403 blocked reason encoded as a `BlockedReason` discriminant.
36            uint8 blockedReason;
37            /// @notice Whether the blocked inbound operation was a transfer or mint.
38            InboundKind kind;
39            /// @notice Application memo copied from the blocked inbound operation.
40            bytes32 memo;
41        }
42
43        function balanceOf(bytes calldata receipt) external view returns (uint256 amount);
44        function claim(address to, bytes calldata receipt) external;
45        function burnBlockedReceipt(bytes calldata receipt) external;
46
47        /// @notice Emitted when an inbound TIP-20 transfer or mint is blocked and funds are redirected.
48        /// @param token TIP-20 token whose funds are held by the guard.
49        /// @param receiver Resolved account where funds would settle; for virtual recipients its their master.
50        /// @param blockedNonce Guard nonce assigned to the blocked operation.
51        /// @param amount Amount of blocked funds held by the guard.
52        /// @param receiptVersion Claim receipt layout version.
53        /// @param receipt ABI-encoded receipt witness that can be passed to `claim`.
54        event TransferBlocked(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint256 amount, uint8 receiptVersion, bytes receipt);
55
56        /// @notice Emitted when blocked funds are claimed with a valid receipt.
57        /// @param token TIP-20 token released by the guard.
58        /// @param receiver Resolved account where funds would settle; for virtual recipients its their master.
59        /// @param blockedNonce Guard nonce from the claimed receipt.
60        /// @param blockedAt Block timestamp from the claimed receipt.
61        /// @param receiptVersion Claim receipt layout version.
62        /// @param originator Original sender/originator from the claimed receipt.
63        /// @param recipient Addressed recipient from the claimed receipt; may be virtual.
64        /// @param recoveryAuthority Claim authority from the claimed receipt.
65        /// @param caller Account that submitted the claim.
66        /// @param to Address where released funds were sent.
67        /// @param amount Amount of funds released.
68        event ReceiptClaimed(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint64 blockedAt, uint8 receiptVersion, address originator, address recipient, address recoveryAuthority, address caller, address to, uint256 amount);
69
70        /// @notice Emitted when blocked funds are burned with a valid receipt.
71        /// @param token TIP-20 token burned by the guard.
72        /// @param receiver Resolved account where funds would settle; for virtual recipients its their master.
73        /// @param blockedNonce Guard nonce from the burned receipt.
74        /// @param blockedAt Block timestamp from the burned receipt.
75        /// @param receiptVersion Claim receipt layout version.
76        /// @param originator Original sender/originator from the burned receipt.
77        /// @param recipient Addressed recipient from the burned receipt; may be virtual.
78        /// @param recoveryAuthority Claim authority from the burned receipt.
79        /// @param caller Account that submitted the burn.
80        /// @param amount Amount of funds burned.
81        event ReceiptBurned(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint64 blockedAt, uint8 receiptVersion, address originator, address recipient, address recoveryAuthority, address caller, uint256 amount);
82
83        error InvalidReceipt();
84        error InvalidClaimAddress();
85        error UnauthorizedClaimer();
86        error AddressReserved();
87    }
88}
89
90impl IReceivePolicyGuard::ClaimReceiptV1 {
91    #[allow(clippy::too_many_arguments)]
92    pub fn new(
93        token: Address,
94        recovery_auth: Address,
95        originator: Address,
96        recipient: Address,
97        at: u64,
98        nonce: u64,
99        reason: u8,
100        kind: IReceivePolicyGuard::InboundKind,
101        memo: B256,
102    ) -> Self {
103        Self {
104            version: 1,
105            token,
106            recoveryAuthority: recovery_auth,
107            originator,
108            recipient,
109            blockedAt: at,
110            blockedNonce: nonce,
111            blockedReason: reason,
112            kind,
113            memo,
114        }
115    }
116
117    pub fn claimed_event(
118        &self,
119        receiver: Address,
120        caller: Address,
121        to: Address,
122        amount: U256,
123    ) -> ReceivePolicyGuardEvent {
124        ReceivePolicyGuardEvent::ReceiptClaimed(IReceivePolicyGuard::ReceiptClaimed {
125            token: self.token,
126            originator: self.originator,
127            receiver,
128            blockedNonce: self.blockedNonce,
129            blockedAt: self.blockedAt,
130            receiptVersion: self.version,
131            recipient: self.recipient,
132            recoveryAuthority: self.recoveryAuthority,
133            caller,
134            to,
135            amount,
136        })
137    }
138
139    pub fn blocked_event(&self, receiver: Address, amount: U256) -> ReceivePolicyGuardEvent {
140        ReceivePolicyGuardEvent::TransferBlocked(IReceivePolicyGuard::TransferBlocked {
141            token: self.token,
142            receiver,
143            blockedNonce: self.blockedNonce,
144            receiptVersion: self.version,
145            amount,
146            receipt: self.abi_encode().into(),
147        })
148    }
149
150    pub fn burned_event(
151        &self,
152        receiver: Address,
153        caller: Address,
154        amount: U256,
155    ) -> ReceivePolicyGuardEvent {
156        ReceivePolicyGuardEvent::ReceiptBurned(IReceivePolicyGuard::ReceiptBurned {
157            token: self.token,
158            receiver,
159            receiptVersion: self.version,
160            blockedNonce: self.blockedNonce,
161            blockedAt: self.blockedAt,
162            originator: self.originator,
163            recipient: self.recipient,
164            recoveryAuthority: self.recoveryAuthority,
165            caller,
166            amount,
167        })
168    }
169}
170
171impl TryFrom<alloy_primitives::Bytes> for IReceivePolicyGuard::ClaimReceiptV1 {
172    type Error = ReceivePolicyGuardError;
173
174    fn try_from(receipt: alloy_primitives::Bytes) -> Result<Self, Self::Error> {
175        Self::abi_decode(&receipt).map_err(|_| ReceivePolicyGuardError::invalid_receipt())
176    }
177}