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

**BREAKING**: Update name lookup API #2113

Merged
merged 33 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
13be033
update endowment, types, caveats and example
hmalik88 Jan 19, 2024
3d612ae
Merge branch 'main' into hm/update-name-lookup
hmalik88 Jan 19, 2024
bd305f5
fix example snap manifest
hmalik88 Jan 19, 2024
570fe59
update shasum
hmalik88 Jan 19, 2024
bfab969
update coverage
hmalik88 Jan 19, 2024
a3714e9
fix validator logic and update coverage for snap controller
hmalik88 Jan 19, 2024
520541a
update coverage (again)
hmalik88 Jan 19, 2024
505be10
fix utils coverage
hmalik88 Jan 19, 2024
be2daaf
Merge branch 'main' into hm/update-name-lookup
hmalik88 Jan 22, 2024
54c0477
export types
hmalik88 Jan 22, 2024
de1e344
update per review
hmalik88 Jan 22, 2024
885a412
update snapshot and make response nullable
hmalik88 Jan 22, 2024
18eb292
Merge branch 'main' into hm/update-name-lookup
hmalik88 Jan 22, 2024
f3190d0
used generic permission validator and updated caveat structs
hmalik88 Jan 22, 2024
63efb40
update tests
hmalik88 Jan 22, 2024
cb1b74e
fix tests, update coverage
hmalik88 Jan 22, 2024
9ce718d
fix coverage
hmalik88 Jan 22, 2024
2369502
fix utils coverage
hmalik88 Jan 22, 2024
9d2dabc
Merge branch 'main' into hm/update-name-lookup
hmalik88 Jan 23, 2024
31fd10f
update per comments
hmalik88 Jan 23, 2024
92f1cb1
fix test
hmalik88 Jan 24, 2024
c12b3e5
update coverage
hmalik88 Jan 24, 2024
5859ccc
update structs
hmalik88 Jan 24, 2024
1195cbd
update test
hmalik88 Jan 24, 2024
f57e2f0
update coverage
hmalik88 Jan 24, 2024
ec59349
Merge branch 'main' into hm/update-name-lookup
hmalik88 Jan 24, 2024
3944601
update utils coverage again
hmalik88 Jan 24, 2024
e4138a3
update per review
hmalik88 Jan 25, 2024
1e67c54
Merge branch 'main' into hm/update-name-lookup
hmalik88 Jan 25, 2024
c012649
fix tests
hmalik88 Jan 25, 2024
617b6db
update types
hmalik88 Jan 25, 2024
da9bd77
update caveat getters, test and snap controller coverage
hmalik88 Jan 25, 2024
39f5d0d
update coverage
hmalik88 Jan 25, 2024
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
10 changes: 6 additions & 4 deletions packages/examples/packages/name-lookup/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "Sbu/MyQ6Mrxr6/4DDjd6SVjESJ2jrWASZSHc5JukBBo=",
"shasum": "mnFLBYHzMpTmIdjvtO3JHGmecaqtcb4g/Tnz7VI7zV8=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand All @@ -17,9 +17,11 @@
}
},
"initialPermissions": {
"endowment:name-lookup": [
"eip155:1"
]
"endowment:name-lookup": {
hmalik88 marked this conversation as resolved.
Show resolved Hide resolved
"chains": [
"eip155:1"
]
}
},
"manifestVersion": "0.1"
}
15 changes: 12 additions & 3 deletions packages/examples/packages/name-lookup/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ describe('onNameLookup', () => {
};

expect(await onNameLookup(request)).toStrictEqual({
resolvedAddress: '0xc0ffee254729296a45a3885639AC7E10F9d54979',
resolvedAddresses: [
{
resolvedAddress: '0xc0ffee254729296a45a3885639AC7E10F9d54979',
protocol: 'test protocol',
},
],
});
});

Expand All @@ -26,7 +31,9 @@ describe('onNameLookup', () => {
};

expect(await onNameLookup(request)).toStrictEqual({
resolvedDomain: 'c0f.1.test.domain',
resolvedDomains: [
{ resolvedDomain: 'c0f.1.test.domain', protocol: 'test protocol' },
],
});
});

Expand All @@ -38,7 +45,9 @@ describe('onNameLookup', () => {
} as any;

expect(await onNameLookup(request)).toStrictEqual({
resolvedDomain: 'c0f.1.test.domain',
resolvedDomains: [
{ resolvedDomain: 'c0f.1.test.domain', protocol: 'test protocol' },
],
});
});

Expand Down
6 changes: 4 additions & 2 deletions packages/examples/packages/name-lookup/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ export const onNameLookup: OnNameLookupHandler = async (request) => {
const shortAddress = address.substring(2, 5);
const chainIdDecimal = parseInt(chainId.split(':')[1], 10);
const resolvedDomain = `${shortAddress}.${chainIdDecimal}.test.domain`;
return { resolvedDomain };
return { resolvedDomains: [{ resolvedDomain, protocol: 'test protocol' }] };
}

if (domain) {
const resolvedAddress = '0xc0ffee254729296a45a3885639AC7E10F9d54979';
return { resolvedAddress };
return {
resolvedAddresses: [{ resolvedAddress, protocol: 'test protocol' }],
};
}

return null;
Expand Down
8 changes: 4 additions & 4 deletions packages/snaps-controllers/coverage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"branches": 90.87,
"functions": 96.7,
"lines": 97.86,
"statements": 97.57
"branches": 89.7,
"functions": 96.73,
"lines": 97.67,
"statements": 97.38
}
4 changes: 4 additions & 0 deletions packages/snaps-controllers/src/snaps/SnapController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
getValidatedLocalizationFiles,
VirtualFile,
NpmSnapFileNames,
OnNameLookupResponseStruct,
} from '@metamask/snaps-utils';
import type { Json, NonEmptyArray, SemVerRange } from '@metamask/utils';
import {
Expand Down Expand Up @@ -2926,6 +2927,9 @@
this.#checkPhishingList.bind(this),
);
break;
case HandlerType.OnNameLookup:
assertStruct(result, OnNameLookupResponseStruct);
hmalik88 marked this conversation as resolved.
Show resolved Hide resolved
break;

Check warning on line 2932 in packages/snaps-controllers/src/snaps/SnapController.ts

View check run for this annotation

Codecov / codecov/patch

packages/snaps-controllers/src/snaps/SnapController.ts#L2930-L2932

Added lines #L2930 - L2932 were not covered by tests
hmalik88 marked this conversation as resolved.
Show resolved Hide resolved
default:
break;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/snaps-controllers/src/snaps/endowments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ export * from './enum';
export { getRpcCaveatOrigins } from './rpc';
export { getSignatureOriginCaveat } from './signature-insight';
export { getTransactionOriginCaveat } from './transaction-insight';
export { getChainIdsCaveat } from './name-lookup';
export { getChainIdsCaveat, getLookupMatchersCaveat } from './name-lookup';
export { getKeyringCaveatOrigins } from './keyring';
188 changes: 160 additions & 28 deletions packages/snaps-controllers/src/snaps/endowments/name-lookup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SnapEndowments } from '.';
import {
nameLookupEndowmentBuilder,
getChainIdsCaveat,
getLookupMatchersCaveat,
getNameLookupCaveatMapper,
nameLookupCaveatSpecifications,
} from './name-lookup';
Expand All @@ -17,7 +18,7 @@ describe('endowment:name-lookup', () => {
permissionType: PermissionType.Endowment,
targetName: SnapEndowments.NameLookup,
endowmentGetter: expect.any(Function),
allowedCaveats: [SnapCaveatType.ChainIds],
allowedCaveats: [SnapCaveatType.ChainIds, SnapCaveatType.LookupMatchers],
subjectTypes: [SubjectType.Snap],
validator: expect.any(Function),
});
Expand All @@ -30,16 +31,20 @@ describe('endowment:name-lookup', () => {
expect(() =>
// @ts-expect-error Missing required permission types.
specification.validator({}),
).toThrow('Expected a single "chainIds" caveat.');
).toThrow(
'Expected the following caveats: "chainIds", "lookupMatchers".',
);
});

