Skip to content

Commit

Permalink
Merge branch 'main' into jl/fix-caip25-remove-scope-mutator
Browse files Browse the repository at this point in the history
  • Loading branch information
jiexi authored Jan 22, 2025
2 parents 1c88bd5 + 16b3c05 commit 428e10b
Show file tree
Hide file tree
Showing 30 changed files with 3,293 additions and 30 deletions.
19 changes: 10 additions & 9 deletions eslint-warning-thresholds.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@
"@typescript-eslint/no-base-to-string": 3,
"@typescript-eslint/no-duplicate-enum-values": 2,
"@typescript-eslint/no-unsafe-enum-comparison": 34,
"@typescript-eslint/no-unused-vars": 36,
"@typescript-eslint/prefer-promise-reject-errors": 13,
"@typescript-eslint/prefer-readonly": 145,
"@typescript-eslint/no-unused-vars": 41,
"@typescript-eslint/prefer-promise-reject-errors": 33,
"@typescript-eslint/prefer-readonly": 147,
"@typescript-eslint/switch-exhaustiveness-check": 0,
"import-x/namespace": 189,
"import-x/no-named-as-default": 1,
"import-x/no-named-as-default-member": 8,
"import-x/order": 205,
"jest/no-conditional-in-test": 129,
"import-x/order": 211,
"jest/no-conditional-in-test": 138,
"jest/prefer-lowercase-title": 2,
"jest/prefer-strict-equal": 2,
"jsdoc/check-tag-names": 375,
"jsdoc/require-returns": 22,
"jsdoc/tag-lines": 328,
"n/no-unsupported-features/node-builtins": 4,
"jsdoc/require-returns": 25,
"jsdoc/tag-lines": 335,
"n/no-unsupported-features/node-builtins": 14,
"n/prefer-global/text-encoder": 4,
"n/prefer-global/text-decoder": 4,
"prettier/prettier": 112,
"prettier/prettier": 116,
"promise/always-return": 3,
"promise/catch-or-return": 2,
"promise/param-names": 8,
Expand Down
5 changes: 5 additions & 0 deletions packages/multichain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@
"@metamask/controller-utils": "^11.4.5",
"@metamask/eth-json-rpc-filters": "^9.0.0",
"@metamask/rpc-errors": "^7.0.2",
"@metamask/safe-event-emitter": "^3.0.0",
"@metamask/utils": "^11.0.1",
"@open-rpc/schema-utils-js": "^2.0.5",
"jsonschema": "^1.4.1",
"lodash": "^4.17.21"
},
"devDependencies": {
"@metamask/auto-changelog": "^3.4.4",
"@metamask/json-rpc-engine": "^10.0.2",
"@metamask/network-controller": "^22.1.1",
"@metamask/permission-controller": "^11.0.5",
"@open-rpc/meta-schema": "^1.14.6",
"@types/jest": "^27.4.1",
"deepmerge": "^4.2.2",
"jest": "^27.5.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toHex } from '@metamask/controller-utils';
import type { Hex } from '@metamask/utils';
import { KnownCaipNamespace } from '@metamask/utils';
import { hexToBigInt, KnownCaipNamespace } from '@metamask/utils';

import type { Caip25CaveatValue } from '../caip25Permission';
import { getUniqueArrayItems } from '../scope/transform';
Expand Down Expand Up @@ -57,7 +57,7 @@ export const addPermittedEthChainId = (
caip25CaveatValue: Caip25CaveatValue,
chainId: Hex,
): Caip25CaveatValue => {
const scopeString = `eip155:${parseInt(chainId, 16)}`;
const scopeString = `eip155:${hexToBigInt(chainId).toString(10)}`;
if (
Object.keys(caip25CaveatValue.requiredScopes).includes(scopeString) ||
Object.keys(caip25CaveatValue.optionalScopes).includes(scopeString)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {
KnownNotifications,
KnownRpcMethods,
KnownWalletNamespaceRpcMethods,
KnownWalletRpcMethods,
} from '../scope/constants';
import {
getInternalScopesObject,
getSessionScopes,
} from './caip-permission-adapter-session-scopes';

describe('CAIP-25 session scopes adapters', () => {
describe('getInternalScopesObject', () => {
it('returns an InternalScopesObject with only the accounts from each NormalizedScopeObject', () => {
const result = getInternalScopesObject({
'wallet:eip155': {
methods: ['foo', 'bar'],
notifications: ['baz'],
accounts: ['wallet:eip155:0xdead'],
},
'eip155:1': {
methods: ['eth_call'],
notifications: ['eth_subscription'],
accounts: ['eip155:1:0xdead', 'eip155:1:0xbeef'],
},
});

expect(result).toStrictEqual({
'wallet:eip155': {
accounts: ['wallet:eip155:0xdead'],
},
'eip155:1': {
accounts: ['eip155:1:0xdead', 'eip155:1:0xbeef'],
},
});
});
});

describe('getSessionScopes', () => {
it('returns a NormalizedScopesObject for the wallet scope', () => {
const result = getSessionScopes({
requiredScopes: {},
optionalScopes: {
wallet: {
accounts: [],
},
},
});

expect(result).toStrictEqual({
wallet: {
methods: KnownWalletRpcMethods,
notifications: [],
accounts: [],
},
});
});

it('returns a NormalizedScopesObject for the wallet:eip155 scope', () => {
const result = getSessionScopes({
requiredScopes: {},
optionalScopes: {
'wallet:eip155': {
accounts: ['wallet:eip155:0xdeadbeef'],
},
},
});

expect(result).toStrictEqual({
'wallet:eip155': {
methods: KnownWalletNamespaceRpcMethods.eip155,
notifications: [],
accounts: ['wallet:eip155:0xdeadbeef'],
},
});
});

it('returns a NormalizedScopesObject with empty methods and notifications for scope with wallet namespace and unknown reference', () => {
const result = getSessionScopes({
requiredScopes: {},
optionalScopes: {
'wallet:foobar': {
accounts: ['wallet:foobar:0xdeadbeef'],
},
},
});

expect(result).toStrictEqual({
'wallet:foobar': {
methods: [],
notifications: [],
accounts: ['wallet:foobar:0xdeadbeef'],
},
});
});

it('returns a NormalizedScopesObject with empty methods and notifications for scope not wallet namespace and unknown reference', () => {
const result = getSessionScopes({
requiredScopes: {},
optionalScopes: {
'foo:1': {
accounts: ['foo:1:0xdeadbeef'],
},
},
});

expect(result).toStrictEqual({
'foo:1': {
methods: [],
notifications: [],
accounts: ['foo:1:0xdeadbeef'],
},
});
});

it('returns a NormalizedScopesObject for a eip155 namespaced scope', () => {
const result = getSessionScopes({
requiredScopes: {},
optionalScopes: {
'eip155:1': {
accounts: ['eip155:1:0xdeadbeef'],
},
},
});

expect(result).toStrictEqual({
'eip155:1': {
methods: KnownRpcMethods.eip155,
notifications: KnownNotifications.eip155,
accounts: ['eip155:1:0xdeadbeef'],
},
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { KnownCaipNamespace } from '@metamask/utils';

import type { Caip25CaveatValue } from '../caip25Permission';
import {
KnownNotifications,
KnownRpcMethods,
KnownWalletNamespaceRpcMethods,
KnownWalletRpcMethods,
} from '../scope/constants';
import { mergeScopes } from '../scope/transform';
import type {
InternalScopesObject,
NonWalletKnownCaipNamespace,
NormalizedScopesObject,
} from '../scope/types';
import { parseScopeString } from '../scope/types';

/**
* Converts an NormalizedScopesObject to a InternalScopesObject.
* @param normalizedScopesObject - The NormalizedScopesObject to convert.
* @returns An InternalScopesObject.
*/
export const getInternalScopesObject = (
normalizedScopesObject: NormalizedScopesObject,
) => {
const internalScopes: InternalScopesObject = {};

Object.entries(normalizedScopesObject).forEach(
([_scopeString, { accounts }]) => {
const scopeString = _scopeString as keyof typeof normalizedScopesObject;

internalScopes[scopeString] = {
accounts,
};
},
);

return internalScopes;
};

/**
* Converts an InternalScopesObject to a NormalizedScopesObject.
* @param internalScopesObject - The InternalScopesObject to convert.
* @returns A NormalizedScopesObject.
*/
const getNormalizedScopesObject = (
internalScopesObject: InternalScopesObject,
) => {
const normalizedScopes: NormalizedScopesObject = {};

Object.entries(internalScopesObject).forEach(
([_scopeString, { accounts }]) => {
const scopeString = _scopeString as keyof typeof internalScopesObject;
const { namespace, reference } = parseScopeString(scopeString);
let methods: string[] = [];
let notifications: string[] = [];

if (namespace === KnownCaipNamespace.Wallet) {
if (reference) {
methods =
KnownWalletNamespaceRpcMethods[
reference as NonWalletKnownCaipNamespace
] ?? [];
} else {
methods = KnownWalletRpcMethods;
}
} else {
methods =
KnownRpcMethods[namespace as NonWalletKnownCaipNamespace] ?? [];
notifications =
KnownNotifications[namespace as NonWalletKnownCaipNamespace] ?? [];
}

normalizedScopes[scopeString] = {
methods,
notifications,
accounts,
};
},
);

return normalizedScopes;
};

/**
* Takes the scopes from an endowment:caip25 permission caveat value,
* hydrates them with supported methods and notifications, and returns a NormalizedScopesObject.
* @param caip25CaveatValue - The CAIP-25 CaveatValue to convert.
* @returns A NormalizedScopesObject.
*/
export const getSessionScopes = (
caip25CaveatValue: Pick<
Caip25CaveatValue,
'requiredScopes' | 'optionalScopes'
>,
) => {
return mergeScopes(
getNormalizedScopesObject(caip25CaveatValue.requiredScopes),
getNormalizedScopesObject(caip25CaveatValue.optionalScopes),
);
};
Loading

0 comments on commit 428e10b

Please sign in to comment.