Skip to content
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

feat: revoke CAIP-25 endowment if only eip155 account or scope is removed #4978

Merged
merged 12 commits into from
Nov 26, 2024
Merged
65 changes: 49 additions & 16 deletions packages/multichain/src/caip25Permission.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('caip25EndowmentBuilder', () => {
describe('Caip25CaveatMutators.authorizedScopes', () => {
describe('removeScope', () => {
it('returns a version of the caveat with the given scope removed from requiredScopes if it is present', () => {
const ethereumGoerliCaveat = {
const caveatValue = {
requiredScopes: {
'eip155:1': {
accounts: [],
Expand All @@ -78,7 +78,7 @@ describe('caip25EndowmentBuilder', () => {
sessionProperties: {},
isMultichainOrigin: true,
};
const result = removeScope(ethereumGoerliCaveat, 'eip155:1');
const result = removeScope(caveatValue, 'eip155:1');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.UpdateValue,
value: {
Expand All @@ -93,7 +93,7 @@ describe('caip25EndowmentBuilder', () => {
});

it('returns a version of the caveat with the given scope removed from optionalScopes if it is present', () => {
const ethereumGoerliCaveat = {
const caveatValue = {
requiredScopes: {
'eip155:1': {
accounts: [],
Expand All @@ -107,7 +107,7 @@ describe('caip25EndowmentBuilder', () => {
sessionProperties: {},
isMultichainOrigin: true,
};
const result = removeScope(ethereumGoerliCaveat, 'eip155:5');
const result = removeScope(caveatValue, 'eip155:5');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.UpdateValue,
value: {
Expand All @@ -122,7 +122,7 @@ describe('caip25EndowmentBuilder', () => {
});

it('returns a version of the caveat with the given scope removed from requiredScopes and optionalScopes if it is present', () => {
const ethereumGoerliCaveat = {
const caveatValue = {
requiredScopes: {
'eip155:1': {
accounts: [],
Expand All @@ -139,7 +139,7 @@ describe('caip25EndowmentBuilder', () => {
sessionProperties: {},
isMultichainOrigin: true,
};
const result = removeScope(ethereumGoerliCaveat, 'eip155:5');
const result = removeScope(caveatValue, 'eip155:5');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.UpdateValue,
value: {
Expand All @@ -153,8 +153,25 @@ describe('caip25EndowmentBuilder', () => {
});
});

it('revokes the permission if the only eip155 scope is removed', () => {
const caveatValue = {
requiredScopes: {},
optionalScopes: {
'eip155:5': {
accounts: [],
},
},
sessionProperties: {},
isMultichainOrigin: true,
};
const result = removeScope(caveatValue, 'eip155:5');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.RevokePermission,
});
});

it('returns the caveat unchanged when the given scope is not found in either requiredScopes or optionalScopes', () => {
const ethereumGoerliCaveat = {
const caveatValue = {
requiredScopes: {
'eip155:1': {
accounts: [],
Expand All @@ -168,7 +185,7 @@ describe('caip25EndowmentBuilder', () => {
sessionProperties: {},
isMultichainOrigin: true,
};
const result = removeScope(ethereumGoerliCaveat, 'eip155:2');
const result = removeScope(caveatValue, 'eip155:2');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.Noop,
});
Expand All @@ -177,7 +194,7 @@ describe('caip25EndowmentBuilder', () => {

describe('removeAccount', () => {
it('returns a version of the caveat with the given account removed from requiredScopes if it is present', () => {
const ethereumGoerliCaveat: Caip25CaveatValue = {
const caveatValue: Caip25CaveatValue = {
requiredScopes: {
'eip155:1': {
accounts: ['eip155:1:0x1', 'eip155:1:0x2'],
Expand All @@ -186,7 +203,7 @@ describe('caip25EndowmentBuilder', () => {
optionalScopes: {},
isMultichainOrigin: true,
};
const result = removeAccount(ethereumGoerliCaveat, '0x1');
const result = removeAccount(caveatValue, '0x1');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.UpdateValue,
value: {
Expand All @@ -202,7 +219,7 @@ describe('caip25EndowmentBuilder', () => {
});

it('returns a version of the caveat with the given account removed from optionalScopes if it is present', () => {
const ethereumGoerliCaveat: Caip25CaveatValue = {
const caveatValue: Caip25CaveatValue = {
requiredScopes: {},
optionalScopes: {
'eip155:1': {
Expand All @@ -211,7 +228,7 @@ describe('caip25EndowmentBuilder', () => {
},
isMultichainOrigin: true,
};
const result = removeAccount(ethereumGoerliCaveat, '0x1');
const result = removeAccount(caveatValue, '0x1');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.UpdateValue,
value: {
Expand All @@ -227,7 +244,7 @@ describe('caip25EndowmentBuilder', () => {
});

it('returns a version of the caveat with the given account removed from requiredScopes and optionalScopes if it is present', () => {
const ethereumGoerliCaveat: Caip25CaveatValue = {
const caveatValue: Caip25CaveatValue = {
requiredScopes: {
'eip155:1': {
accounts: ['eip155:1:0x1', 'eip155:1:0x2'],
Expand All @@ -243,7 +260,7 @@ describe('caip25EndowmentBuilder', () => {
},
isMultichainOrigin: true,
};
const result = removeAccount(ethereumGoerliCaveat, '0x1');
const result = removeAccount(caveatValue, '0x1');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.UpdateValue,
value: {
Expand All @@ -265,8 +282,24 @@ describe('caip25EndowmentBuilder', () => {
});
});

it('revokes the permission when the only eip155 account is removed', () => {
const caveatValue: Caip25CaveatValue = {
requiredScopes: {},
optionalScopes: {
'eip155:1': {
accounts: ['eip155:1:0x1'],
},
},
isMultichainOrigin: true,
};
const result = removeAccount(caveatValue, '0x1');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.RevokePermission,
});
});

it('returns the caveat unchanged when the given account is not found in either requiredScopes or optionalScopes', () => {
const ethereumGoerliCaveat: Caip25CaveatValue = {
const caveatValue: Caip25CaveatValue = {
requiredScopes: {
'eip155:1': {
accounts: ['eip155:1:0x1', 'eip155:1:0x2'],
Expand All @@ -279,7 +312,7 @@ describe('caip25EndowmentBuilder', () => {
},
isMultichainOrigin: true,
};
const result = removeAccount(ethereumGoerliCaveat, '0x3');
const result = removeAccount(caveatValue, '0x3');
expect(result).toStrictEqual({
operation: CaveatMutatorOperation.Noop,
});
Expand Down
52 changes: 35 additions & 17 deletions packages/multichain/src/caip25Permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { cloneDeep, isEqual } from 'lodash';

import { getEthAccounts } from './adapters/caip-permission-adapter-eth-accounts';
import { getPermittedEthChainIds } from './adapters/caip-permission-adapter-permittedChains';
import { assertIsInternalScopesObject } from './scope/assert';
import { isSupportedScopeString } from './scope/supported';
import {
Expand Down Expand Up @@ -230,27 +231,35 @@ function removeAccount(
caip25CaveatValue: Caip25CaveatValue,
targetAddress: Hex,
) {
const copyOfCaveatValue = cloneDeep(caip25CaveatValue);
const updatedCaveatValue = cloneDeep(caip25CaveatValue);

[copyOfCaveatValue.requiredScopes, copyOfCaveatValue.optionalScopes].forEach(
(scopes) => {
Object.entries(scopes).forEach(([, scopeObject]) => {
removeAccountFromScopeObject(scopeObject, targetAddress);
});
},
);
[
updatedCaveatValue.requiredScopes,
updatedCaveatValue.optionalScopes,
].forEach((scopes) => {
Object.entries(scopes).forEach(([, scopeObject]) => {
removeAccountFromScopeObject(scopeObject, targetAddress);
});
});

const noChange = isEqual(copyOfCaveatValue, caip25CaveatValue);
const noChange = isEqual(updatedCaveatValue, caip25CaveatValue);

if (noChange) {
return {
operation: CaveatMutatorOperation.Noop,
};
}

const ethAccounts = getEthAccounts(updatedCaveatValue);
if (ethAccounts.length === 0) {
return {
operation: CaveatMutatorOperation.RevokePermission,
};
}

return {
operation: CaveatMutatorOperation.UpdateValue,
value: copyOfCaveatValue,
value: updatedCaveatValue,
};
}

Expand Down Expand Up @@ -283,17 +292,26 @@ function removeScope(
newOptionalScopes.length !==
Object.keys(caip25CaveatValue.optionalScopes).length;

if (requiredScopesRemoved || optionalScopesRemoved) {
if (!requiredScopesRemoved && !optionalScopesRemoved) {
return {
operation: CaveatMutatorOperation.Noop,
};
}

const updatedCaveatValue = {
requiredScopes: Object.fromEntries(newRequiredScopes),
optionalScopes: Object.fromEntries(newOptionalScopes),
};

const ethChainIds = getPermittedEthChainIds(updatedCaveatValue);
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
if (ethChainIds.length === 0) {
return {
operation: CaveatMutatorOperation.UpdateValue,
value: {
requiredScopes: Object.fromEntries(newRequiredScopes),
optionalScopes: Object.fromEntries(newOptionalScopes),
},
operation: CaveatMutatorOperation.RevokePermission,
};
}

return {
operation: CaveatMutatorOperation.Noop,
operation: CaveatMutatorOperation.UpdateValue,
value: updatedCaveatValue,
};
}
Loading