Skip to main content

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}