Skip to content

Conversation

@V00D00-child
Copy link
Member

@V00D00-child V00D00-child commented Nov 12, 2025

Description

Currently, during permission revocation submission, we store a boolean revoked flag to track the permission revocation status in profile sync. This PR extends the permission revocation submission process to allow storing additional metadata on the revocation transaction.

References

Required by(Core): Attach metadata when submitting a revocation to the permission provider snap

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Introduces on-chain-aware revocation handling and metadata persistence.

  • Profile Sync: Extends StoredGrantedPermission with revocationMetadata and updates updatePermissionRevocationStatus to persist/clear it; validates via zod; maintains 400kb limits
  • RPC: submitRevocation now validates revocationMetadata, checks delegation disabled on-chain, optionally validates txHash via receipt status, then stores revocation with metadata
  • Blockchain utilities: New BlockchainMetadataClient for on-chain checks; adds getTransactionReceipt with retry logic and validateTransactionReceipt
  • Types/validation: Adds TransactionReceipt type and zTransactionReceipt; updates validateRevocationParams to accept revocationMetadata
  • Wiring: Instantiates and passes BlockchainMetadataClient in index.ts
  • Tests: Comprehensive unit tests added/updated for clients, RPC handler, and profile sync

Written by Cursor Bugbot for commit 81e61df. This will update automatically on new commits. Configure here.

@V00D00-child V00D00-child marked this pull request as ready for review December 17, 2025 22:28
@V00D00-child V00D00-child requested a review from a team as a code owner December 17, 2025 22:28
Copy link
Contributor

@jeffsmale90 jeffsmale90 left a comment

Choose a reason for hiding this comment

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

A couple of general comments, and, I think a more architectural concern:

I think we should remove isRevoked from the stored permission, and use the existence of revocationMetadata to determine whether the permission is revoked to help improve data integrity.

logger.debug('submitRevocation() called with params:', params);

const { permissionContext } = validateRevocationParams(params);
const { permissionContext, metadata } = validateRevocationParams(params);
Copy link
Contributor

Choose a reason for hiding this comment

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

we are trusting the timestamp provided by the caller.

We could accept just the txhash (instead of the metadata), fetch the block, and fetch it's timestamp. We are already fetching the tx receipt to ensure it's success.

I don't know how important it is that we have the correct block timestamp.

Copy link
Member Author

@V00D00-child V00D00-child Dec 19, 2025

Choose a reason for hiding this comment

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

I dropped the block timestamp from the metadata. If we ever need a block timestamp to present to the user in the MM client, we can fetch the tx receipt. Seems unnecessary to store block timestamp in the profile sync.

* @throws ChainDisconnectedError if the provider is on the wrong chain.
* @throws ResourceUnavailableError if the on-chain check fails and we cannot determine the status.
*/
public async checkTransactionReceipt({
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is the correct place for this function - this class is a "Client that fetches token metadata directly from the blockchain".

Copy link
Member Author

Choose a reason for hiding this comment

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

I was following the pattern of checkDelegationDisabledOnChain, which is also in this file, to maintain consistency. It's a bit confusing since the file name is blockchainMetadataClient but the class name in the file is BlockchainTokenMetadataClient.

My suggestion here:

  1. Create a new class in the file called BlockchainMetadataClient
  2. Move checkDelegationDisabledOnChain() and checkTransactionReceipt() into that new class

Copy link
Member Author

Choose a reason for hiding this comment

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

I created a new class, BlockchainMetadataClient, and moved checkDelegationDisabledOnChain() and checkTransactionReceipt() into it.

Comment on lines +182 to +184
throw new InternalError(
`Transaction receipt not found after ${retries + 1} attempts`,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the code here can never execute because the loop either returns, throws, or continues.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, the throw after the loop is unreachable, but it still satisfies TypeScript's control-flow analysis(ie, ts complains with Function lacks ending return statement, and return type does not include 'undefined') when we remove it, even though the code can't logically reach certain points.

Comment on lines +1124 to +1126
mockBlockchainMetadataClient.checkTransactionReceipt.mockResolvedValueOnce(
true,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

All submitRevocation tests mock checkTransactionReceipt to return true, but there's no test for when it returns false

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a test case that captures when checkTransactionReceipt.mockResolvedValueOnce returns false which should throw an error - Error(Transaction ${txHash} was not successful. Cannot process revocation.)

… make txHash property optional on RevocationMetadata type
…ationMetadata to handle legacy data that was created before revocationMetadata was introduced
…egation disable and transaction receipt functions checks to BlockchainMetadataClient class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants