Skip to content

Commit c6f220b

Browse files
committed
added burn fuses tuple
1 parent 0b11f63 commit c6f220b

File tree

5 files changed

+106
-38
lines changed

5 files changed

+106
-38
lines changed

packages/ensjs/src/functions/burnFuses.test.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,25 @@ describe('burnFuses', () => {
2121
beforeEach(async () => {
2222
await revert()
2323
})
24-
it('should return a burnFuses transaction and succeed', async () => {
24+
it('should return a burnFuses transaction from an array and succeed', async () => {
2525
const tx = await ENSInstance.burnFuses('wrapped.eth', {
26-
fusesToBurn: new Set(['CANNOT_UNWRAP', 'CANNOT_CREATE_SUBDOMAIN', 'CANNOT_SET_TTL']),
26+
fuseArrayToBurn: [
27+
'CANNOT_UNWRAP',
28+
'CANNOT_CREATE_SUBDOMAIN',
29+
'CANNOT_SET_TTL',
30+
],
31+
addressOrIndex: accounts[1],
32+
})
33+
expect(tx).toBeTruthy()
34+
await tx.wait()
35+
36+
const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
37+
const [fuses] = await nameWrapper.getFuses(namehash('wrapped.eth'))
38+
expect(fuses).toBe(113)
39+
})
40+
it('should return a burnFuses transaction from a number and succeed', async () => {
41+
const tx = await ENSInstance.burnFuses('wrapped.eth', {
42+
fuseNumberToBurn: 49,
2743
addressOrIndex: accounts[1],
2844
})
2945
expect(tx).toBeTruthy()
+56-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,68 @@
11
import { ENSArgs } from '..'
2-
import { namehash } from '../utils/normalise'
32
import { fuseEnum } from '../utils/fuses'
3+
import { namehash } from '../utils/normalise'
4+
5+
type Fuse = keyof typeof fuseEnum
6+
type FuseArrayPossibilities =
7+
| [Fuse]
8+
| [Fuse, Fuse]
9+
| [Fuse, Fuse, Fuse]
10+
| [Fuse, Fuse, Fuse, Fuse]
11+
| [Fuse, Fuse, Fuse, Fuse, Fuse]
12+
| [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse]
13+
| [Fuse, Fuse, Fuse, Fuse, Fuse, Fuse, Fuse]
14+
15+
type FusesWithoutDuplicates<A, B = never> = A extends FuseArrayPossibilities
16+
? A extends [infer Head, ...infer Tail]
17+
? Head extends B
18+
? []
19+
: [Head, ...FusesWithoutDuplicates<Tail, Head | B>]
20+
: A
21+
: []
22+
23+
type FusePropsArray<A extends FuseArrayPossibilities> = {
24+
fuseArrayToBurn: FusesWithoutDuplicates<A>
25+
}
26+
27+
type FusePropsNumber = {
28+
fuseNumberToBurn: number
29+
}
430

5-
export default async function (
31+
type FuseProps<A extends FuseArrayPossibilities> =
32+
| FusePropsArray<A>
33+
| FusePropsNumber
34+
35+
export default async function <A extends FuseArrayPossibilities>(
636
{ contracts, signer }: ENSArgs<'contracts' | 'signer'>,
737
name: string,
8-
{
9-
fusesToBurn,
10-
}: {
11-
fusesToBurn: Set<Partial<keyof typeof fuseEnum>>
12-
},
38+
props: FuseProps<A>,
1339
) {
40+
const isArray = 'fuseArrayToBurn' in props
41+
if (!isArray) {
42+
if (props.fuseNumberToBurn > 2 ** 32) {
43+
throw new Error(
44+
`Fuse number must be limited to Uin32, ${props.fuseNumberToBurn} was too high.`,
45+
)
46+
}
47+
} else {
48+
for (const fuse of props.fuseArrayToBurn) {
49+
if (!(fuse in fuseEnum)) {
50+
throw new Error(`${fuse} is not a valid fuse`)
51+
}
52+
}
53+
}
54+
1455
const nameWrapper = (await contracts?.getNameWrapper()!).connect(signer)
1556
const hash = namehash(name)
1657

17-
const encodedFuses = Array.from(fusesToBurn).reduce((previousValue: number, currentValue): number => {
18-
return previousValue + fuseEnum[currentValue]
19-
}, 0)
58+
const encodedFuses = isArray
59+
? Array.from(props.fuseArrayToBurn).reduce(
60+
(previousValue: number, currentValue): number => {
61+
return previousValue + fuseEnum[currentValue as Fuse]
62+
},
63+
0,
64+
)
65+
: props.fuseNumberToBurn
2066

2167
return nameWrapper.populateTransaction.setFuses(hash, encodedFuses)
2268
}

packages/ensjs/src/functions/getFuses.test.ts

+20-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { BigNumber, ethers } from 'ethers'
2-
import { resolveRequestDocument } from 'graphql-request'
32
import { ENS } from '..'
43
import setup from '../tests/setup'
54

@@ -11,19 +10,19 @@ let accounts: string[]
1110
let withWrappedSnapshot: any
1211

1312
const unwrappedNameDefault = {
14-
expiryDate: new Date(0).toString(),
13+
expiryDate: new Date(0).toString(),
1514
fuseObj: {
16-
CANNOT_BURN_FUSES: false,
17-
CANNOT_CREATE_SUBDOMAIN: false,
18-
CANNOT_SET_RESOLVER: false,
19-
CANNOT_SET_TTL: false,
20-
CANNOT_TRANSFER: false,
21-
CANNOT_UNWRAP: false,
22-
PARENT_CANNOT_CONTROL: false,
23-
canDoEverything: true
24-
},
25-
owner: "0x0000000000000000000000000000000000000000",
26-
rawFuses: BigNumber.from(0)
15+
CANNOT_BURN_FUSES: false,
16+
CANNOT_CREATE_SUBDOMAIN: false,
17+
CANNOT_SET_RESOLVER: false,
18+
CANNOT_SET_TTL: false,
19+
CANNOT_TRANSFER: false,
20+
CANNOT_UNWRAP: false,
21+
PARENT_CANNOT_CONTROL: false,
22+
canDoEverything: true,
23+
},
24+
owner: '0x0000000000000000000000000000000000000000',
25+
rawFuses: BigNumber.from(0),
2726
}
2827

2928
beforeAll(async () => {
@@ -45,7 +44,9 @@ afterAll(async () => {
4544
describe('getFuses', () => {
4645
it('should return default data for an unwrapped name', async () => {
4746
const result = await ENSInstance.getFuses('with-profile.eth')
48-
expect({ ...result, expiryDate: result?.expiryDate.toString() }).toEqual(unwrappedNameDefault)
47+
expect({ ...result, expiryDate: result?.expiryDate.toString() }).toEqual(
48+
unwrappedNameDefault,
49+
)
4950
})
5051
it('should return with canDoEverything set to true for a name with no fuses burned', async () => {
5152
const nameWrapper = await ENSInstance.contracts!.getNameWrapper()!
@@ -64,7 +65,11 @@ describe('getFuses', () => {
6465
})
6566
it('should return with other correct fuses', async () => {
6667
const tx = await ENSInstance.burnFuses('wrapped.eth', {
67-
fusesToBurn: ['CANNOT_UNWRAP', 'CANNOT_CREATE_SUBDOMAIN', 'CANNOT_SET_TTL'],
68+
fuseArrayToBurn: [
69+
'CANNOT_UNWRAP',
70+
'CANNOT_CREATE_SUBDOMAIN',
71+
'CANNOT_SET_TTL',
72+
],
6873
addressOrIndex: 1,
6974
})
7075
await tx.wait()

packages/ensjs/src/utils/fuses.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ const CANNOT_CREATE_SUBDOMAIN = 32
77
const PARENT_CANNOT_CONTROL = 64
88
const CAN_DO_EVERYTHING = 0
99

10-
export const fuseEnum: { [key: string]: number } = {
10+
export const fuseEnum = {
1111
CANNOT_UNWRAP,
1212
CANNOT_BURN_FUSES,
1313
CANNOT_TRANSFER,
1414
CANNOT_SET_RESOLVER,
1515
CANNOT_SET_TTL,
1616
CANNOT_CREATE_SUBDOMAIN,
1717
PARENT_CANNOT_CONTROL,
18-
}
18+
} as const
1919

20-
const fullFuseEnum: { [key: string]: number } = {
20+
const fullFuseEnum = {
2121
...fuseEnum,
2222
CAN_DO_EVERYTHING,
2323
}

tsconfig.json

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"compilerOptions": {
3+
"noErrorTruncation": true,
34
/* Visit https://aka.ms/tsconfig.json to read more about this file */
45

56
/* Projects */
@@ -11,7 +12,7 @@
1112
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
1213

1314
/* Language and Environment */
14-
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15+
"target": "es2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
1516
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
1617
// "jsx": "preserve", /* Specify what JSX code is generated. */
1718
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
@@ -24,9 +25,9 @@
2425
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
2526

2627
/* Modules */
27-
"module": "es2020", /* Specify what module code is generated. */
28+
"module": "es2020" /* Specify what module code is generated. */,
2829
// "rootDir": "./", /* Specify the root folder within your source files. */
29-
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30+
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
3031
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
3132
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
3233
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
@@ -69,12 +70,12 @@
6970
/* Interop Constraints */
7071
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
7172
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
72-
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
73+
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
7374
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
74-
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
75+
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
7576

7677
/* Type Checking */
77-
"strict": true, /* Enable all strict type-checking options. */
78+
"strict": true /* Enable all strict type-checking options. */,
7879
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
7980
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
8081
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
@@ -96,6 +97,6 @@
9697

9798
/* Completeness */
9899
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
99-
"skipLibCheck": true /* Skip type checking all .d.ts files. */
100-
},
100+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
101+
}
101102
}

0 commit comments

Comments
 (0)