tempo_contracts/precompiles/account_keychain.rs
1pub use IAccountKeychain::{
2 IAccountKeychainErrors as AccountKeychainError, IAccountKeychainEvents as AccountKeychainEvent,
3};
4
5crate::sol! {
6 /// Account Keychain interface for managing authorized keys
7 ///
8 /// This precompile allows accounts to authorize secondary keys with:
9 /// - Different signature types (secp256k1, P256, WebAuthn)
10 /// - Expiry times for key rotation
11 /// - Per-token spending limits for security
12 ///
13 /// Only the main account key can authorize/revoke keys, while secondary keys
14 /// can be used for regular transactions within their spending limits.
15 #[derive(Debug, PartialEq, Eq)]
16 #[sol(abi)]
17 interface IAccountKeychain {
18 enum SignatureType {
19 Secp256k1,
20 P256,
21 WebAuthn,
22 }
23
24 /// Token spending limit structure
25 struct TokenLimit {
26 address token;
27 uint256 amount;
28 }
29
30 /// Key information structure
31 struct KeyInfo {
32 SignatureType signatureType;
33 address keyId;
34 uint64 expiry;
35 bool enforceLimits;
36 bool isRevoked;
37 }
38 /// Emitted when a new key is authorized
39 event KeyAuthorized(address indexed account, address indexed publicKey, uint8 signatureType, uint64 expiry);
40
41 /// Emitted when a key is revoked
42 event KeyRevoked(address indexed account, address indexed publicKey);
43
44 /// Emitted when a spending limit is updated
45 event SpendingLimitUpdated(address indexed account, address indexed publicKey, address indexed token, uint256 newLimit);
46
47 /// Authorize a new key for the caller's account
48 /// @param keyId The key identifier (address derived from public key)
49 /// @param signatureType 0: secp256k1, 1: P256, 2: WebAuthn
50 /// @param expiry Block timestamp when the key expires (u64::MAX for never expires)
51 /// @param enforceLimits Whether to enforce spending limits for this key
52 /// @param limits Initial spending limits for tokens (only used if enforceLimits is true)
53 function authorizeKey(
54 address keyId,
55 SignatureType signatureType,
56 uint64 expiry,
57 bool enforceLimits,
58 TokenLimit[] calldata limits
59 ) external;
60
61 /// Revoke an authorized key
62 /// @param publicKey The public key to revoke
63 function revokeKey(address keyId) external;
64
65 /// Update spending limit for a key-token pair
66 /// @param publicKey The public key
67 /// @param token The token address
68 /// @param newLimit The new spending limit
69 function updateSpendingLimit(
70 address keyId,
71 address token,
72 uint256 newLimit
73 ) external;
74
75 /// Get key information
76 /// @param account The account address
77 /// @param publicKey The public key
78 /// @return Key information
79 function getKey(address account, address keyId) external view returns (KeyInfo memory);
80
81 /// Get remaining spending limit
82 /// @param account The account address
83 /// @param publicKey The public key
84 /// @param token The token address
85 /// @return Remaining spending amount
86 function getRemainingLimit(
87 address account,
88 address keyId,
89 address token
90 ) external view returns (uint256);
91
92 /// Get the key used in the current transaction
93 /// @return The keyId used in the current transaction
94 function getTransactionKey() external view returns (address);
95
96 // Errors
97 error UnauthorizedCaller();
98 error KeyAlreadyExists();
99 error KeyNotFound();
100 error KeyExpired();
101 error SpendingLimitExceeded();
102 error InvalidSignatureType();
103 error ZeroPublicKey();
104 error ExpiryInPast();
105 error KeyAlreadyRevoked();
106 error SignatureTypeMismatch(uint8 expected, uint8 actual);
107 }
108}
109
110impl AccountKeychainError {
111 /// Creates an error for signature type mismatch.
112 pub const fn signature_type_mismatch(expected: u8, actual: u8) -> Self {
113 Self::SignatureTypeMismatch(IAccountKeychain::SignatureTypeMismatch { expected, actual })
114 }
115
116 /// Creates an error for unauthorized caller.
117 pub const fn unauthorized_caller() -> Self {
118 Self::UnauthorizedCaller(IAccountKeychain::UnauthorizedCaller {})
119 }
120
121 /// Creates an error for key already exists.
122 pub const fn key_already_exists() -> Self {
123 Self::KeyAlreadyExists(IAccountKeychain::KeyAlreadyExists {})
124 }
125
126 /// Creates an error for key not found.
127 pub const fn key_not_found() -> Self {
128 Self::KeyNotFound(IAccountKeychain::KeyNotFound {})
129 }
130
131 /// Creates an error for key expired.
132 pub const fn key_expired() -> Self {
133 Self::KeyExpired(IAccountKeychain::KeyExpired {})
134 }
135
136 /// Creates an error for spending limit exceeded.
137 pub const fn spending_limit_exceeded() -> Self {
138 Self::SpendingLimitExceeded(IAccountKeychain::SpendingLimitExceeded {})
139 }
140
141 /// Creates an error for invalid signature type.
142 pub const fn invalid_signature_type() -> Self {
143 Self::InvalidSignatureType(IAccountKeychain::InvalidSignatureType {})
144 }
145
146 /// Creates an error for zero public key.
147 pub const fn zero_public_key() -> Self {
148 Self::ZeroPublicKey(IAccountKeychain::ZeroPublicKey {})
149 }
150
151 /// Creates an error for expiry timestamp in the past.
152 pub const fn expiry_in_past() -> Self {
153 Self::ExpiryInPast(IAccountKeychain::ExpiryInPast {})
154 }
155
156 /// Creates an error for when a key_id has already been revoked.
157 /// Once revoked, a key_id can never be re-authorized for the same account.
158 /// This prevents replay attacks where a revoked key's authorization is reused.
159 pub const fn key_already_revoked() -> Self {
160 Self::KeyAlreadyRevoked(IAccountKeychain::KeyAlreadyRevoked {})
161 }
162}