Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/gator-permissions-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Extends the `GatorPermissionsController` to enable attaching metadata(transaction hash, block timestamp) when submitting a permission revocation. ([#7503](https://github.com/MetaMask/core/pull/7503))

### Changed

- Bump `@metamask/transaction-controller` from `^62.5.0` to `^62.7.0` ([#7430](https://github.com/MetaMask/core/pull/7430), [#7494](https://github.com/MetaMask/core/pull/7494))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,71 @@ describe('GatorPermissionsController', () => {
});
});

it('should submit revocation metadata when transaction is confirmed', async () => {
const mockHandleRequestHandler = jest.fn().mockResolvedValue(undefined);
const rootMessenger = getRootMessenger({
snapControllerHandleRequestActionHandler: mockHandleRequestHandler,
});
const messenger = getMessenger(rootMessenger);

const controller = new GatorPermissionsController({
messenger,
state: {
isGatorPermissionsEnabled: true,
gatorPermissionsProviderSnapId:
MOCK_GATOR_PERMISSIONS_PROVIDER_SNAP_ID,
},
});

const txId = 'test-tx-id';
const permissionContext = '0x1234567890abcdef1234567890abcdef12345678';
const hash = '0x-mock-hash';

await controller.addPendingRevocation({ txId, permissionContext });

// Emit transaction approved event (user confirms)
rootMessenger.publish('TransactionController:transactionApproved', {
transactionMeta: { id: txId } as TransactionMeta,
});

// Emit transaction confirmed event
rootMessenger.publish('TransactionController:transactionConfirmed', {
id: txId,
hash,
} as TransactionMeta);

await flushPromises();

// Verify submitRevocation was called
expect(mockHandleRequestHandler).toHaveBeenCalledWith({
snapId: MOCK_GATOR_PERMISSIONS_PROVIDER_SNAP_ID,
origin: 'metamask',
handler: 'onRpcRequest',
request: {
jsonrpc: '2.0',
method: 'permissionsProvider_submitRevocation',
params: {
permissionContext,
revocationMetadata: {
txHash: hash,
},
},
},
});

// Verify that permissions are refreshed after revocation (getGrantedPermissions is called)
expect(mockHandleRequestHandler).toHaveBeenCalledWith({
snapId: MOCK_GATOR_PERMISSIONS_PROVIDER_SNAP_ID,
origin: 'metamask',
handler: 'onRpcRequest',
request: {
jsonrpc: '2.0',
method: 'permissionsProvider_getGrantedPermissions',
params: { isRevoked: false },
},
});
});

it('should cleanup without adding to state when transaction is rejected by user', async () => {
const mockHandleRequestHandler = jest.fn().mockResolvedValue(undefined);
const rootMessenger = getRootMessenger({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ import {
} from './errors';
import { controllerLog } from './logger';
import { GatorPermissionsSnapRpcMethod } from './types';
import type { StoredGatorPermissionSanitized } from './types';
import type {
RevocationMetadata,
StoredGatorPermissionSanitized,
} from './types';
import type {
GatorPermissionsMap,
PermissionTypesWithCustom,
Expand Down Expand Up @@ -948,9 +951,33 @@ export default class GatorPermissionsController extends BaseController<
controllerLog('Transaction confirmed, submitting revocation', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not strictly related to this PR - but do we need to check transactionMeta.status here?

When a transaction is confirmed, do we explicitly guard against failed transactions?

txId,
permissionContext,
txHash: transactionMeta.hash,
});

this.submitRevocation({ permissionContext })
// Attach metadata by parsing the confirmed transactionMeta
let revocationMetadata: RevocationMetadata | undefined;
const { hash } = transactionMeta;
if (hash === undefined) {
controllerLog(
'Failed to attach transaction hash after revocation transaction confirmed',
{
txId,
permissionContext,
error: new Error(
'Confirmed transaction is missing transaction hash',
),
},
);
} else {
revocationMetadata = {
txHash: hash as Hex,
};
}

const revocationParams = revocationMetadata
? { permissionContext, revocationMetadata }
: { permissionContext };
this.submitRevocation(revocationParams)
.catch((error) => {
controllerLog(
'Failed to submit revocation after transaction confirmed',
Expand Down
12 changes: 12 additions & 0 deletions packages/gator-permissions-controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ export type DelegationDetails = Pick<
'caveats' | 'delegator' | 'delegate' | 'authority'
>;

/**
* Represents the metadata for confirmed transaction revocation.
*/
export type RevocationMetadata = {
txHash: Hex;
};

/**
* Represents the parameters for submitting a revocation.
*/
Expand All @@ -245,6 +252,11 @@ export type RevocationParams = {
* The permission context as a hex string that identifies the permission to revoke.
*/
permissionContext: Hex;

/**
* The metadata associated with the permission revocation transaction.
*/
revocationMetadata?: RevocationMetadata;
};

/**
Expand Down
Loading