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