it('throws if the caveat is not a single "chainIds"', () => {
it('throws if the caveats are not one or both of "chainIds" and "lookupMatchers".', () => {
expect(() =>
// @ts-expect-error Missing other required permission types.
specification.validator({
caveats: [{ type: 'foo', value: 'bar' }],
}),
).toThrow('Expected a single "chainIds" caveat.');
).toThrow(
'Expected the following caveats: "chainIds", "lookupMatchers", received "foo".',
);

expect(() =>
// @ts-expect-error Missing other required permission types.
Expand All @@ -49,7 +54,7 @@ describe('endowment:name-lookup', () => {
{ type: 'chainIds', value: ['bar'] },
],
}),
).toThrow('Expected a single "chainIds" caveat.');
).toThrow('Duplicate caveats are not allowed.');
});
});
});
Expand Down Expand Up @@ -87,28 +92,60 @@ describe('getChainIdsCaveat', () => {
expect(getChainIdsCaveat(permission)).toBeNull();
});

it('throws if the permission does not have exactly one caveat', () => {
it('throws if there is not a "chainIds" caveat', () => {
const permission: PermissionConstraint = {
date: 0,
parentCapability: 'foo',
invoker: 'bar',
id: 'baz',
caveats: [
{
type: SnapCaveatType.ChainIds,
value: ['eip155:1'],
type: SnapCaveatType.PermittedCoinTypes,
value: 'foo',
},
],
};

expect(() => getChainIdsCaveat(permission)).toThrow('Assertion failed');
});
});

