Skip to content

Commit

Permalink
Merge pull request #136 from gnosis/reverse-ens-lookup
Browse files Browse the repository at this point in the history
feat: Add ENS lookup methods
  • Loading branch information
germartinez authored Jan 10, 2022
2 parents bff86c3 + 86d6638 commit 63ece7e
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cla.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ jobs:
path-to-signatures: 'signatures/version1/cla.json'
path-to-cla-document: 'https://gnosis-safe.io/cla/'
branch: 'cla-signatures'
allowlist: germartinez,mikheevm,rmeissner,Uxio0,dasanra,davidalbela,luarx,giacomolicari,lukasschor,tschubotz,gnosis-info,bot*,katspaugh
allowlist: germartinez,mikheevm,rmeissner,Uxio0,dasanra,davidalbela,luarx,giacomolicari,lukasschor,tschubotz,gnosis-info,bot*,katspaugh,usame-algan
empty-commit-flag: false
blockchain-storage-flag: false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@ deployments
typechain

openapi/
.idea
2 changes: 2 additions & 0 deletions packages/safe-core-sdk/src/ethereumLibs/EthAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ interface EthAdapter {
signMessage(message: string, signerAddress: string): Promise<string>
estimateGas(transaction: EthAdapterTransaction, options?: string): Promise<number>
call(transaction: EthAdapterTransaction): Promise<string>
ensLookup(name: string): Promise<string>
ensReverseLookup(address: string): Promise<string>
}

export default EthAdapter
34 changes: 34 additions & 0 deletions packages/safe-core-sdk/src/ethereumLibs/EthersAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from '../contracts/safeDeploymentContracts'
import { AbiItem } from '../types'
import EthAdapter, { EthAdapterTransaction, GetSafeContractProps } from './EthAdapter'
import ErrorCodes from './exceptions'

