Skip to content

Commit f185c7c

Browse files
glitch003claude
andcommitted
feat(account-config): hasSpendingRules flag + multicall view (lambda-parity PR 3)
The on-chain zero-latency gate for per-key spending rules. All additive and storage-safe: a new mapping appended to the END of root AccountConfigStorage (not a field on the inline-embedded UsageApiKey struct, which would shift the Account layout). - AppStorage: append `mapping(uint256 => bool) usageKeyHasSpendingRules`. - ViewsFacet: `getSpendingRulesFlag(apiKeyHash)` and `canExecuteActionWithSpendingRules(apiKeyHash, cidHash) -> (canExecute, hasSpendingRules)` so the gateway reads both in one RPC. - WritesFacet: `setSpendingRulesFlag(accountApiKeyHash, usageApiKeyHash, bool)` + event, same account-access control as setUsageApiKey. Source only; `forge build` passes. Regenerate the Rust bindings + diamond ABI with `make generate` on the canonical toolchain, then deploy via Safe diamond-cut on Base (both ops steps). The gateway reads the new view through a scoped sol! interface, so it does not depend on the regenerated giant binding. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 71eb95c commit f185c7c

3 files changed

Lines changed: 57 additions & 0 deletions

File tree

lit-api-server/blockchain/lit_node_express/contracts/AccountConfigFacets/AppStorage.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ library AppStorage {
119119
EnumerableSet.StringSet nodeConfigurationKeys;
120120
mapping(string => string) nodeConfigurationValues;
121121
uint256 serverTriggerValue;
122+
// Lambda-parity: per-usage-key flag gating off-hot-path spending-rule
123+
// enforcement (rolling spend cap, rate/concurrency limits, origin
124+
// allowlist) stored off-chain. False for every existing key, so the
125+
// gateway does zero extra work unless it is explicitly set. Appended at
126+
// the end of root storage so the existing layout is untouched.
127+
// See plans/chipotle-lambda-parity.md.
128+
mapping(uint256 => bool) usageKeyHasSpendingRules;
122129
}
123130

124131
function getStorage()

lit-api-server/blockchain/lit_node_express/contracts/AccountConfigFacets/ViewsFacet.sol

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,29 @@ contract ViewsFacet {
405405
return apiKeyCanExecuteForAnyGroup(apiKeyHash, groupIds);
406406
}
407407

408+
/// @notice Whether a usage API key has off-chain spending rules the gateway
409+
/// must enforce. False for every key that never set it, so the
410+
/// gateway's hot path stays free for keys without rules.
411+
function getSpendingRulesFlag(
412+
uint256 apiKeyHash
413+
) public view returns (bool) {
414+
return AppStorage.getStorage().usageKeyHasSpendingRules[apiKeyHash];
415+
}
416+
417+
/// @notice Combined hot-path check: returns (canExecute, hasSpendingRules)
418+
/// in a single call so the gateway reads both in one RPC and pays no
419+
/// extra round trip for the spending-rules gate.
420+
/// See plans/chipotle-lambda-parity.md.
421+
function canExecuteActionWithSpendingRules(
422+
uint256 apiKeyHash,
423+
uint256 cidHash
424+
) public view returns (bool canExecute, bool hasSpendingRules) {
425+
canExecute = canExecuteAction(apiKeyHash, cidHash);
426+
hasSpendingRules = AppStorage.getStorage().usageKeyHasSpendingRules[
427+
apiKeyHash
428+
];
429+
}
430+
408431
function canUseWalletInAction(
409432
uint256 apiKeyHash,
410433
uint256 cidHash,

lit-api-server/blockchain/lit_node_express/contracts/AccountConfigFacets/WritesFacet.sol

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ contract WritesFacet {
2525
uint256 indexed accountApiKeyHash,
2626
uint256 indexed usageApiKeyHash
2727
);
28+
event SpendingRulesFlagSet(
29+
uint256 indexed accountApiKeyHash,
30+
uint256 indexed usageApiKeyHash,
31+
bool hasSpendingRules
32+
);
2833
event GroupAdded(uint256 indexed apiKeyHash, uint256 indexed groupId);
2934
event GroupUpdated(
3035
uint256 indexed accountApiKeyHash,
@@ -321,6 +326,28 @@ contract WritesFacet {
321326
emit UsageApiKeySet(masterAccountApiKeyHash, usageApiKeyHash);
322327
}
323328

329+
/// @notice Set the off-chain spending-rules flag for a usage API key.
330+
/// @dev When true, the gateway enforces this key's off-chain spending rules
331+
/// (rolling spend cap, rate/concurrency limits, origin allowlist); when
332+
/// false it skips all of that on the hot path. Same account-access
333+
/// control as setUsageApiKey. The detailed rules live off-chain (see
334+
/// lit-payments); this only flips the gate. See
335+
/// plans/chipotle-lambda-parity.md.
336+
function setSpendingRulesFlag(
337+
uint256 accountApiKeyHash,
338+
uint256 usageApiKeyHash,
339+
bool hasSpendingRules
340+
) public {
341+
SecurityLib.revertIfNoAccountAccess(accountApiKeyHash, msg.sender);
342+
AppStorage.AccountConfigStorage storage s = AppStorage.getStorage();
343+
s.usageKeyHasSpendingRules[usageApiKeyHash] = hasSpendingRules;
344+
emit SpendingRulesFlagSet(
345+
accountApiKeyHash,
346+
usageApiKeyHash,
347+
hasSpendingRules
348+
);
349+
}
350+
324351
function addGroup(
325352
uint256 apiKeyHash,
326353
string memory name,

0 commit comments

Comments
 (0)