describe('getLookupMatchersCaveat', () => {
it('returns the value from a name-lookup permission', () => {
const permission: PermissionConstraint = {
date: 0,
parentCapability: 'foo',
invoker: 'bar',
id: 'baz',
caveats: [
{
type: SnapCaveatType.ChainIds,
value: ['eip155:2'],
type: SnapCaveatType.LookupMatchers,
value: { tlds: ['lens'] },
},
],
};
expect(getLookupMatchersCaveat(permission)).toStrictEqual({
tlds: ['lens'],
});
});

expect(() => getChainIdsCaveat(permission)).toThrow('Assertion failed');
it('returns null if the input is undefined', () => {
expect(getLookupMatchersCaveat(undefined)).toBeNull();
});

it('throws if the first caveat is not a "chainIds" caveat', () => {
it('returns null if the permission does not have caveats', () => {
const permission: PermissionConstraint = {
date: 0,
parentCapability: 'foo',
invoker: 'bar',
id: 'baz',
caveats: null,
};

expect(getLookupMatchersCaveat(permission)).toBeNull();
});

it('throws if there is not a "matchers" caveat', () => {
const permission: PermissionConstraint = {
date: 0,
parentCapability: 'foo',
Expand All @@ -122,20 +159,46 @@ describe('getChainIdsCaveat', () => {
],
};

expect(() => getChainIdsCaveat(permission)).toThrow('Assertion failed');
expect(() => getLookupMatchersCaveat(permission)).toThrow(
'Assertion failed',
);
});
});

describe('getNameLookupCaveatMapper', () => {
it('maps input to a caveat', () => {
expect(getNameLookupCaveatMapper(['eip155:1'])).toStrictEqual({
expect(getNameLookupCaveatMapper({ chains: ['eip155:1'] })).toStrictEqual({
caveats: [
{
type: 'chainIds',
value: ['eip155:1'],
},
],
});

expect(
getNameLookupCaveatMapper({ matchers: { tlds: ['lens'] } }),
).toStrictEqual({
caveats: [
{
type: 'lookupMatchers',
value: { tlds: ['lens'] },
},
],
});

expect(
getNameLookupCaveatMapper({
matchers: { tlds: ['lens'], schemes: ['fio'] },
}),
).toStrictEqual({
caveats: [
{
type: 'lookupMatchers',
value: { tlds: ['lens'], schemes: ['fio'] },
},
],
});
});

it('does not include caveat if input is empty array', () => {
Expand All @@ -158,21 +221,81 @@ describe('nameLookupCaveatSpecifications', () => {
).toThrow('Expected a plain object.');
});

it.each([
{
type: SnapCaveatType.ChainIds,
value: ['eip155'],
},
{
type: SnapCaveatType.ChainIds,
value: undefined,
},
])('throws if the caveat values are invalid types', (val) => {
it('throws if the caveat values are invalid for the "chainIds" caveat', () => {
expect(() =>
nameLookupCaveatSpecifications[SnapCaveatType.ChainIds].validator?.(
val,
),
).toThrow('Expected caveat value to have type "string array"');
nameLookupCaveatSpecifications[SnapCaveatType.ChainIds].validator?.({
type: SnapCaveatType.ChainIds,
value: ['eip155'],
}),
).toThrow(
'Assertion failed: At path: 0 -- Expected a Chain ID matching `/^(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-a-zA-Z0-9]{1,32})$/` but received "eip155".',
);

expect(() =>
nameLookupCaveatSpecifications[SnapCaveatType.ChainIds].validator?.({
type: SnapCaveatType.ChainIds,
value: undefined,
}),
).toThrow(
'Assertion failed: Expected an array value, but received: undefined.',
);
});

it('throws if the caveat values are invalid for the "matchers" caveat', () => {
expect(() =>
nameLookupCaveatSpecifications[
SnapCaveatType.LookupMatchers
].validator?.({
type: SnapCaveatType.LookupMatchers,
value: undefined,
}),
).toThrow(
'Assertion failed: Expected an object, but received: undefined.',
);

expect(() =>
nameLookupCaveatSpecifications[
SnapCaveatType.LookupMatchers
].validator?.({
type: SnapCaveatType.LookupMatchers,
value: { foo: 'bar', tlds: ['lens'], schemes: ['fio'] },
}),
).toThrow(
'Assertion failed: At path: foo -- Expected a value of type `never`, but received: `"bar"`.',
);

expect(() =>
nameLookupCaveatSpecifications[
SnapCaveatType.LookupMatchers
].validator?.({
type: SnapCaveatType.LookupMatchers,
value: { foo: 'bar' },
}),
).toThrow(
'Assertion failed: At path: foo -- Expected a value of type `never`, but received: `"bar"`.',
);

expect(() =>
nameLookupCaveatSpecifications[
SnapCaveatType.LookupMatchers
].validator?.({
type: SnapCaveatType.LookupMatchers,
value: { tlds: ['lens'], schemes: [1, 2] },
}),
).toThrow(
'Assertion failed: At path: schemes.0 -- Expected a string, but received: 1.',
);

expect(() =>
nameLookupCaveatSpecifications[
SnapCaveatType.LookupMatchers
].validator?.({
type: SnapCaveatType.LookupMatchers,
value: { tlds: [1, 2], schemes: ['fio'] },
}),
).toThrow(
'Assertion failed: At path: tlds.0 -- Expected a string, but received: 1.',
);
});

it('will not throw with a valid caveat value', () => {
Expand All @@ -182,6 +305,15 @@ describe('nameLookupCaveatSpecifications', () => {
value: ['eip155:1'],
}),
).not.toThrow();

expect(() =>
nameLookupCaveatSpecifications[
SnapCaveatType.LookupMatchers
].validator?.({
type: SnapCaveatType.LookupMatchers,
value: { tlds: ['lens'], schemes: ['fio'] },
}),
).not.toThrow();
});
});
});
Loading