Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add ENS lookup methods #136

Merged
merged 11 commits into from
Jan 10, 2022
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
1 change: 1 addition & 0 deletions packages/safe-core-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
}
},
"dependencies": {
"@ensdomains/eth-ens-namehash": "^2.0.15",
"@gnosis.pm/safe-core-sdk-types": "^0.1.1",
"@gnosis.pm/safe-deployments": "^1.4.0",
"ethereumjs-util": "^7.1.3"
Expand Down
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 | null>
ensReverseLookup(address: string): Promise<string | null>
}

export default EthAdapter
8 changes: 8 additions & 0 deletions packages/safe-core-sdk/src/ethereumLibs/EthersAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ class EthersAdapter implements EthAdapter {
call(transaction: EthAdapterTransaction): Promise<string> {
return this.#provider.call(transaction)
}

ensLookup(name: string): Promise<string | null> {
return this.#provider.resolveName(name)
}

ensReverseLookup(address: string): Promise<string | null> {
return this.#provider.lookupAddress(address);
}
}

export default EthersAdapter
21 changes: 17 additions & 4 deletions packages/safe-core-sdk/src/ethereumLibs/Web3Adapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Web3 from 'web3'
const namehash = require('@ensdomains/eth-ens-namehash')
import { BigNumber } from '@ethersproject/bignumber'
import { SafeVersion } from '../contracts/config'
import {
Expand All @@ -18,13 +20,13 @@ import EthAdapter, { EthAdapterTransaction, GetSafeContractProps } from './EthAd

export interface Web3AdapterConfig {
/** web3 - Web3 library */
web3: any
web3: Web3
/** signerAddress - Address of the signer */
signerAddress: string
}

class Web3Adapter implements EthAdapter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some context:
EthAdapter is an interface implemented by Web3Adapter and EthersAdapter classes where all the methods are defined in the interface and implemented using Web3 and ethers.js libraries in the 2 classes respectively. This way it doesn't matter if a Dapp uses ethers.js or web3, they will still be able to access the same functionality.

It would be cool if the 2 new methods are included in EthAdapter and EthersAdapter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

#web3: any
#web3: Web3
#signerAddress: string

constructor({ web3, signerAddress }: Web3AdapterConfig) {
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,24 @@ 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)
}

ensLookup(name: string): Promise<string> {
return this.#web3.eth.ens.getAddress(name)
}

async ensReverseLookup(address: string): Promise<string> {
const lookup = address.slice(-40) + '.addr.reverse'
const node = namehash.hash(lookup)
const ResolverContract = await this.#web3.eth.ens.getResolver(lookup);
return await ResolverContract.methods.name(node).call()
}
}

export default Web3Adapter
77 changes: 77 additions & 0 deletions packages/safe-core-sdk/tests/ens.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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'

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('safe.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')
} catch(error) {
chai.expect((error as Error).message).to.equal('The resolver at 0x0000000000000000000000000000000000000000does not implement requested method: \"addr\".')
}
})
})

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

it('throws an error if no name exists for address', async () => {
try {
await web3Adapter.ensReverseLookup('0x16B110D5b7583266B29159d89eF0d001adf6f6FD')
} catch(error: any) {
chai.expect(error.message).to.exist
}
})
})
})

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 () => {
const address = await ethersAdapter.ensLookup('nonexistingname')
chai.expect(address).to.be.null
})
})

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

it('returns null if no name exists for address', async () => {
const name = await ethersAdapter.ensReverseLookup('0x16B110D5b7583266B29159d89eF0d001adf6f6FD')
chai.expect(name).to.be.null
})
})
})
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,11 @@
ethers "^5.0.13"
js-sha3 "^0.8.0"

"@ensdomains/eth-ens-namehash@^2.0.15":
version "2.0.15"
resolved "https://registry.yarnpkg.com/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz#5e5f2f24ba802aff8bc19edd822c9a11200cdf4a"
integrity sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw==

"@ensdomains/[email protected]", "@ensdomains/resolver@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89"
Expand Down