-
Notifications
You must be signed in to change notification settings - Fork 5.4k
fix: Extract gator permission expiry from delegation context #37874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Fixes #464 - Permission with expiry showing 'No expiration' - Extract expiry timestamp from permissionResponse.context by decoding delegation - Find TimestampEnforcer caveat and decode the terms field (last 32 hex chars) - Convert BigInt timestamp to readable date format - Add comprehensive test coverage for all edge cases: - Valid expiry extraction - No TimestampEnforcer caveat - Invalid delegation count (0 or >1) - Invalid terms length - Zero timestamp - Decoding errors - Remove unused imports and debug logs
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
✨ Files requiring CODEOWNER review ✨👨🔧 @MetaMask/core-extension-ux (2 files, +169 -30)
|
...mponents/multichain/pages/gator-permissions/components/review-gator-permission-item.test.tsx
Show resolved
Hide resolved
Builds ready [542ada2]
UI Startup Metrics (1214 ± 97 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
…missionItem tests - Add beforeEach hooks to configure decodeDelegations and getDeleGatorEnvironment mocks for NATIVE and ERC20 token test suites - Update test assertions to verify actual expiration date content instead of just element presence - Fix variable naming conflicts in edge case tests to avoid scope shadowing - Ensures tests correctly validate expiration date extraction from delegation context
Builds ready [9261685]
UI Startup Metrics (1261 ± 86 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
MoMannn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some tests are failing. Run yarn test:unit:coverage --shard=4/6 locally to check.
| if (!rules) { | ||
| const getExpirationDate = useCallback((): string => { | ||
| try { | ||
| const delegations = decodeDelegations(permissionContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it might be usable in different places. Could we wrap it into a reusable function that returns expiry or 0 and move it to: gator-permissions-utils file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then you can also move most of the test to utils testing the function and only basic test that shows or shows no expiration in the item tests.
|
Would it make sense to merge this into: #37768 and have a single PR? |
- Created extractExpiryTimestampFromDelegation() in time-utils.ts - Returns expiry timestamp or 0, making it reusable across components - Simplified review-gator-permission-item.tsx from ~60 lines to ~10 lines - Moved comprehensive tests from component to utility tests - Component tests now focus on UI behavior only
Builds ready [741e6c2]
UI Startup Metrics (1213 ± 79 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Jest's it() function doesn't accept timeout as third parameter with async callbacks. Removed invalid timeout arguments from two test cases that were causing TypeScript errors.
|
|
||
| if (!expiry || expiry === 0) { | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Timestamp Overflow Leads to Conversion Crash
Converting a uint128 value larger than Number.MAX_SAFE_INTEGER to Number produces Infinity, which passes the validation checks and gets returned. When convertTimestampToReadableDate receives Infinity, it throws an uncaught error. The function should check for Infinity and return 0, or validate that the timestamp is within a reasonable range before conversion.
Builds ready [d790d8a]
UI Startup Metrics (1223 ± 91 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Jest's beforeAll/afterAll don't accept timeout as second parameter with async callbacks. Removed invalid timeout arguments that were causing issues.
Builds ready [8596ba0]
UI Startup Metrics (1242 ± 101 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
| } | ||
|
|
||
| const dateTime = DateTime.fromSeconds(timestamp); | ||
| const dateTime = DateTime.fromSeconds(timestamp, { zone: 'utc' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used in multiple places, is it ok to change to UTC generally?
| * @param chainId - The chain ID hex string | ||
| * @returns The expiration timestamp in seconds, or 0 if no expiration exists | ||
| */ | ||
| export const extractExpiryTimestampFromDelegation = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We talked also about possibly moving this to the core gator permissions controller package. Looking more carefully I think that would be best. Since logic for this is already in the core but seems it does not work correctly: https://github.com/MetaMask/core/blob/33179969f4aa3df91b31a6ec18ba67da6b574c82/packages/gator-permissions-controller/src/decodePermission/decodePermission.ts#L124 I think it would be best to fix that logic there.
Description
Fixes #464 - Gator permissions with expiry were displaying "No expiration" in the UI.
Root Cause: The expiry timestamp is not stored directly on the permission object. Instead, it's encoded within the
permissionResponse.contextfield as part of the delegation'sTimestampEnforcercaveat.Solution:
permissionContextusingdecodeDelegations()from@metamask/delegation-coreTimestampEnforcercaveat in the delegationtermsfield (uint128 encoding)Changelog
CHANGELOG entry: Fixed gator permissions displaying "No expiration" when expiry timestamp exists
Related issues
Fixes: #464
Manual testing steps
jeff.dripfund.xyzjeff.dripfund.xyzScreenshots/Recordings
Before
Permission showed "No expiration" despite having an expiry timestamp in the delegation context.
After
Permission now correctly displays the expiration date (e.g., "11/13/2026") extracted from the
TimestampEnforcercaveat.Pre-merge author checklist
Pre-merge reviewer checklist
Note
Derives gator permission expiration from delegation context (TimestampEnforcer) and updates UI to show the correct UTC date.
shared/lib/gator-permissions/time-utils.ts):extractExpiryTimestampFromDelegation(permissionContext, chainId)usingdecodeDelegationsandgetDeleGatorEnvironmentto parseTimestampEnforcerterms and return expiry or0.convertTimestampToReadableDateto format in UTC.review-gator-permission-item.tsx):extractExpiryTimestampFromDelegationand render formatted expiration or "No expiration".Written by Cursor Bugbot for commit 8596ba0. This will update automatically on new commits. Configure here.