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}