DID Resolver for the NFT method
npm install nft-did-resolver> NFT is a DID method that uses the Ceramic network to resolve DID documents for NFTs
> See CIP-94
This implementation is still a prototype. Contributions are welcome!
To use a package, you would need to provide three subgraph endpoints for every network you are going to use:
one for blocks, one for ERC721 tokens, another for ERC1155 tokens. You would also need to provide a skew that
is a time (in milliseconds) within which a latest block is considered valid. Usually it is a typical block time.
```
$ npm install nft-did-resolver
`typescript
import { getResolver } from 'nft-did-resolver'
import type { NftResolverConfig } from 'nft-did-resolver'
import { Resolver } from 'did-resolver'
import Ceramic from '@ceramicnetwork/http-client'
const ceramic = new Ceramic() // connects to localhost:7007 by default
const config: NftResolverConfig = {
ceramic,
chains: {
'eip155:1': {
blocks: 'https://api.thegraph.com/subgraphs/name/yyong1010/ethereumblocks',
skew: 15000,
assets: {
erc721: 'https://api.thegraph.com/subgraphs/name/sunguru98/mainnet-erc721-subgraph',
erc1155: 'https://api.thegraph.com/subgraphs/name/sunguru98/mainnet-erc1155-subgraph',
},
},
'eip155:4': {
blocks: 'https://api.thegraph.com/subgraphs/name/mul53/rinkeby-blocks',
skew: 15000,
assets: {
erc721: 'https://api.thegraph.com/subgraphs/name/sunguru98/erc721-rinkeby-subgraph',
erc1155: 'https://api.thegraph.com/subgraphs/name/sunguru98/erc1155-rinkeby-subgraph',
},
},
},
}
// getResolver will return an object with a key/value pair of { 'nft': resolver }
// where resolver is a function used by the generic did resolver.
const nftResolver = getResolver(config)
const didResolver = Resolver(nftResolver)
const erc721result = await didResolver.resolve(
'did:nft:eip155:1_erc721:0xb300a43751601bd54ffee7de35929537b28e1488_2'
)
const erc1155result = await didResolver.resolve(
'did:nft:eip155:1_erc1155:0x06eb48572a2ef9a3b230d69ca731330793b65bdc_1'
)
console.log(erc721result, erc1155result)
`
chains field in config has CAIP-2 chain identifiers as keys.chain
Each such is expected to contain endpoints to ERC721 and/or ERC1155 subgraphs under assets field.
Both ERC721 and ERC1155 are supported. Feel free to specify either one or both.
The resolver supports the following networks by default:
- Ethereum mainnet (eip155:1),eip155:4
- Ethereum Rinkeby (),eip155:137
- Polygon (formerly Matic) ().
If you use one of those, you do not have to provide chains field.
``
$ npm test
You may specify custom subgraph URLs in the configuration object as shown above in usage.
Note: custom subgraphs must conform to the below schemas at a _minimum_ for assets to be resolved properly.
Note: At the moment, only ERC721 and ERC1155 asset namespaces are supported. However, CAIP2 chains beside ETH,
for instance xDAI, with support for those namespaces _are_ supported, as long as the subgraph schema is the same.
`gql
type Token @entity {
id: ID!
contract: TokenContract!
owner: Owner!
...
}
type TokenContract @entity {
id: ID!
tokens: [Token!]! @derivedFrom(field: "contract")
...
}
type Owner @entity {
id: ID!
tokens: [Token!]! @derivedFrom(field: "owner")
...
}
`
`gql
type Account @entity {
id: ID!
balances: [Balance!]! @derivedFrom(field: "account")
...
}
type TokenRegistry @entity {
id: ID!
tokens: [Token!]! @derivedFrom(field: "registry")
...
}
type Token @entity {
id: ID!
registry: TokenRegistry!
identifier: BigInt!
balances: [Balance!]! @derivedFrom(field: "token")
...
}
type Balance @entity {
id: ID!
token: Token!
account: Account!
...
}
`
For more information on writing schemas for GraphProtocol, check out their documentation.
The token DIDs are prefixed with did:nft:, and the latter half is a modified CAIP format.
ERC721 (CAIP-22)
DID: did:nft:{chainNamespace}:{chainReference}_erc721:{contractAddress}_{tokenId}
CAIP-22: {chainNamespace}:{chainReference}/erc721:{contractAddress}/{tokenId}
ERC1155 (CAIP-29)
DID: did:nft:{chainNamespace}:{chainReference}_erc1155:{contractAddress}_{tokenId}
CAIP-29: {chainNamespace}:{chainReference}/erc1155:{contractAddress}/{tokenId}
DID->CAIP
``
const caip = did.substr(8).replace(/_/g, '/')
CAIP->DID
`did:nft:${caip.replace(/\//g, '_')
const did =
``
There are helpers that help you with the conversion:
`typescript
import { caipToDid, didToCaip, createNftDidUrl } from 'nft-did-resolver'
import { AssetId } from 'caip'
// CAIP -> DID URL
const didUrl = createNftDidUrl({
chainId: 'eip155:1',
namespace: 'erc721',
contract: '0x1234567891234567891234567891234596351156'
tokenId: '1',
})
// If you use caip library in your app, consider using sister caipToDid function to convert AssetId to NFT DID URL.
// DID URL -> CAIP
const assetId1 = didToCaip(didUrl) // eip155:1/erc721:0x1234567891234567891234567891234596351156/1
const assetId2 = didToCaip(didUrlWithTimestamp) // eip155:1/erc721:0x1234567891234567891234567891234596351156/1
``
We are happy to accept small and large contributions. Make sure to check out the Ceramic specifications for details of how the protocol works.
Apache-2.0 OR MIT