-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathIAccountKeychain.sol
More file actions
228 lines (200 loc) · 8.85 KB
/
IAccountKeychain.sol
File metadata and controls
228 lines (200 loc) · 8.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.13 <0.9.0;
/**
* @title Account Keychain Precompile Interface
* @notice Interface for the Account Keychain precompile that manages authorized access keys
* @dev This precompile is deployed at address `0xaAAAaaAA00000000000000000000000000000000`
*
* The Account Keychain allows accounts to authorize secondary keys (Access Keys) that can sign
* transactions on behalf of the account. Access Keys can be scoped by:
* - Expiry timestamp (when the key becomes invalid)
* - Per-TIP20 token spending limits (one-time or periodic) that deplete as the key spends
* - Call scopes restricting which contracts/selectors the key may call (T3+)
*
* Only the Root Key can call authorizeKey, revokeKey, updateSpendingLimit, setAllowedCalls,
* and removeAllowedCalls.
* This restriction is enforced by the protocol at transaction validation time.
* Access Keys attempting to call these functions will fail with UnauthorizedCaller.
*
* This design is inspired by session key and access control patterns,
* enshrined at the protocol level for better UX and reduced gas costs.
*/
interface IAccountKeychain {
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/// @notice Signature type enumeration
enum SignatureType {
Secp256k1,
P256,
WebAuthn
}
/// @notice Legacy token spending limit structure used before T3
struct LegacyTokenLimit {
address token; // TIP20 token address
uint256 amount; // Spending limit amount
}
/// @notice Token spending limit structure
struct TokenLimit {
address token; // TIP20 token address
uint256 amount; // Spending limit amount
uint64 period; // Period duration in seconds (0 = one-time limit, >0 = periodic reset)
}
/// @notice Selector-level recipient rule
struct SelectorRule {
bytes4 selector; // 4-byte function selector
address[] recipients; // Empty means no recipient restriction for this selector
}
/// @notice Per-target call scope
struct CallScope {
address target; // Target contract address
SelectorRule[] selectorRules; // Empty means any selector is allowed for this target
}
/// @notice Optional access-key restrictions configured at authorization time
struct KeyRestrictions {
uint64 expiry; // Unix timestamp when key expires (use type(uint64).max for never)
bool enforceLimits; // Whether spending limits are enforced for this key
TokenLimit[] limits; // Token spending limits
bool allowAnyCalls; // true = unrestricted calls (allowedCalls must be empty)
CallScope[] allowedCalls; // Call scopes when allowAnyCalls is false
}
/// @notice Key information structure
struct KeyInfo {
SignatureType signatureType; // Signature type of the key
address keyId; // The key identifier (address)
uint64 expiry; // Unix timestamp when key expires (use type(uint64).max for never)
bool enforceLimits; // Whether spending limits are enforced for this key
bool isRevoked; // Whether this key has been revoked
}
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when a new key is authorized
event KeyAuthorized(address indexed account, address indexed publicKey, uint8 signatureType, uint64 expiry);
/// @notice Emitted when a key is revoked
event KeyRevoked(address indexed account, address indexed publicKey);
/// @notice Emitted when a spending limit is updated
event SpendingLimitUpdated(
address indexed account, address indexed publicKey, address indexed token, uint256 newLimit
);
/// @notice Emitted when an access key spends tokens
event AccessKeySpend(
address indexed account,
address indexed publicKey,
address indexed token,
uint256 amount,
uint256 remainingLimit
);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error UnauthorizedCaller();
error KeyAlreadyExists();
error KeyNotFound();
error KeyExpired();
error SpendingLimitExceeded();
error InvalidSpendingLimit();
error InvalidSignatureType();
error ZeroPublicKey();
error ExpiryInPast();
error KeyAlreadyRevoked();
error SignatureTypeMismatch(uint8 expected, uint8 actual);
error CallNotAllowed();
error InvalidCallScope();
error LegacyAuthorizeKeySelectorChanged(bytes4 newSelector);
/*//////////////////////////////////////////////////////////////
MANAGEMENT FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Legacy authorize-key entrypoint used before T3
* @param keyId The key identifier (address) to authorize
* @param signatureType Signature type of the key
* @param expiry Unix timestamp when key expires
* @param enforceLimits Whether to enforce spending limits for this key
* @param limits Initial spending limits for tokens
*/
function authorizeKey(
address keyId,
SignatureType signatureType,
uint64 expiry,
bool enforceLimits,
LegacyTokenLimit[] calldata limits
) external;
/**
* @notice Authorize a new key for the caller's account with T3 extensions
* @param keyId The key identifier (address derived from public key)
* @param signatureType Signature type of the key
* @param config Access-key expiry and optional limits / call restrictions
*/
function authorizeKey(address keyId, SignatureType signatureType, KeyRestrictions calldata config) external;
/**
* @notice Revoke an authorized key
* @param keyId The key ID to revoke
*/
function revokeKey(address keyId) external;
/**
* @notice Update spending limit for a specific token on an authorized key
* @param keyId The key ID to update
* @param token The token address
* @param newLimit The new spending limit
*/
function updateSpendingLimit(address keyId, address token, uint256 newLimit) external;
/**
* @notice Set or replace allowed calls for one or more key+target pairs
* @param keyId The key ID to configure
* @param scopes The call scopes to set
*/
function setAllowedCalls(address keyId, CallScope[] calldata scopes) external;
/**
* @notice Remove any configured call scope for a key+target pair
* @param keyId The key ID to update
* @param target The target contract to remove from allowed calls
*/
function removeAllowedCalls(address keyId, address target) external;
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Get key information
* @param account The account address
* @param keyId The key ID
* @return Key information (returns default values if key doesn't exist)
*/
function getKey(address account, address keyId) external view returns (KeyInfo memory);
/**
* @notice Get remaining spending limit for a key-token pair (legacy)
* @param account The account address
* @param keyId The key ID
* @param token The token address
* @return remaining Remaining spending amount
*/
function getRemainingLimit(address account, address keyId, address token) external view returns (uint256 remaining);
/**
* @notice Get remaining spending limit together with the active period end
* @param account The account address
* @param keyId The key ID
* @param token The token address
* @return remaining Remaining spending amount
* @return periodEnd Period end timestamp for periodic limits (0 for one-time)
*/
function getRemainingLimitWithPeriod(address account, address keyId, address token)
external
view
returns (uint256 remaining, uint64 periodEnd);
/**
* @notice Returns whether an account key is call-scoped and the configured call scopes
* @param account The account address
* @param keyId The key ID
* @return isScoped Whether the key is call-scoped
* @return scopes The configured call scopes
*/
function getAllowedCalls(address account, address keyId)
external
view
returns (bool isScoped, CallScope[] memory scopes);
/**
* @notice Get the transaction key used in the current transaction
* @return The key ID that signed the transaction
*/
function getTransactionKey() external view returns (address);
}