0xweb
Version:
Contract package manager and other web3 tools
111 lines (92 loc) • 4.1 kB
text/typescript
import alot from 'alot';
import { TAddress } from '@dequanto/models/TAddress';
import { $config } from '@dequanto/utils/$config';
import { $require } from '@dequanto/utils/$require';
import { INsProvider, INsProviderOptions } from './INsProvider';
import { TEth } from '@dequanto/models/TEth';
import { $base } from '@dequanto/utils/$base';
import { TPlatform } from '@dequanto/models/TPlatform';
import { Web3Client } from '@dequanto/clients/Web3Client';
import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory';
import { $address } from '@dequanto/utils/$address';
import { $is } from '@dequanto/utils/$is';
export abstract class ANsProvider implements INsProvider {
public configKey: string
constructor(public client) {
}
abstract supports(domain: string): boolean;
async getAddress(domain: string, opts: INsProviderOptions): Promise<{
platform: TPlatform
address: TAddress
}> {
let clients = await this.getClients(opts);
return alot(clients)
.mapAsync(async client => this.getAddressInner(client, domain))
.firstAsync(x => $address.isEmpty(x?.address) === false);
}
protected abstract getAddressInner (client: Web3Client, domain: string): Promise<{
platform: TPlatform
address: TAddress
}>;
/** Gets contentHash if root, or the record from path: foo.eth/FOO_RECORD */
async getContent(uri: string, opts: INsProviderOptions): Promise<{ platform: TPlatform, value: string }> {
let clients = await this.getClients(opts);
return alot(clients)
.mapAsync(async client => this.getContentInner(client, uri))
.firstAsync(x => x?.value != null);
}
protected abstract getContentInner (client: Web3Client, uri: string): Promise<{
platform: TPlatform
value: string
}>;
async getReverseName(address: TAddress, opts: INsProviderOptions): Promise<{ platform: TPlatform, name: string }> {
let clients = await this.getClients(opts);
return await alot(clients)
.mapAsync(async client => this.getReversedInner(client, address))
.firstAsync(x => $is.notEmpty(x?.name));
}
protected abstract getReversedInner (client: Web3Client, address: TAddress): Promise<{
platform: TPlatform
name: string
}>;
protected async getClients(opts: INsProviderOptions): Promise<Web3Client[]> {
if (opts?.multichain === false) {
return [ this.client ];
}
let clients = await alot(this.getSupportedChains())
.mapAsync(x => Web3ClientFactory.getAsync(x))
.toArrayAsync();
return alot([
this.client,
...clients
])
.distinctBy(x => x.network)
.toArray();
}
protected getSupportedChains(): TPlatform[] {
let settings = $config.get(`ns.${this.configKey}`);
let chains = $config.get(`web3`);
return Object.keys(settings).filter(x => x in chains) as TPlatform[];
}
protected decodeContentHash(hex: TEth.Hex) {
const ipfsMatch = /^0x(?<protocol>e3010170|e5010172)(?<hex>[0-9a-f]*)$/i.exec(hex);
if (ipfsMatch) {
let scheme = (ipfsMatch.groups.protocol === 'e3010170') ? 'ipfs' : 'ipns';
let hex = `0x${ipfsMatch.groups.hex}` as const;
let base58 = $base.$58.encode(hex);
return `${scheme}://${base58}`;
}
// Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
const swarm = /^0xe40101fa011b20(?<hex>[0-9a-f]*)$/i.exec(hex);
if (swarm?.groups?.hex.length === 64) {
return `bzz:/\/${swarm.groups.hex}`;
}
return hex;
}
protected getNsAddress(platform: TPlatform, type: 'registry' | 'resolver' = 'registry'): TAddress {
let key = `ns.${this.configKey}.${platform}.${type}`;
let registryAddr = $config.get(key);
$require.Address(registryAddr, `Not valid registry address in ${key}`);
return registryAddr;
}
}