export interface EthersAdapterConfig {
/** ethers - Ethers v5 library */
Expand Down Expand Up @@ -151,6 +152,39 @@ class EthersAdapter implements EthAdapter {
call(transaction: EthAdapterTransaction): Promise<string> {
return this.#provider.call(transaction)
}

async ensLookup(name: string): Promise<string> {
let address: string | null

try {
address = await this.#provider.resolveName(name)
} catch (error) {
address = null
}

if (!address) {
throw new Error(ErrorCodes._100)
}

return address

}

async ensReverseLookup(address: string): Promise<string> {
let name: string | null

try {
name = await this.#provider.lookupAddress(address);
} catch (error) {
name = null
}

if (!name) {
throw new Error(ErrorCodes._101)
}

return name
}
}

export default EthersAdapter
26 changes: 24 additions & 2 deletions packages/safe-core-sdk/src/ethereumLibs/Web3Adapter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BigNumber } from '@ethersproject/bignumber'
import { namehash } from '@ethersproject/hash'
import { SafeVersion } from '../contracts/config'
import {
getGnosisSafeProxyFactoryContractInstance,
Expand All @@ -15,6 +16,7 @@ import {
} from '../contracts/safeDeploymentContracts'
import { AbiItem } from '../types'
import EthAdapter, { EthAdapterTransaction, GetSafeContractProps } from './EthAdapter'
import ErrorCodes from './exceptions'

export interface Web3AdapterConfig {
/** web3 - Web3 library */
Expand Down Expand Up @@ -105,7 +107,7 @@ class Web3Adapter implements EthAdapter {
return getGnosisSafeProxyFactoryContractInstance(safeVersion, proxyFactoryContract)
}

getContract(address: string, abi: AbiItem[]): any {
getContract(address: string, abi: any): any {
return new this.#web3.eth.Contract(abi, address)
}

Expand All @@ -125,13 +127,33 @@ class Web3Adapter implements EthAdapter {
return this.#web3.eth.sign(message, this.#signerAddress)
}

estimateGas(transaction: EthAdapterTransaction, options?: string): Promise<number> {
estimateGas(transaction: EthAdapterTransaction, options?: any): Promise<number> {
return this.#web3.eth.estimateGas(transaction, options)
}

call(transaction: EthAdapterTransaction): Promise<string> {
return this.#web3.eth.call(transaction)
}

async ensLookup(name: string): Promise<string> {
try {
return await this.#web3.eth.ens.getAddress(name)
} catch (error) {
throw new Error(ErrorCodes._100)
}
}

async ensReverseLookup(address: string): Promise<string> {
const lookup = address.slice(2) + '.addr.reverse'
const node = namehash(lookup)

try {
const ResolverContract = await this.#web3.eth.ens.getResolver(lookup);
return await ResolverContract.methods.name(node).call()
} catch (error) {
throw new Error(ErrorCodes._101)
}
}
}

export default Web3Adapter
6 changes: 6 additions & 0 deletions packages/safe-core-sdk/src/ethereumLibs/exceptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
enum ErrorCodes {
_100 = 'Error retrieving address for ENS Name',
_101 = 'Error retrieving ENS Name for address'
}

export default ErrorCodes
87 changes: 87 additions & 0 deletions packages/safe-core-sdk/tests/ens.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import Web3 from 'web3'
import { ethers } from 'hardhat'
import { Web3Adapter } from '../src'
import { EthersAdapter } from '../dist/src'
import { ZERO_ADDRESS } from '../src/utils/constants'
import chai from 'chai'
import { getDefaultProvider } from '@ethersproject/providers'
import { Wallet } from '@ethersproject/wallet'
import ErrorCodes from '../src/ethereumLibs/exceptions'

describe('Web3Adapter', () => {
const web3 = new Web3(new Web3.providers.HttpProvider('https://rinkeby-light.eth.linkpool.io/', {}))
const web3Adapter = new Web3Adapter({web3, signerAddress: ZERO_ADDRESS})

describe('ENS direct lookup', () => {
it('returns an address for ens name', async () => {
const address = await web3Adapter.ensLookup('loremipsum.eth')
chai.expect(address).match(/0x[0-9a-z]{40}/i)
})

it('throws an error for a non existing name', async () => {
try {
await web3Adapter.ensLookup('nonexistingname')
chai.expect(true).to.be.false
} catch(error) {
chai.expect((error as Error).message).to.equal(ErrorCodes._100)
}
})
})

describe('ENS reverse lookup', () => {
it('returns a name for existing address', async () => {
const name = await web3Adapter.ensReverseLookup('0xd8bbcb76bc9aea78972ed4773a5eb67b413f26a5')
chai.expect(name).to.equal("loremipsum.eth")
})

it('throws an error if no name exists for address', async () => {
try {
await web3Adapter.ensReverseLookup(ZERO_ADDRESS)
chai.expect(true).to.be.false
} catch(error) {
chai.expect((error as Error).message).to.equal(ErrorCodes._101)
}
})
})
})

describe('EthersAdapter', () => {
const provider = getDefaultProvider(`https://rinkeby.infura.io/v3/${process.env.INFURA_KEY}`)
const signer = new Wallet(
'0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d', // A Safe owner
provider
)
const ethersAdapter = new EthersAdapter({ ethers, signer })

describe('ENS direct lookup', () => {
it('returns an address for ens name', async () => {
const address = await ethersAdapter.ensLookup('safe.eth')
chai.expect(address).match(/0x[0-9a-z]{40}/i)
})

it('throws an error for a non existing name', async () => {
try {
await ethersAdapter.ensLookup('nonexistingname')
chai.expect(true).to.be.false
} catch (error) {
chai.expect((error as Error).message).to.equal(ErrorCodes._100)
}
})
})

describe('ENS reverse lookup', () => {
it('returns a name for existing address', async () => {
const name = await ethersAdapter.ensReverseLookup('0xd8bbcb76bc9aea78972ed4773a5eb67b413f26a5')
chai.expect(name).to.equal('loremipsum.eth')
})

it('returns null if no name exists for address', async () => {
try {
await ethersAdapter.ensReverseLookup(ZERO_ADDRESS)
chai.expect(true).to.be.false
} catch (error) {
chai.expect((error as Error).message).to.equal(ErrorCodes._101)
}
})
})
})

0 comments on commit 63ece7e

Please sign in to comment.