@ensdomains/ensjs 3.0.0-alpha.25 → 3.0.0-alpha.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/contracts/getContractAddress.js +4 -4
- package/dist/cjs/functions/batchWrappers.js +41 -8
- package/dist/cjs/functions/deleteSubname.js +2 -5
- package/dist/cjs/functions/getName.js +2 -2
- package/dist/cjs/functions/getOwner.js +4 -4
- package/dist/cjs/functions/getProfile.js +117 -87
- package/dist/cjs/generated/factories/NameWrapper__factory.js +13 -0
- package/dist/cjs/generated/factories/UniversalResolver__factory.js +277 -0
- package/dist/cjs/utils/ccip.js +128 -0
- package/dist/cjs/utils/singleCall.js +1 -1
- package/dist/esm/contracts/getContractAddress.mjs +4 -4
- package/dist/esm/functions/batchWrappers.mjs +35 -8
- package/dist/esm/functions/deleteSubname.mjs +2 -5
- package/dist/esm/functions/getName.mjs +2 -2
- package/dist/esm/functions/getOwner.mjs +4 -4
- package/dist/esm/functions/getProfile.mjs +117 -87
- package/dist/esm/generated/factories/NameWrapper__factory.mjs +13 -0
- package/dist/esm/generated/factories/UniversalResolver__factory.mjs +277 -0
- package/dist/esm/utils/ccip.mjs +114 -0
- package/dist/esm/utils/singleCall.mjs +1 -1
- package/dist/types/functions/batchWrappers.d.ts +58 -1
- package/dist/types/functions/getProfile.d.ts +6 -0
- package/dist/types/generated/NameWrapper.d.ts +9 -1
- package/dist/types/generated/UniversalResolver.d.ts +123 -21
- package/dist/types/index.d.ts +64 -2
- package/dist/types/utils/ccip.d.ts +3 -0
- package/package.json +3 -3
- package/src/contracts/getContractAddress.ts +4 -4
- package/src/functions/batchWrappers.ts +40 -9
- package/src/functions/deleteSubname.test.ts +21 -1
- package/src/functions/deleteSubname.ts +2 -6
- package/src/functions/getName.ts +2 -2
- package/src/functions/getOwner.ts +4 -2
- package/src/functions/getProfile-ccip.test.ts +29 -0
- package/src/functions/getProfile.test.ts +1 -1
- package/src/functions/getProfile.ts +160 -100
- package/src/functions/setName.test.ts +6 -2
- package/src/functions/setRecord.test.ts +3 -3
- package/src/functions/setRecords.test.ts +2 -2
- package/src/generated/NameWrapper.ts +14 -0
- package/src/generated/UniversalResolver.ts +382 -19
- package/src/generated/factories/NameWrapper__factory.ts +13 -0
- package/src/generated/factories/UniversalResolver__factory.ts +277 -0
- package/src/index.ts +1 -1
- package/src/utils/ccip.ts +148 -0
- package/src/utils/singleCall.ts +1 -1
|
@@ -20,19 +20,19 @@ const addresses: Record<
|
|
|
20
20
|
'1': '0x283af0b28c62c092c9727f1ee09c02ca627eb7f5',
|
|
21
21
|
'3': '0xa5627AB7Ae47063B533622C34FEBDb52d3281dF8',
|
|
22
22
|
'4': '0x283af0b28c62c092c9727f1ee09c02ca627eb7f5',
|
|
23
|
-
'5': '
|
|
23
|
+
'5': '0x9C51161bA2FB02Cc0a403332B607117685f34831',
|
|
24
24
|
},
|
|
25
25
|
Multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
26
26
|
NameWrapper: {
|
|
27
27
|
'1': '0x0000000000000000000000000000000000000000',
|
|
28
28
|
'3': '0xF82155e2a43Be0871821E9654Fc8Ae894FB8307C',
|
|
29
29
|
'4': '0x0000000000000000000000000000000000000000',
|
|
30
|
-
'5': '
|
|
30
|
+
'5': '0x582224b8d4534F4749EFA4f22eF7241E0C56D4B8',
|
|
31
31
|
},
|
|
32
32
|
PublicResolver: {
|
|
33
33
|
'1': '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41',
|
|
34
34
|
'3': '0x13F0659Ee6bb7484C884FEeFb7F75C93951ef837',
|
|
35
|
-
'5': '
|
|
35
|
+
'5': '0xE264d5bb84bA3b8061ADC38D3D76e6674aB91852',
|
|
36
36
|
},
|
|
37
37
|
ENSRegistryWithFallback: {
|
|
38
38
|
'1': '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e',
|
|
@@ -49,7 +49,7 @@ const addresses: Record<
|
|
|
49
49
|
'1': '0x580AF46E06DaaD47eb5940526FD64d95b815Cb70',
|
|
50
50
|
'3': '0x74e20bd2a1fe0cdbe45b9a1d89cb7e0a45b36376',
|
|
51
51
|
'4': '0x74e20bd2a1fe0cdbe45b9a1d89cb7e0a45b36376',
|
|
52
|
-
'5': '
|
|
52
|
+
'5': '0x687c30Cc44bFA39A1449e86E172BF002E7b3f0b0',
|
|
53
53
|
},
|
|
54
54
|
BulkRenewal: {
|
|
55
55
|
'1': '0xfF252725f6122A92551A5FA9a6b6bf10eb0Be035',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ethers } from 'ethers'
|
|
2
2
|
import { ENSArgs } from '..'
|
|
3
|
+
import ccipLookup from '../utils/ccip'
|
|
3
4
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
4
5
|
|
|
5
6
|
export const universalWrapper = {
|
|
@@ -11,16 +12,16 @@ export const universalWrapper = {
|
|
|
11
12
|
const universalResolver = await contracts?.getUniversalResolver()!
|
|
12
13
|
return {
|
|
13
14
|
to: universalResolver.address,
|
|
14
|
-
data: universalResolver.interface.encodeFunctionData(
|
|
15
|
-
|
|
16
|
-
data,
|
|
17
|
-
|
|
15
|
+
data: universalResolver.interface.encodeFunctionData(
|
|
16
|
+
'resolve(bytes,bytes)',
|
|
17
|
+
[hexEncodeName(name), data],
|
|
18
|
+
),
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
decode: async ({ contracts }: ENSArgs<'contracts'>, data: string) => {
|
|
21
22
|
const universalResolver = await contracts?.getUniversalResolver()!
|
|
22
23
|
const response = universalResolver.interface.decodeFunctionResult(
|
|
23
|
-
'resolve',
|
|
24
|
+
'resolve(bytes,bytes)',
|
|
24
25
|
data,
|
|
25
26
|
)
|
|
26
27
|
if (!response || !response[0]) {
|
|
@@ -75,7 +76,11 @@ export const multicallWrapper = {
|
|
|
75
76
|
]),
|
|
76
77
|
}
|
|
77
78
|
},
|
|
78
|
-
async decode(
|
|
79
|
+
async decode(
|
|
80
|
+
{ contracts, provider }: ENSArgs<'contracts' | 'provider'>,
|
|
81
|
+
data: string,
|
|
82
|
+
transactions: ethers.providers.TransactionRequest[],
|
|
83
|
+
) {
|
|
79
84
|
if (!data) return
|
|
80
85
|
const multicall = await contracts?.getMulticall()!
|
|
81
86
|
try {
|
|
@@ -83,9 +88,35 @@ export const multicallWrapper = {
|
|
|
83
88
|
'tryAggregate',
|
|
84
89
|
data,
|
|
85
90
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
const ccipChecked = await Promise.all(
|
|
92
|
+
(result as [boolean, string][]).map(
|
|
93
|
+
async ([success, returnData], i) => {
|
|
94
|
+
let newArr: [boolean, string] = [success, returnData]
|
|
95
|
+
// OffchainLookup(address,string[],bytes,bytes4,bytes)
|
|
96
|
+
if (!success && returnData.startsWith('0x556f1830')) {
|
|
97
|
+
try {
|
|
98
|
+
const newData = await ccipLookup(
|
|
99
|
+
provider!,
|
|
100
|
+
transactions[i],
|
|
101
|
+
returnData,
|
|
102
|
+
)
|
|
103
|
+
if (newData) {
|
|
104
|
+
newArr = [true, newData]
|
|
105
|
+
}
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
...newArr,
|
|
110
|
+
success: newArr[0],
|
|
111
|
+
returnData: newArr[1],
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
return ccipChecked
|
|
117
|
+
} catch (e: any) {
|
|
118
|
+
console.error(e)
|
|
119
|
+
return
|
|
89
120
|
}
|
|
90
121
|
},
|
|
91
122
|
}
|
|
@@ -29,7 +29,10 @@ describe('deleteSubname', () => {
|
|
|
29
29
|
const result = await registry.owner(namehash('test.with-subnames.eth'))
|
|
30
30
|
expect(result).toBe('0x0000000000000000000000000000000000000000')
|
|
31
31
|
})
|
|
32
|
+
|
|
32
33
|
it('should allow deleting a subname on the nameWrapper', async () => {
|
|
34
|
+
const nameWrapper = await ensInstance.contracts!.getNameWrapper()!
|
|
35
|
+
|
|
33
36
|
const tx = await ensInstance.deleteSubname(
|
|
34
37
|
'test.wrapped-with-subnames.eth',
|
|
35
38
|
{
|
|
@@ -40,10 +43,27 @@ describe('deleteSubname', () => {
|
|
|
40
43
|
expect(tx).toBeTruthy()
|
|
41
44
|
await tx.wait()
|
|
42
45
|
|
|
43
|
-
const nameWrapper = await ensInstance.contracts!.getNameWrapper()!
|
|
44
46
|
const result = await nameWrapper.ownerOf(
|
|
45
47
|
namehash('test.wrapped-with-subnames.eth'),
|
|
46
48
|
)
|
|
47
49
|
expect(result).toBe('0x0000000000000000000000000000000000000000')
|
|
48
50
|
})
|
|
51
|
+
|
|
52
|
+
it('should not allow deleting 1LD', async () => {
|
|
53
|
+
await expect(
|
|
54
|
+
ensInstance.deleteSubname('eth', {
|
|
55
|
+
contract: 'nameWrapper',
|
|
56
|
+
addressOrIndex: 1,
|
|
57
|
+
}),
|
|
58
|
+
).rejects.toThrow()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should not allow deleting 2LD', async () => {
|
|
62
|
+
await expect(
|
|
63
|
+
ensInstance.deleteSubname('test123.eth', {
|
|
64
|
+
contract: 'registry',
|
|
65
|
+
addressOrIndex: 1,
|
|
66
|
+
}),
|
|
67
|
+
).rejects.toThrow()
|
|
68
|
+
})
|
|
49
69
|
})
|
|
@@ -13,12 +13,8 @@ export default async function (
|
|
|
13
13
|
) {
|
|
14
14
|
const labels = name.split('.')
|
|
15
15
|
|
|
16
|
-
if (labels.length
|
|
17
|
-
throw new Error(
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (labels[2] !== 'eth') {
|
|
21
|
-
throw new Error('ENS.js currently only supports deleting .eth 2LDs')
|
|
16
|
+
if (labels.length < 3) {
|
|
17
|
+
throw new Error(`${name} is not a valid subname`)
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
const label = labels.shift() as string
|
package/src/functions/getName.ts
CHANGED
|
@@ -6,7 +6,7 @@ const raw = async ({ contracts }: ENSArgs<'contracts'>, address: string) => {
|
|
|
6
6
|
const reverseNode = `${address.toLowerCase().substring(2)}.addr.reverse`
|
|
7
7
|
return {
|
|
8
8
|
to: universalResolver.address,
|
|
9
|
-
data: universalResolver.interface.encodeFunctionData('reverse', [
|
|
9
|
+
data: universalResolver.interface.encodeFunctionData('reverse(bytes)', [
|
|
10
10
|
hexEncodeName(reverseNode),
|
|
11
11
|
]),
|
|
12
12
|
}
|
|
@@ -21,7 +21,7 @@ const decode = async (
|
|
|
21
21
|
const universalResolver = await contracts?.getUniversalResolver()!
|
|
22
22
|
try {
|
|
23
23
|
const result = universalResolver.interface.decodeFunctionResult(
|
|
24
|
-
'reverse',
|
|
24
|
+
'reverse(bytes)',
|
|
25
25
|
data,
|
|
26
26
|
)
|
|
27
27
|
return {
|
|
@@ -100,7 +100,7 @@ const decode = async (
|
|
|
100
100
|
name: string,
|
|
101
101
|
contract?: 'nameWrapper' | 'registry' | 'registrar',
|
|
102
102
|
): Promise<Owner | undefined> => {
|
|
103
|
-
if (data
|
|
103
|
+
if (!data) return
|
|
104
104
|
const labels = name.split('.')
|
|
105
105
|
if (contract || labels.length === 1) {
|
|
106
106
|
const singleOwner = singleContractOwnerDecode(data)
|
|
@@ -119,7 +119,7 @@ const decode = async (
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
const result = await multicallWrapper.decode(data)
|
|
122
|
-
if (result
|
|
122
|
+
if (!result) return
|
|
123
123
|
const nameWrapper = await contracts?.getNameWrapper()!
|
|
124
124
|
|
|
125
125
|
const decodedData = [result[0][1], result[1][1], result[2]?.[1]].map(
|
|
@@ -163,6 +163,7 @@ const decode = async (
|
|
|
163
163
|
// this means that the subname is wrapped
|
|
164
164
|
if (
|
|
165
165
|
registryOwner === nameWrapper.address &&
|
|
166
|
+
nameWrapperOwner &&
|
|
166
167
|
ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x'
|
|
167
168
|
) {
|
|
168
169
|
return {
|
|
@@ -186,6 +187,7 @@ const decode = async (
|
|
|
186
187
|
// and for wrapped names, owner and registrant are the same thing
|
|
187
188
|
if (
|
|
188
189
|
registryOwner === nameWrapper.address &&
|
|
190
|
+
nameWrapperOwner &&
|
|
189
191
|
ethers.utils.hexStripZeros(nameWrapperOwner) !== '0x'
|
|
190
192
|
) {
|
|
191
193
|
return {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import dotenv from 'dotenv'
|
|
2
|
+
import { ENS } from '..'
|
|
3
|
+
import setup from '../tests/setup'
|
|
4
|
+
|
|
5
|
+
dotenv.config()
|
|
6
|
+
|
|
7
|
+
let ensInstance: ENS
|
|
8
|
+
|
|
9
|
+
beforeAll(async () => {
|
|
10
|
+
;({ ensInstance } = await setup(true))
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
jest.setTimeout(20000)
|
|
14
|
+
|
|
15
|
+
describe('getProfile', () => {
|
|
16
|
+
it('should return a profile from a ccip-read name', async () => {
|
|
17
|
+
const result = await ensInstance.getProfile('1.offchainexample.eth', {
|
|
18
|
+
fallback: {
|
|
19
|
+
texts: ['email', 'description'],
|
|
20
|
+
contentHash: true,
|
|
21
|
+
coinTypes: ['0', '60'],
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
expect(result).toBeTruthy()
|
|
25
|
+
if (result) {
|
|
26
|
+
expect(result.address).toBe('0x41563129cDbbD0c5D3e1c86cf9563926b243834d')
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { formatsByName } from '@ensdomains/address-encoder'
|
|
2
2
|
import { ethers } from 'ethers'
|
|
3
|
+
import { hexStripZeros } from 'ethers/lib/utils'
|
|
3
4
|
import { ENSArgs } from '..'
|
|
4
5
|
import { decodeContenthash, DecodedContentHash } from '../utils/contentHash'
|
|
5
6
|
import { hexEncodeName } from '../utils/hexEncodedName'
|
|
@@ -18,6 +19,12 @@ type ProfileResponse = {
|
|
|
18
19
|
coinTypes?: string[]
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
type FallbackRecords = {
|
|
23
|
+
contentHash?: boolean
|
|
24
|
+
texts?: string[]
|
|
25
|
+
coinTypes?: string[]
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
type DataItem = {
|
|
22
29
|
key: string | number
|
|
23
30
|
type: 'addr' | 'text' | 'contentHash'
|
|
@@ -41,19 +48,25 @@ type ResolvedProfile = {
|
|
|
41
48
|
reverseResolverAddress?: string
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
type CallObj = {
|
|
52
|
+
key: string
|
|
53
|
+
data: {
|
|
54
|
+
to: string
|
|
55
|
+
data: string
|
|
56
|
+
}
|
|
57
|
+
type: 'addr' | 'text' | 'contentHash'
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
const makeMulticallData = async (
|
|
45
61
|
{
|
|
46
62
|
_getAddr,
|
|
47
63
|
_getContentHash,
|
|
48
64
|
_getText,
|
|
49
|
-
|
|
50
|
-
}: ENSArgs<
|
|
51
|
-
'_getText' | '_getAddr' | '_getContentHash' | 'resolverMulticallWrapper'
|
|
52
|
-
>,
|
|
65
|
+
}: ENSArgs<'_getText' | '_getAddr' | '_getContentHash'>,
|
|
53
66
|
name: string,
|
|
54
67
|
options: InternalProfileOptions,
|
|
55
68
|
) => {
|
|
56
|
-
let calls:
|
|
69
|
+
let calls: (CallObj | null)[] = []
|
|
57
70
|
if (options.texts)
|
|
58
71
|
calls = [
|
|
59
72
|
...calls,
|
|
@@ -61,7 +74,7 @@ const makeMulticallData = async (
|
|
|
61
74
|
options.texts.map(async (x) => ({
|
|
62
75
|
key: x,
|
|
63
76
|
data: await _getText.raw(name, x),
|
|
64
|
-
type: 'text',
|
|
77
|
+
type: 'text' as const,
|
|
65
78
|
})),
|
|
66
79
|
)),
|
|
67
80
|
]
|
|
@@ -73,7 +86,7 @@ const makeMulticallData = async (
|
|
|
73
86
|
options.coinTypes.map(async (x) => ({
|
|
74
87
|
key: x,
|
|
75
88
|
data: await _getAddr.raw(name, x, true),
|
|
76
|
-
type: 'addr',
|
|
89
|
+
type: 'addr' as const,
|
|
77
90
|
})),
|
|
78
91
|
)),
|
|
79
92
|
]
|
|
@@ -82,21 +95,19 @@ const makeMulticallData = async (
|
|
|
82
95
|
calls.push({
|
|
83
96
|
key: 'contentHash',
|
|
84
97
|
data: await _getContentHash.raw(name),
|
|
85
|
-
type: '
|
|
98
|
+
type: 'contentHash' as const,
|
|
86
99
|
})
|
|
87
100
|
}
|
|
88
101
|
|
|
89
|
-
if (!calls.find((x) => x
|
|
102
|
+
if (!calls.find((x) => x!.key === '60')) {
|
|
90
103
|
calls.push({
|
|
91
104
|
key: '60',
|
|
92
105
|
data: await _getAddr.raw(name, '60', true),
|
|
93
|
-
type: 'addr',
|
|
106
|
+
type: 'addr' as const,
|
|
94
107
|
})
|
|
95
108
|
}
|
|
96
109
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return { data: prRawData.data, calls }
|
|
110
|
+
return { data: calls.map((x) => x!.data.data), calls }
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
const fetchWithoutResolverMulticall = async (
|
|
@@ -116,9 +127,11 @@ const fetchWithoutResolverMulticall = async (
|
|
|
116
127
|
data: call.data.data,
|
|
117
128
|
}))
|
|
118
129
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
130
|
+
const results = await multicallWrapper(callsWithResolver)
|
|
131
|
+
|
|
132
|
+
if (!results || !results.length) return []
|
|
133
|
+
|
|
134
|
+
return results.map((x: [boolean, string]) => x[1])
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
const formatRecords = async (
|
|
@@ -139,7 +152,7 @@ const formatRecords = async (
|
|
|
139
152
|
key: calls[i].key,
|
|
140
153
|
type: calls[i].type,
|
|
141
154
|
}
|
|
142
|
-
if (itemRet.type === '
|
|
155
|
+
if (itemRet.type === 'contentHash') {
|
|
143
156
|
;[decodedFromAbi] = ethers.utils.defaultAbiCoder.decode(
|
|
144
157
|
['bytes'],
|
|
145
158
|
item,
|
|
@@ -171,7 +184,7 @@ const formatRecords = async (
|
|
|
171
184
|
} catch {
|
|
172
185
|
return
|
|
173
186
|
}
|
|
174
|
-
case '
|
|
187
|
+
case 'contentHash':
|
|
175
188
|
try {
|
|
176
189
|
itemRet = {
|
|
177
190
|
...itemRet,
|
|
@@ -217,7 +230,7 @@ const formatRecords = async (
|
|
|
217
230
|
}
|
|
218
231
|
} else if (options.contentHash) {
|
|
219
232
|
const foundRecord = returnedRecords.find(
|
|
220
|
-
(item: any) => item.type === '
|
|
233
|
+
(item: any) => item.type === 'contentHash',
|
|
221
234
|
)
|
|
222
235
|
returnedResponse.contentHash = foundRecord ? foundRecord.value : null
|
|
223
236
|
}
|
|
@@ -240,7 +253,6 @@ const getDataForName = async (
|
|
|
240
253
|
_getAddr,
|
|
241
254
|
_getContentHash,
|
|
242
255
|
_getText,
|
|
243
|
-
resolverMulticallWrapper,
|
|
244
256
|
multicallWrapper,
|
|
245
257
|
}: ENSArgs<
|
|
246
258
|
| 'contracts'
|
|
@@ -252,62 +264,77 @@ const getDataForName = async (
|
|
|
252
264
|
>,
|
|
253
265
|
name: string,
|
|
254
266
|
options: InternalProfileOptions,
|
|
255
|
-
fallbackResolver?: string,
|
|
256
267
|
specificResolver?: string,
|
|
257
268
|
) => {
|
|
258
|
-
const universalResolver = await contracts?.getUniversalResolver()
|
|
269
|
+
const universalResolver = await contracts?.getUniversalResolver()!
|
|
259
270
|
|
|
260
271
|
const { data, calls } = await makeMulticallData(
|
|
261
|
-
{ _getAddr, _getContentHash, _getText
|
|
272
|
+
{ _getAddr, _getContentHash, _getText },
|
|
262
273
|
name,
|
|
263
274
|
options,
|
|
264
275
|
)
|
|
265
276
|
|
|
266
|
-
let
|
|
267
|
-
let
|
|
268
|
-
|
|
269
|
-
|
|
277
|
+
let recordData: (string | null)[] | undefined
|
|
278
|
+
let resolverAddress: string | undefined = specificResolver
|
|
279
|
+
|
|
280
|
+
if (specificResolver) {
|
|
281
|
+
try {
|
|
270
282
|
const publicResolver = await contracts?.getPublicResolver(
|
|
271
283
|
undefined,
|
|
272
284
|
specificResolver,
|
|
273
285
|
)
|
|
274
|
-
|
|
275
|
-
|
|
286
|
+
recordData = await publicResolver?.callStatic.multicall(data)
|
|
287
|
+
} catch (e: any) {
|
|
288
|
+
console.error('getProfile error:', e)
|
|
289
|
+
recordData = await fetchWithoutResolverMulticall(
|
|
290
|
+
{ multicallWrapper },
|
|
291
|
+
calls as CallObj[],
|
|
292
|
+
resolverAddress!,
|
|
276
293
|
)
|
|
277
|
-
} else {
|
|
278
|
-
resolvedData = await universalResolver?.resolve(hexEncodeName(name), data)
|
|
279
294
|
}
|
|
280
|
-
} catch {
|
|
281
|
-
useFallbackResolver = true
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
let resolverAddress: string
|
|
285
|
-
let recordData: any
|
|
286
|
-
|
|
287
|
-
if (useFallbackResolver) {
|
|
288
|
-
resolverAddress = specificResolver || fallbackResolver!
|
|
289
|
-
recordData = await fetchWithoutResolverMulticall(
|
|
290
|
-
{ multicallWrapper },
|
|
291
|
-
calls,
|
|
292
|
-
resolverAddress,
|
|
293
|
-
)
|
|
294
295
|
} else {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
296
|
+
const resolvedData = await universalResolver['resolve(bytes,bytes[])'](
|
|
297
|
+
hexEncodeName(name),
|
|
298
|
+
data,
|
|
299
|
+
{
|
|
300
|
+
ccipReadEnabled: true,
|
|
301
|
+
},
|
|
302
|
+
)
|
|
303
|
+
recordData = [...resolvedData['0']]
|
|
304
|
+
resolverAddress = resolvedData['1']
|
|
305
|
+
for (let i = 0; i < recordData.length; i += 1) {
|
|
306
|
+
// error code for reverted call in batch
|
|
307
|
+
// this is expected when using offchain resolvers, so should be ignored
|
|
308
|
+
if (recordData[i]!.startsWith('0x0d1947a9')) {
|
|
309
|
+
calls[i] = null
|
|
310
|
+
recordData[i] = null
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (
|
|
315
|
+
!resolverAddress ||
|
|
316
|
+
!recordData ||
|
|
317
|
+
hexStripZeros(resolverAddress) === '0x'
|
|
318
|
+
) {
|
|
319
|
+
return {
|
|
320
|
+
address: null,
|
|
321
|
+
records: {},
|
|
322
|
+
resolverAddress: null,
|
|
300
323
|
}
|
|
301
324
|
}
|
|
302
325
|
|
|
303
|
-
const
|
|
326
|
+
const filteredCalls = calls.filter((x) => x) as CallObj[]
|
|
327
|
+
const filteredRecordData = recordData.filter((x) => x)
|
|
328
|
+
|
|
329
|
+
const matchAddress =
|
|
330
|
+
filteredRecordData[filteredCalls.findIndex((x) => x.key === '60')]
|
|
304
331
|
|
|
305
332
|
return {
|
|
306
333
|
address: matchAddress && (await _getAddr.decode(matchAddress)),
|
|
307
334
|
records: await formatRecords(
|
|
308
335
|
{ _getAddr, _getContentHash, _getText },
|
|
309
|
-
|
|
310
|
-
|
|
336
|
+
filteredRecordData,
|
|
337
|
+
filteredCalls,
|
|
311
338
|
options,
|
|
312
339
|
),
|
|
313
340
|
resolverAddress,
|
|
@@ -332,7 +359,6 @@ const graphFetch = async (
|
|
|
332
359
|
addr {
|
|
333
360
|
id
|
|
334
361
|
}
|
|
335
|
-
address
|
|
336
362
|
}
|
|
337
363
|
}
|
|
338
364
|
}
|
|
@@ -379,14 +405,7 @@ const graphFetch = async (
|
|
|
379
405
|
|
|
380
406
|
const returnedRecords: ProfileResponse = {}
|
|
381
407
|
|
|
382
|
-
if (!resolverResponse) return { isMigrated, createdAt }
|
|
383
|
-
|
|
384
|
-
if (!wantedRecords)
|
|
385
|
-
return {
|
|
386
|
-
isMigrated,
|
|
387
|
-
createdAt,
|
|
388
|
-
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
389
|
-
}
|
|
408
|
+
if (!resolverResponse || !wantedRecords) return { isMigrated, createdAt }
|
|
390
409
|
|
|
391
410
|
Object.keys(wantedRecords).forEach((key: string) => {
|
|
392
411
|
const data = wantedRecords[key as keyof ProfileOptions]
|
|
@@ -403,7 +422,6 @@ const graphFetch = async (
|
|
|
403
422
|
...returnedRecords,
|
|
404
423
|
isMigrated,
|
|
405
424
|
createdAt,
|
|
406
|
-
graphResolverAddress: resolverResponse.address || resolverAddress,
|
|
407
425
|
}
|
|
408
426
|
}
|
|
409
427
|
|
|
@@ -415,6 +433,7 @@ type ProfileOptions = {
|
|
|
415
433
|
|
|
416
434
|
type InputProfileOptions = ProfileOptions & {
|
|
417
435
|
resolverAddress?: string
|
|
436
|
+
fallback?: FallbackRecords
|
|
418
437
|
}
|
|
419
438
|
|
|
420
439
|
const getProfileFromName = async (
|
|
@@ -438,7 +457,7 @@ const getProfileFromName = async (
|
|
|
438
457
|
name: string,
|
|
439
458
|
options?: InputProfileOptions,
|
|
440
459
|
) => {
|
|
441
|
-
const { resolverAddress, ..._options } = options || {}
|
|
460
|
+
const { resolverAddress, fallback, ..._options } = options || {}
|
|
442
461
|
const optsLength = Object.keys(_options).length
|
|
443
462
|
let usingOptions: InputProfileOptions | undefined
|
|
444
463
|
if (!optsLength || _options?.texts === true || _options?.coinTypes === true) {
|
|
@@ -452,35 +471,69 @@ const getProfileFromName = async (
|
|
|
452
471
|
usingOptions,
|
|
453
472
|
resolverAddress,
|
|
454
473
|
)
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
474
|
+
let isMigrated: boolean | null = null
|
|
475
|
+
let createdAt: string | null = null
|
|
476
|
+
let result: Awaited<ReturnType<typeof getDataForName>> | null = null
|
|
477
|
+
if (!graphResult) {
|
|
478
|
+
if (!fallback) return
|
|
479
|
+
result = await getDataForName(
|
|
480
|
+
{
|
|
481
|
+
contracts,
|
|
482
|
+
_getAddr,
|
|
483
|
+
_getContentHash,
|
|
484
|
+
_getText,
|
|
485
|
+
resolverMulticallWrapper,
|
|
486
|
+
multicallWrapper,
|
|
487
|
+
},
|
|
488
|
+
name,
|
|
489
|
+
fallback,
|
|
490
|
+
undefined,
|
|
491
|
+
)
|
|
492
|
+
} else {
|
|
493
|
+
const {
|
|
494
|
+
isMigrated: _isMigrated,
|
|
495
|
+
createdAt: _createdAt,
|
|
496
|
+
...wantedRecords
|
|
497
|
+
}: {
|
|
498
|
+
isMigrated: boolean
|
|
499
|
+
createdAt: string
|
|
500
|
+
} & InternalProfileOptions = graphResult
|
|
501
|
+
isMigrated = _isMigrated
|
|
502
|
+
createdAt = _createdAt
|
|
503
|
+
let recordsWithFallback = usingOptions
|
|
504
|
+
? wantedRecords
|
|
505
|
+
: (_options as InternalProfileOptions)
|
|
506
|
+
if (
|
|
507
|
+
(Object.keys(recordsWithFallback).length === 0 ||
|
|
508
|
+
(!recordsWithFallback.coinTypes &&
|
|
509
|
+
!recordsWithFallback.texts &&
|
|
510
|
+
Object.keys(recordsWithFallback.contentHash || {}).length === 0)) &&
|
|
511
|
+
fallback
|
|
512
|
+
) {
|
|
513
|
+
recordsWithFallback = fallback
|
|
514
|
+
}
|
|
515
|
+
result = await getDataForName(
|
|
516
|
+
{
|
|
517
|
+
contracts,
|
|
518
|
+
_getAddr,
|
|
519
|
+
_getContentHash,
|
|
520
|
+
_getText,
|
|
521
|
+
resolverMulticallWrapper,
|
|
522
|
+
multicallWrapper,
|
|
523
|
+
},
|
|
524
|
+
name,
|
|
525
|
+
recordsWithFallback,
|
|
526
|
+
options?.resolverAddress!,
|
|
527
|
+
)
|
|
528
|
+
}
|
|
529
|
+
if (!result?.resolverAddress)
|
|
530
|
+
return {
|
|
531
|
+
isMigrated,
|
|
532
|
+
createdAt,
|
|
533
|
+
message: !result
|
|
534
|
+
? "Records fetch didn't complete"
|
|
535
|
+
: "Name doesn't have a resolver",
|
|
536
|
+
}
|
|
484
537
|
return { ...result, isMigrated, createdAt, message: undefined }
|
|
485
538
|
}
|
|
486
539
|
|
|
@@ -537,6 +590,13 @@ const getProfileFromAddress = async (
|
|
|
537
590
|
}
|
|
538
591
|
}
|
|
539
592
|
|
|
593
|
+
const mapCoinTypes = (coin: string) => {
|
|
594
|
+
if (!Number.isNaN(parseInt(coin))) {
|
|
595
|
+
return coin
|
|
596
|
+
}
|
|
597
|
+
return `${formatsByName[coin.toUpperCase()].coinType}`
|
|
598
|
+
}
|
|
599
|
+
|
|
540
600
|
export default async function (
|
|
541
601
|
{
|
|
542
602
|
contracts,
|
|
@@ -560,13 +620,13 @@ export default async function (
|
|
|
560
620
|
nameOrAddress: string,
|
|
561
621
|
options?: InputProfileOptions,
|
|
562
622
|
): Promise<ResolvedProfile | undefined> {
|
|
563
|
-
if (options
|
|
564
|
-
options.coinTypes
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}
|
|
623
|
+
if (options) {
|
|
624
|
+
if (options.coinTypes && typeof options.coinTypes !== 'boolean') {
|
|
625
|
+
options.coinTypes = options.coinTypes.map(mapCoinTypes)
|
|
626
|
+
}
|
|
627
|
+
if (options.fallback && options.fallback.coinTypes) {
|
|
628
|
+
options.fallback.coinTypes = options.fallback.coinTypes.map(mapCoinTypes)
|
|
629
|
+
}
|
|
570
630
|
}
|
|
571
631
|
|
|
572
632
|
const inputType = parseInputType(nameOrAddress)
|