{"id":13744206,"url":"https://github.com/decentralized-identity/element","last_synced_at":"2026-03-20T01:19:59.200Z","repository":{"id":55847200,"uuid":"177348137","full_name":"decentralized-identity/element","owner":"decentralized-identity","description":"DID Method implementation using the Sidetree protocol on top of Ethereum and IPFS","archived":true,"fork":false,"pushed_at":"2020-12-11T09:27:40.000Z","size":18526,"stargazers_count":102,"open_issues_count":30,"forks_count":28,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-27T04:37:22.983Z","etag":null,"topics":["crypto","dapp","did","ethereum","ipfs","protocol","sidetree","wg-sidetree"],"latest_commit_sha":null,"homepage":"https://element-did.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/decentralized-identity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-23T22:51:56.000Z","updated_at":"2024-05-30T09:49:16.000Z","dependencies_parsed_at":"2022-08-15T07:50:44.663Z","dependency_job_id":null,"html_url":"https://github.com/decentralized-identity/element","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decentralized-identity%2Felement","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decentralized-identity%2Felement/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decentralized-identity%2Felement/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decentralized-identity%2Felement/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/decentralized-identity","download_url":"https://codeload.github.com/decentralized-identity/element/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253177883,"owners_count":21866414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crypto","dapp","did","ethereum","ipfs","protocol","sidetree","wg-sidetree"],"created_at":"2024-08-03T05:01:05.122Z","updated_at":"2026-03-20T01:19:59.171Z","avatar_url":"https://github.com/decentralized-identity.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\n## See [sidetree.js](https://github.com/transmute-industries/sidetree.js)\n\nThis repo is no longer maintained.\n\n### Element\n\n[![Build Status](https://travis-ci.org/decentralized-identity/element.svg?branch=master)](https://travis-ci.org/decentralized-identity/element) [![codecov](https://codecov.io/gh/decentralized-identity/element/branch/master/graph/badge.svg)](https://codecov.io/gh/decentralized-identity/element)\n\n#### 🔥 Experimental Sidetree Protocol based DID Method `elem` with Ethereum and IPFS\n\n### [See the DID method specification](./docs/did-method-spec/spec.md)\n\n### [See our blog post](https://medium.com/transmute-techtalk/introducing-element-328b4260e757)\n\n[OUTDATED] Click below image for demo video.\n\n[![Element Testnet Demo](./BrowserDemo.png)](https://www.youtube.com/watch?v=KY_dt2tKQxw)\n\nSee also [ion](https://github.com/decentralized-identity/ion), [sidetree](https://github.com/decentralized-identity/sidetree), [sidetree-ethereum](https://github.com/decentralized-identity/sidetree-ethereum).\n\n## Useful resources\n\n- [Element documentation](https://docs.element-did.com)\n- [Web App](https://element-did.com)\n- [API Docs](https://element-did.com/api/docs)\n- [React Storybook](https://storybook.element-did.com)\n- [Current Anchor Contract](https://ropsten.etherscan.io/address/0xD49Da2b7C0A15f6ac5A856f026D68A9B9848D96f)\n\n## Getting Started\n\n```\ngit clone git@github.com:decentralized-identity/element.git\ncd element\nnpm install\n```\n\nElement follows the [Mono Repo structure](https://github.com/lerna/lerna). Running `npm install` will install dependencies in the top level npm project as well as in the following packages:\n\n- [Element LIB](./packages/element-lib): Javascript SDK for using Element. Works with node 10, node 12 and in the browser\n- [Element APP](./packages/element-app): Progressive Web App to create a wallet, create a DID, add and remove keys, search through the Element Block explorer, etc... The PWA allows you to use two different types of Sidetree nodes:\n  - The light node (or browser node) which uses element-lib in the browser for Sidetree operations and interacts with Ethereum through [Metamask](https://metamask.io/) Make sure you have the Metamask browser extension installed if you want to use it the light node.\n  - The full node which uses element-api for Sidetree operations\n- [Element API](./packages/element-api): API powered by element-lib that exposes Sidetree operations with an HTTP interface. See [Swagger documentation](https://element-did.com/api/docs/) for more details.\n\n## How to use element-lib\n\n```\ncd packages/element-lib\n```\n\n### Running the tests\n\nIn order to run the tests, you need to start Element services\n\n```\nnpm run services:start\n```\n\nThis will start 3 services:\n\n- [Ganache](https://www.trufflesuite.com/ganache): A local Ethereum chain initialized with the [Element smart contract](https://ropsten.etherscan.io/address/0xD49Da2b7C0A15f6ac5A856f026D68A9B9848D96f) running with on port 8545\n- [IPFS](https://ipfs.io/): A local IPFS node running on port 5001\n- [CouchDB](https://couchdb.apache.org/): A local CouchDB instance running on port 5984. CouchDB will be ran in the Docker container, so you will need Docker installed. If you don't have it and / or don't want to install it, it is fine. Just be aware that the CouchDB tests will fail\n\nCheck that services are properly initalized with\n\n```\nnpm run services:healthcheck\n```\n\nThen you can run the tests (note that running this command will initialize the services if they have not been initialized)\n\n```\nnpm test\n```\n\nWhen you are done, you can stop the Element services by running\n\n```\nnpm run services:stop\n```\n\n### Initializing the Sidetree class\n\nIn order to use element-lib in node or in the browser, you will need to initalize the Sidetree class by providing three interfaces:\n\n- A `db` interface: this is where all the caching artifacts will be stored. While caching is not technically required for Element to work, CRUD operations will be prohibitively slow without it. To initialize, chose one db adapter (several options are available [here](./packages/element-lib/src/adapters/database)):\n\n  - [RXDB](https://github.com/pubkey/rxdb)\n  - [CouchDB](https://couchdb.apache.org/)\n  - [Firestore](https://firebase.google.com/docs/firestore/): A good option if you're going to use Element in a [Firebase Cloud Function](https://cloud.google.com/functions/), pretty slow otherwise. Also note that this technology is proprietary as opposed to the two above which are open source..\n\n- A `storage` interface: the Content Addressed Storage layer where Sidetree operation data will be stored. To initialize, chose one storage adapter (several options are available [here](./packages/element-lib/src/adapters/storage)):\n\n  - IPFS\n  - IPFS Storage Manager: A layer on top of IPFS that uses a cache and some retry logic when the call to IPFS fails: This one is recommended for production use as the IPFS link provided by Infura tend to fail intermittently\n\n- A `blockchain` interface: An interface for the decentralized ledger to be used for anchoring Sidetree operations. Element may only be used with the [Ethereum interface](./packages/element-lib/src/adapters/blockchain), however feel free to reuse this codebase to implement a did method that uses a different ledger.\n\n- A `parameter` object. Currently the supported parameters are:\n  - maxOperationsPerBatch: recommended value is 10000,\n  - batchingIntervalInSeconds: recommended value is 10,\n  - didMethodName: recommended value is `did:elem:ropsten` for Element testnet\n  - logLevel: one of [ error, warn, info, http, verbose, debug, silly ]. `error` would log all the logs, while `silly` would only capture the most unimportant ones\n\nSee several examples for how to initialize the Sidetree class:\n\n- [For a local node used for testing purposes](./packages/element-lib/src/__tests__/test-utils.js) : uses RXDB for in memory cache, local IPFS node for the storage interface, and local Ethereum node for the blockchain interface\n- [For a production node running in nodeJS](./packages/element-api/src/services/sidetree.js): uses Firestore for the cache, IPFS Storage Manager for the storage interface, and Infura Ropsten for the blockchain interface\n- [For a production node running in the browser](./packages/element-app/src/services/sidetree.js): uses RXDB for in browser cache, IPFS Storage Manager for the storage interface and Metamask for the blockchain interface\n\n### Using element-lib to Create Read Update Delete DIDs\n\nOnce you have an instance of the Sidetree class with the suitable adapters, you can access all the helper functions (`sidetree.func`) and perform CRUD operations (`sidetree.op`). Here are a few code snippet to get you started:\n\n#### Create a DID\n\n```js\nconst { Sidetree, MnemonicKeySystem } = require(\"@transmute/element-lib\");\n\n// Instantiate the Sidetree class\nconst element = new Sidetree(/* See previous section for how to initialize the Sidetree class*/);\n\n// Generate a simple did document model\nconst mks = new MnemonicKeySystem(MnemonicKeySystem.generateMnemonic());\nconst primaryKey = await mks.getKeyForPurpose(\"primary\", 0);\nconst recoveryKey = await mks.getKeyForPurpose(\"recovery\", 0);\nconst didDocumentModel = element.op.getDidDocumentModel(\n  primaryKey.publicKey,\n  recoveryKey.publicKey\n);\n\n// Generate Sidetree Create payload\nconst createPayload = element.op.getCreatePayload(didDocumentModel, primaryKey);\n\n// Create the Sidetree transaction.\n// This can potentially take a few minutes if you're not on a local network\nconst createTransaction = await element.batchScheduler.writeNow(createPayload);\nconst didUniqueSuffix = element.func.getDidUniqueSuffix(createPayload);\nconst did = `did:elem:ropsten:${didUniqueSuffix}`;\nconsole.log(`${did} was successfully created`);\n```\n\n#### Read a DID (aka resolve a DID)\n\n```js\nconst didDocument = await element.resolve(didUniqueSuffix, true);\nconsole.log(\n  `${did} was successfully resolved into ${JSON.stringify(\n    didDocument,\n    null,\n    2\n  )}`\n);\n```\n\n#### Update a DID document\n\nAdd a new key to the did document\n\n```js\n// Get last operation data\nconst operations = await element.db.readCollection(didUniqueSuffix);\nconst lastOperation = operations.pop();\n\n// Generate update payload for adding a new key\nconst newKey = await mks.getKeyForPurpose(\"primary\", 1);\nconst newPublicKey = {\n  id: \"#newKey\",\n  usage: \"signing\",\n  type: \"Secp256k1VerificationKey2018\",\n  publicKeyHex: newKey.publicKey,\n};\nconst updatePayload = await element.op.getUpdatePayloadForAddingAKey(\n  lastOperation,\n  newPublicKey,\n  primaryKey.privateKey\n);\n\n// Create the Sidetree transaction.\nconst updateTransaction = await element.batchScheduler.writeNow(updatePayload);\nconst newDidDocument = await element.resolve(didUniqueSuffix, true);\nconsole.log(`${JSON.stringify(newDidDocument, null, 2)} has a new publicKey`);\n```\n\n#### Recover a did document\n\nHow to recover a did document using the recovery key if the private key is lost:\n\n```js\n// Generate a recovery payload with the inital did document model\nconst recoveryPayload = await element.op.getRecoverPayload(\n  didUniqueSuffix,\n  didDocumentModel,\n  recoveryKey.privateKey\n);\n\n// Send Sidetree transaction\nconst recoveryTransaction = await element.batchScheduler.writeNow(\n  recoveryPayload\n);\nconst recoveredDidDocument = await element.resolve(didUniqueSuffix, true);\nconsole.log(`${JSON.stringify(recoveredDidDocument, null, 2)} was recovered`);\n```\n\n#### Delete a did document\n\n```js\n// Generate a delete payload this will brick the did forever\nconst deletePayload = await element.op.getDeletePayload(\n  didUniqueSuffix,\n  recoveryKey.privateKey\n);\n\n// Send Sidetree transaction\nconst deleteTransaction = await element.batchScheduler.writeNow(deletePayload);\nconst deletedDidDocument = await element.resolve(didUniqueSuffix, true);\nconsole.log(`${JSON.stringify(deletedDidDocument, null, 2)} was deleted`);\n```\n\n## How to use element-api\n\n### Define the environment file\n\nIn the root level directory copy the example config\n\n```\ncp example.env .env\n```\n\nthen fill the following values:\n\n- ELEMENT_MNEMONIC: a mnemonic funded with ethereum. See step 1 and 2 of [this tutorial](./create-funded-mnemonic.md)\n- ELEMENT_PROVIDER: either `http://localhost:8545` for connecting with local ganache network or use an Infura URL that should look like this `https://ropsten.infura.io/v3/\u003cAPI_TOKEN\u003e`\n- ELEMENT_IPFS_MULTIADDR: either `/ip4/127.0.0.1/tcp/5001` for connecting with local IPFS node or `/dns4/ipfs.infura.io/tcp/5001/https` for connecting through Infura\n- ELEMENT_CONTRACT_ADDRESS: \"0xD49Da2b7C0A15f6ac5A856f026D68A9B9848D96f\"\n- ELEMENT_COUCHDB_REMOTE: Only use this if you want to you the replication feature of CouchDB\n\nThen run the following create the api config file\n\n```\ncd packages/element-api\nnpm run env:create:prod\n```\n\nYou may now start the API by running\n\n```bash\nnpm run start # if you have setup a firebase project\nnpm run start:standalone # to run the standalone express version of the API\n```\n\n## How to use element-app\n\nAll config is checked into source so you can run the app by:\n\n```bash\nnpm run start\n```\n\n## Useful commands\n\n#### Install:\n\n```\nnpm i\n```\n\n#### Run smart contract tests:\n\n```\nnpm run test:contracts\n```\n\n#### Run lib, api and app tests:\n\n```\nnpm run test\n```\n\n#### Lint\n\n```\nnpm run lint\n```\n\n#### Coverage\n\n```\nnpm run coverage\n```\n\n#### Publishing\n\nIf you have 2fa enabled for npm (and you should!).\n\n```\nlerna version patch\nNPM_CONFIG_OTP=123456 lerna publish\n```\n\n#### Testing Documentation\n\n```\nnpm i -g http-server\nserve ./docs\n```\n\nSee [.travis.yml](./.travis.yml) for setup and test commands for linux.\n\n## Docker\n\nTo run the APP in docker, run\n\n```\ndocker run --rm -p 80:80 gjgd/element-app:latest\n```\n\nTo run the API in docker, run\n\n```\ndocker run --rm -p 80:5002 gjgd/element-api:latest\n```\n\n### How to build Element APP with a different domain for the API:\n\n1. Clone Element\n2. `cd packages/element-app`\n3. edit the content of `.env.production` to the API_URL you want to use\n4. `docker build -t my-tag .`\n5. `docker run --rm -p 80:5002 my-tag`\n6. Now the app runs on port 80 and will use the API_URL specified in 3)\n\n### Release process\n\n```\nlerna publish\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecentralized-identity%2Felement","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdecentralized-identity%2Felement","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecentralized-identity%2Felement/lists"}