This repository has been archived by the owner on May 19, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
397 additions
and
210 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import Web3 from 'web3/types'; | ||
import { Contract } from 'web3-eth-contract/types'; | ||
import { hash as namehash } from 'eth-ens-namehash'; | ||
import { hasMethod } from './utils'; | ||
import { createAddrResolver, createChainAddrResolver } from './factories'; | ||
import { | ||
NO_ADDR_RESOLUTION, NO_ADDR_RESOLUTION_SET, NO_RESOLVER, | ||
NO_CHAIN_ADDR_RESOLUTION, NO_CHAIN_ADDR_RESOLUTION_SET | ||
} from './errors'; | ||
import { ZERO_ADDRESS, ADDR_INTERFACE, ERC165_INTERFACE, CHAIN_ADDR_INTERFACE } from './constants'; | ||
import { ChainId, Resolutions } from './types'; | ||
|
||
export default class implements Resolutions { | ||
constructor(private web3: Web3, private registry: Contract) { } | ||
|
||
private async _createResolver( | ||
node: string, | ||
methodInterface: string, | ||
errorMessage: string, | ||
contractFactory: (web3: Web3, address: string) => Contract | ||
): Promise<Contract> { | ||
const resolverAddress: string = await this.registry.methods.resolver(node).call(); | ||
|
||
if (resolverAddress === ZERO_ADDRESS) { | ||
throw new Error(NO_RESOLVER); | ||
} | ||
|
||
const isErc165Contract = await hasMethod(this.web3, resolverAddress, ERC165_INTERFACE); | ||
if (!isErc165Contract) { | ||
throw new Error(errorMessage); | ||
} | ||
|
||
const resolver: Contract = contractFactory(this.web3, resolverAddress); | ||
|
||
const supportsInterface: boolean = await resolver.methods.supportsInterface(methodInterface).call(); | ||
if (!supportsInterface) { | ||
throw new Error(errorMessage); | ||
} | ||
|
||
return resolver; | ||
} | ||
|
||
async addr(domain: string): Promise<string> { | ||
const node: string = namehash(domain); | ||
|
||
const resolver = await this._createResolver(node, ADDR_INTERFACE, NO_ADDR_RESOLUTION, createAddrResolver); | ||
|
||
const addr: string = await resolver.methods.addr(node).call(); | ||
|
||
if (addr === ZERO_ADDRESS){ | ||
throw new Error(NO_ADDR_RESOLUTION_SET); | ||
} | ||
|
||
return addr; | ||
} | ||
|
||
async chainAddr(domain: string, chainId: ChainId) { | ||
const node: string = namehash(domain); | ||
|
||
const resolver = await this._createResolver(node, CHAIN_ADDR_INTERFACE, NO_CHAIN_ADDR_RESOLUTION, createChainAddrResolver); | ||
|
||
const addr: string = await resolver.methods.chainAddr(node, chainId).call(); | ||
if (!addr || addr === ZERO_ADDRESS){ | ||
throw new Error(NO_CHAIN_ADDR_RESOLUTION_SET); | ||
} | ||
|
||
return addr; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Web3 from "web3"; | ||
|
||
export const hasMethod = async(web3: Web3, contractAddress: string, signatureHash: string) => { | ||
const code = await web3.eth.getCode(contractAddress); | ||
return code.indexOf(signatureHash.slice(2, signatureHash.length)) > 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import Web3 from 'web3'; | ||
import RNS from '../src/index'; | ||
import { NO_ADDR_RESOLUTION_SET, NO_RESOLVER, NO_ADDR_RESOLUTION } from '../src/errors'; | ||
import { asyncExpectThrowError } from './utils'; | ||
|
||
const PUBLIC_NODE_MAINNET = 'https://public-node.rsk.co'; | ||
const PUBLIC_NODE_TESTNET = 'https://public-node.testnet.rsk.co'; | ||
|
||
describe ('addr resolution', () => { | ||
describe ('should resolve a name', () => { | ||
test('mainnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_MAINNET); | ||
const rns = new RNS(web3); | ||
const addr = await rns.addr('testing.rsk'); | ||
expect(addr).toBe('0x0000000000000000000000000000000001000006'); | ||
}); | ||
|
||
test('testnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_TESTNET); | ||
const rns = new RNS(web3); | ||
const addr = await rns.addr('testing.rsk'); | ||
expect(addr).toBe('0x0000000000000000000000000000000001000006'); | ||
}); | ||
}); | ||
|
||
describe ('should throw an error when resolver has not been set', () => { | ||
test('mainnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_MAINNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noresolver.testing.rsk'), NO_RESOLVER); | ||
}); | ||
|
||
test('testnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_TESTNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noresolver.testing.rsk'), NO_RESOLVER); | ||
}); | ||
}); | ||
|
||
describe ('should throw an error when resolver does not support addr interface', () => { | ||
describe ('ERC165 contract as resolver that not implements addr method', () => { | ||
// the resolver address is the NameResolver contract. Is an ERC165 that not supports addr interface | ||
test('mainnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_MAINNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noaddrresolver.testing.rsk'), NO_ADDR_RESOLUTION); | ||
}); | ||
|
||
test('testnet with another ERC165 as resolver', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_TESTNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noaddrresolver.testing.rsk'), NO_ADDR_RESOLUTION); | ||
}); | ||
}); | ||
|
||
describe('non contract address as a resolver', () => { | ||
test('mainnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_MAINNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('accountasresolver.testing.rsk'), NO_ADDR_RESOLUTION); | ||
}); | ||
|
||
test('testnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_TESTNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('accountasresolver.testing.rsk'), NO_ADDR_RESOLUTION); | ||
}); | ||
}); | ||
}); | ||
|
||
describe ('should throw an error when no resolution set', () => { | ||
test('mainnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_MAINNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noresolution.testing.rsk'), NO_ADDR_RESOLUTION_SET); | ||
}); | ||
|
||
test('testnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_TESTNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noresolution.testing.rsk'), NO_ADDR_RESOLUTION_SET); | ||
}); | ||
}); | ||
|
||
describe ('should throw an error when domain do not exist', () => { | ||
test('mainnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_MAINNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noexist.testing.rsk'), NO_RESOLVER); | ||
}); | ||
|
||
test('testnet', async () => { | ||
const web3 = new Web3(PUBLIC_NODE_TESTNET); | ||
const rns = new RNS(web3); | ||
await asyncExpectThrowError(async () => await rns.addr('noexist.testing.rsk'), NO_RESOLVER); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.