-
Notifications
You must be signed in to change notification settings - Fork 0
/
resolver.ts
145 lines (118 loc) · 5.89 KB
/
resolver.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { init } from '@emurgo/cross-csl-nodejs';
import { WasmModuleProxy } from '@emurgo/cross-csl-core';
import {
validateCNSUserRecord,
validateExpiry,
validateVirtualSubdomainEnabled,
} from '../validators';
import { ParsedCNSUserRecord, SocialRecord } from '../type';
import { CNSFetcher } from '../fetcher/fetcher';
import { CNSConstants } from '../constants';
import { CSLParser, hexToString, parseAssocMap, parseAssocMapAsync } from '../utils';
export class CNSResolver {
fetcher: CNSFetcher;
constants: CNSConstants;
parser: CSLParser;
constructor(fetcher: CNSFetcher, parserProxy?: WasmModuleProxy) {
this.fetcher = fetcher;
if (parserProxy) {
this.parser = new CSLParser(parserProxy);
} else {
this.parser = new CSLParser(init('ctx'));
}
this.fetcher.parser = this.parser;
this.constants = new CNSConstants(fetcher.network);
}
resolveAddress = async (cnsName: string): Promise<string> => {
const deconstructedCns = cnsName.split('.');
if (deconstructedCns.length === 2) {
const address = await this.resolveDomain(cnsName);
return address;
}
if (deconstructedCns.length === 3) {
const address = await this.resolveVirtualSubdomain(cnsName);
return address;
}
return 'Invalid domain / virtual domain';
};
private resolveDomain = async (cnsName: string): Promise<string> => {
const assetName = Buffer.from(cnsName).toString('hex');
const assetHex = `${this.constants.cnsPolicyID}${assetName}`;
const metadata = await this.fetcher.getMetadata(this.constants.cnsPolicyID, assetName);
if (!metadata) return 'CNS not found';
if (!validateExpiry(metadata)) return 'CNS expired';
const address = await this.fetcher.getAssetAddress(assetHex);
if (!address) return 'CNS not found';
return address;
};
resolveUserRecord = async (cnsName: string): Promise<ParsedCNSUserRecord | string> => {
const assetName = Buffer.from(cnsName).toString('hex');
const metadata = await this.fetcher.getMetadata(this.constants.cnsPolicyID, assetName);
if (!metadata) return 'CNS not found';
if (!validateExpiry(metadata)) return 'CNS expired';
const recordAssetHex = `${this.constants.recordPolicyID}${assetName}`;
const inlineDatum = await this.fetcher.getAssetInlineDatum(
this.constants.recordAddress,
recordAssetHex,
);
if (!inlineDatum) return 'User record not found';
if (!validateCNSUserRecord(inlineDatum)) return 'Invalid user record';
const virtualSubdomains = await parseAssocMapAsync(inlineDatum.fields[0], async (item) => {
const itemHex = await this.parser.objToHex(item);
const bech32 = await this.parser.parsePlutusAddressToBech32(
itemHex,
this.fetcher.networkId || 0,
);
return bech32;
});
const parsedInlineDatum: ParsedCNSUserRecord = {
virtualSubdomains: validateVirtualSubdomainEnabled(metadata) ? virtualSubdomains : [],
socialProfiles: parseAssocMap(inlineDatum.fields[1], (item) => hexToString(item.bytes)),
otherRecords: parseAssocMap(inlineDatum.fields[2], (item) => hexToString(item.bytes)),
};
return parsedInlineDatum;
};
// Example:
// resolveUserRecord('bbb.ada').then((res) => console.log(res));
resolveVirtualSubdomains = async (cnsName: string): Promise<string[][] | string> => {
const parsedUserRecord = await this.resolveUserRecord(cnsName);
if (typeof parsedUserRecord === 'string') return parsedUserRecord;
return parsedUserRecord.virtualSubdomains;
};
// Example:
// resolveVirtualSubdomains('bbb.ada').then((res) => console.log(res));
private resolveVirtualSubdomain = async (virtualDomain: string): Promise<string> => {
const [target, cnsName, ext] = virtualDomain.split('.');
const virtualDomains = await this.resolveVirtualSubdomains(`${cnsName}.${ext}`);
if (typeof virtualDomains === 'string') return virtualDomains;
const resolvedVirtualDomain = virtualDomains?.find(([key]) => key === target);
if (!resolvedVirtualDomain) return 'Virtual domain not found';
return resolvedVirtualDomain[1];
};
resolveSocialRecords = async (cnsName: string): Promise<string[][] | string> => {
const parsedUserRecord = await this.resolveUserRecord(cnsName);
if (typeof parsedUserRecord === 'string') return parsedUserRecord;
return parsedUserRecord.socialProfiles;
};
// // Example
// resolveSocialRecords('bbb.ada').then((res) => console.log(res));
resolveSocialRecord = async (cnsName: string, socialName: SocialRecord): Promise<string> => {
const socialRecords = await this.resolveSocialRecords(cnsName);
if (typeof socialRecords === 'string') return socialRecords;
const resolvedSocialRecord = socialRecords?.find(([key]) => key === socialName);
if (!resolvedSocialRecord) return 'Social record not found';
return resolvedSocialRecord[1];
};
resolveOtherRecords = async (cnsName: string): Promise<string[][] | string> => {
const parsedUserRecord = await this.resolveUserRecord(cnsName);
if (typeof parsedUserRecord === 'string') return parsedUserRecord;
return parsedUserRecord.otherRecords;
};
resolveOtherRecord = async (cnsName: string, otherName: string): Promise<string> => {
const otherRecords = await this.resolveOtherRecords(cnsName);
if (typeof otherRecords === 'string') return otherRecords;
const resolvedOtherRecord = otherRecords?.find(([key]) => key === otherName);
if (!resolvedOtherRecord) return 'Other record not found';
return resolvedOtherRecord[1];
};
}