tempo_contracts/precompiles/account_keychain.rs
1#![allow(clippy::too_many_arguments)]
2
3pub use IAccountKeychain::{
4 IAccountKeychainErrors as AccountKeychainError, IAccountKeychainEvents as AccountKeychainEvent,
5 authorizeAdminKeyCall, authorizeKey_0Call as legacyAuthorizeKeyCall,
6 authorizeKey_1Call as authorizeKeyCall, authorizeKey_2Call as authorizeKeyWithWitnessCall,
7 getAllowedCallsReturn, getRemainingLimitWithPeriodCall,
8 getRemainingLimitWithPeriodReturn as getRemainingLimitReturn,
9};
10
11crate::sol! {
12 /// Account Keychain interface for managing authorized keys
13 ///
14 /// This precompile allows accounts to authorize secondary keys with:
15 /// - Different signature types (secp256k1, P256, WebAuthn)
16 /// - Expiry times for key rotation
17 /// - Per-token spending limits for security
18 ///
19 /// Only the main account key can authorize/revoke keys, while secondary keys
20 /// can be used for regular transactions within their spending limits.
21 #[derive(Debug, PartialEq, Eq)]
22 #[sol(abi)]
23 interface IAccountKeychain {
24 enum SignatureType {
25 Secp256k1,
26 P256,
27 WebAuthn,
28 }
29
30 /// Legacy token spending limit structure used before T3.
31 struct LegacyTokenLimit {
32 address token;
33 uint256 amount;
34 }
35
36 /// Token spending limit structure
37 struct TokenLimit {
38 address token;
39 uint256 amount;
40 uint64 period;
41 }
42
43 /// Selector-level recipient rule.
44 struct SelectorRule {
45 bytes4 selector;
46 /// Empty means no recipient restriction for this selector.
47 /// To block the selector entirely, remove the selector rule instead of passing `[]`.
48 address[] recipients;
49 }
50
51 /// Per-target call scope.
52 struct CallScope {
53 address target;
54 /// Empty means no selector restriction for this target.
55 /// To block the target entirely, omit this scope from `allowedCalls` or call
56 /// `removeAllowedCalls` for incremental updates.
57 SelectorRule[] selectorRules;
58 }
59
60 /// Optional access-key restrictions configured at authorization time.
61 struct KeyRestrictions {
62 uint64 expiry;
63 bool enforceLimits;
64 TokenLimit[] limits;
65 /// `true` means the key is unrestricted and `allowedCalls` must be empty.
66 /// `false` means `allowedCalls` defines the full call scope (including deny-all with `[]`).
67 bool allowAnyCalls;
68 CallScope[] allowedCalls;
69 }
70
71 /// Key information structure
72 struct KeyInfo {
73 SignatureType signatureType;
74 address keyId;
75 uint64 expiry;
76 bool enforceLimits;
77 bool isRevoked;
78 }
79 /// Emitted when a new key is authorized
80 event KeyAuthorized(address indexed account, address indexed publicKey, uint8 signatureType, uint64 expiry);
81
82 /// Emitted when a new admin key is authorized.
83 event AdminKeyAuthorized(address indexed account, address indexed publicKey);
84
85 /// Emitted when a key is revoked
86 event KeyRevoked(address indexed account, address indexed publicKey);
87
88 /// Emitted when a spending limit is updated
89 event SpendingLimitUpdated(address indexed account, address indexed publicKey, address indexed token, uint256 newLimit);
90
91 event AccessKeySpend(
92 address indexed account,
93 address indexed publicKey,
94 address indexed token,
95 uint256 amount,
96 uint256 remainingLimit
97 );
98
99 /// Emitted when a key authorization carries a TIP-1053 witness.
100 event KeyAuthorizationWitness(address indexed account, bytes32 indexed witness);
101
102 /// Emitted when a TIP-1053 key-authorization witness is manually burned.
103 event KeyAuthorizationWitnessBurned(address indexed account, bytes32 indexed witness);
104
105 /// Legacy authorize-key entrypoint used before T3.
106 function authorizeKey(
107 address keyId,
108 SignatureType signatureType,
109 uint64 expiry,
110 bool enforceLimits,
111 LegacyTokenLimit[] calldata limits
112 ) external;
113
114 /// Authorize a new key for the caller's account with T3 extensions.
115 /// @param keyId The key identifier (address derived from public key)
116 /// @param signatureType 0: secp256k1, 1: P256, 2: WebAuthn
117 /// @param config Access-key expiry and optional limits / call restrictions
118 function authorizeKey(
119 address keyId,
120 SignatureType signatureType,
121 KeyRestrictions calldata config
122 ) external;
123
124 /// Authorize a new key with a TIP-1053 witness.
125 /// @dev The witness must not be burned for the caller's account. bytes32(0) is valid.
126 function authorizeKey(
127 address keyId,
128 SignatureType signatureType,
129 KeyRestrictions calldata config,
130 bytes32 witness
131 ) external;
132
133 /// Authorize a new admin key for the caller's account.
134 /// @dev The witness must not be burned for the caller's account. bytes32(0) is valid.
135 function authorizeAdminKey(
136 address keyId,
137 SignatureType signatureType,
138 bytes32 witness
139 ) external;
140
141 /// Burn a TIP-1053 key-authorization witness without authorizing a key.
142 /// @dev Callable only by the account admin key.
143 function burnKeyAuthorizationWitness(bytes32 witness) external;
144
145 /// Revoke an authorized key
146 /// @param publicKey The public key to revoke
147 function revokeKey(address keyId) external;
148
149 /// Update spending limit for a key-token pair
150 /// @param publicKey The public key
151 /// @param token The token address
152 /// @param newLimit The new spending limit
153 function updateSpendingLimit(
154 address keyId,
155 address token,
156 uint256 newLimit
157 ) external;
158
159 /// Set or replace allowed calls for one or more key+target pairs.
160 /// @dev Reverts if `scopes` is empty; use `removeAllowedCalls` to delete target scopes.
161 /// @dev `scope.selectorRules = []` does NOT block the target; it allows any selector on that target.
162 /// @dev To block the target entirely, call `removeAllowedCalls`. To block one selector,
163 /// omit that selector rule from `scope.selectorRules`.
164 function setAllowedCalls(
165 address keyId,
166 CallScope[] calldata scopes
167 ) external;
168
169 /// Remove any configured call scope for a key+target pair.
170 function removeAllowedCalls(address keyId, address target) external;
171
172 /// Get key information
173 /// @param account The account address
174 /// @param publicKey The public key
175 /// @return Key information
176 function getKey(address account, address keyId) external view returns (KeyInfo memory);
177
178 /// Get remaining spending limit using the legacy pre-T3 return shape.
179 /// @param account The account address
180 /// @param publicKey The public key
181 /// @param token The token address
182 function getRemainingLimit(
183 address account,
184 address keyId,
185 address token
186 ) external view returns (uint256 remaining);
187
188 /// Get remaining spending limit together with the active period end.
189 /// @param account The account address
190 /// @param publicKey The public key
191 /// @param token The token address
192 /// @return remaining Remaining spending amount
193 /// @return periodEnd Period end timestamp for periodic limits (0 for one-time)
194 function getRemainingLimitWithPeriod(
195 address account,
196 address keyId,
197 address token
198 ) external view returns (uint256 remaining, uint64 periodEnd);
199
200 /// Returns whether an account key is call-scoped and, if so, the configured call scopes.
201 /// @dev `isScoped = false` means unrestricted. `isScoped = true && scopes.length == 0`
202 /// means scoped deny-all.
203 /// @dev Missing, revoked, or expired access keys also return scoped deny-all so callers do
204 /// not observe stale persisted scope state.
205 function getAllowedCalls(
206 address account,
207 address keyId
208 ) external view returns (bool isScoped, CallScope[] memory scopes);
209
210 /// Returns whether a TIP-1053 key-authorization witness has been manually burned.
211 function isKeyAuthorizationWitnessBurned(address account, bytes32 witness) external view returns (bool);
212
213 /// Returns true if `keyId` is the root key or an active admin key for `account`.
214 function isAdminKey(address account, address keyId) external view returns (bool);
215
216 /// Get the key used in the current transaction
217 /// @return The keyId used in the current transaction
218 function getTransactionKey() external view returns (address);
219
220 // Errors
221 error UnauthorizedCaller();
222 error KeyAlreadyExists();
223 error KeyNotFound();
224 error KeyExpired();
225 error SpendingLimitExceeded();
226 error InvalidSpendingLimit();
227 error InvalidSignatureType();
228 error ZeroPublicKey();
229 error ExpiryInPast();
230 error KeyAlreadyRevoked();
231 error SignatureTypeMismatch(uint8 expected, uint8 actual);
232 error CallNotAllowed();
233 error InvalidCallScope();
234 error InvalidKeyId();
235 error InvalidKeyAuthorizationWitness();
236 error KeyAuthorizationWitnessAlreadyBurned();
237 error LegacyAuthorizeKeySelectorChanged(bytes4 newSelector);
238 }
239}