Skip to content

Instantly share code, notes, and snippets.

@jefflau
Last active September 20, 2020 23:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jefflau/38d41fe732870892cb7abf950fb76b7a to your computer and use it in GitHub Desktop.
Save jefflau/38d41fe732870892cb7abf950fb76b7a to your computer and use it in GitHub Desktop.
ENS Javascript API design

API design for ENS

The ENS library is to be used in dapps and possibly other tools that need to connect to the set of ENS contracts on the Ethereum blockchain. It should give them all the tools they need to resolve and set records for their ENS names, as well as abstracting implementation details including, but not limited to:

  • namehashes (could be provided as an advanced option)
  • resolvers (unless it's absolutely required for custom resolvers)
  • using the graph for getting textRecord or non-eth address keys
  • decoders/encoders of addresses

Instantiation

Takes either a string, for connecting directly to infura, alternatively, can take a web3 provider object

import ENS from ‘ensLib’

const ens = new ENS({ 
  provider: web3.currentProvider, 
  registryAddress: registry  // optional, if it recognises the network, it will use a hardcoded list of registry addresses otherwise will error and ask user to provider a registry address
}) 

High level overview of API

  • ens.getName() - Gets the name object using a namehash or ens name
  • ens.getResolver() - Gets the resolver object at certain address, which can be then be asked what name you want from that resolver.
  • ens.setReverseRecord() - Sets the reverse record for the current account

Name object

const name = ens.name(‘jefflau.eth’)

Getters

const owner = await name.getOwner()
const resolver = await name.getResolver()
const address = await name.getAddr(‘eth’)
const contenthash = await name.getContenthash()
const parent = await name.getParent() //eth

TextRecords

const textRecord = await name.getTextRecord(‘url’)
// ‘http://awesome.com'
const textRecords = await name.getAllTextRecords() 

// [{ key: ‘url’, value: ‘http://awesome.com'}]

Coins

const coin = await name.getAddress(‘eth’)
// { key: ‘ETH’, coinId: 50, value: ‘0x000….’}

const coin = await name.getAddress(50)
// { key: ‘ETH’, coinId: 50, value: ‘0x000….’}

const coins = await name.getAllAddresses()
// [{ key: ‘ETH’, value: ‘0x000….’}, {key: "BTC", value: '14abc...']

Setters

const tx = await name.setResolver() // by default sets it to the public resolver with no arguments
const tx = await name.setResolver(customResolverAddr)
const tx = await name.setOwner(addr)
const tx = await name.setSubnodeOwner(label, addr)
const tx = await name.createSubdomain(label) //sets the owner to yourself

Record Setter

const tx = await name.setRecords({
  contentHash: 'ipfs://...',
  addresses: [{key: 'ETH', value: "0x123..." }],
  textRecords: [{ key: "url", value: "http://..."}]
})

//TODO possible get all records convenience function

Registrar object

const registrarDetails = name.getRegistrarDetails() //errors if isn't .eth
{
   expiryDate: DateObject,
   gracePeriodEnds: DateObject,
   registrant: "0x123..."
}

Resolver Object

const resolver = ens.getResolver('0x123')

const name = await resolver.name('vitalik.eth') // same as ens.getName, but only returns names that are using this resolver
const resolverAddress = resolver.address // 0x123... (not async)

name.getAddr('eth') // 0x123...
name.getContenthash() // ipfs://

Reverse record

ens.getReverseRecord()
ens.setReverseRecord('vitalik.eth')
@makoto
Copy link

makoto commented Sep 14, 2020

Would be nice if we have some sort of introspection function such as resolver.address returning resolver address.

@makoto
Copy link

makoto commented Sep 14, 2020

Do we not support setReverseRecord and creating subdomain? Also it would be nice if we can provide name.getParent() which returns parent name.

@makoto
Copy link

makoto commented Sep 14, 2020

name.getAddress(‘eth’) is it supposed to be case insensitive? If not, it should be name.getAddress(‘ETH’). Also name.getAddress() should default to return ETH address.

@jefflau
Copy link
Author

jefflau commented Sep 18, 2020

name.getAddress(‘eth’) is it supposed to be case insensitive? If not, it should be name.getAddress(‘ETH’). Also name.getAddress() should default to return ETH address.

I think case insensitivity is fine here, especially if we're going to do things like add defaults like getAddress()

@Arachnid
Copy link

I was thinking this was more of a merge. Thinking about delete, that might make sense, however we would still like to support multiple records deletes/updates. I'm not sure the best API to have create/update and then do delete. The only thing I can think of is a keyword like 'delete', but that seems kind of lame

What I'd suggest is this:

  • For single values, if the field is present it overrides the current value. Specifying null unsets/deletes it.
  • For lists such as addresses and textRecords, it replaces the values of the supplied elements but does not touch others. Setting the value to null deletes an entry.

So if nick.eth has a contentHash of a and text records url: example.com and avatar: foo, then after this operation:

const tx = await name.setRecords({
  contentHash: 'b',
  textRecords: [{ key: "url", value: null}, { key: "test", value: "bar"}]
})

The name will then have a contentHash of b, and text records avatar: foo and test: bar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment