├── .env.example ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE │ └── issue-report.md └── dependabot.yml ├── .gitignore ├── .prettierrc ├── LICENSE-APACHE ├── LICENSE-MIT ├── Readme.md ├── dl_circuits.sh ├── index.ts ├── package-lock.json ├── package.json ├── request.ts ├── tsconfig.json └── walletSetup.ts /.env.example: -------------------------------------------------------------------------------- 1 | # reverse hash service url 2 | RHS_URL="https://rhs-staging.polygonid.me" 3 | # state v2 contract address in the amoy network 4 | CONTRACT_ADDRESS="0x1a4cC30f2aA0377b0c3bc9848766D90cb4404124" 5 | # path to the circuits folder 6 | CIRCUITS_PATH="./circuits" 7 | # key in hex format with matic balance 8 | WALLET_KEY="" 9 | # MongoDB connection string, uses in memory Mongo server if not specified 10 | MONGO_DB_CONNECTION="" 11 | # RPC URL for getting info from contract 12 | RPC_URL="" 13 | # Chain ID for the network 14 | CHAIN_ID="" 15 | # third part url to polygon amoy network rpc node 16 | THIRD_PARTY_RPC_URL="" 17 | # third party contract address in the linea test network 18 | THIRD_PARTY_CONTRACT_ADDRESS="" 19 | # third party key in hex format with matic balance 20 | THIRD_PARTY_WALLET_KEY="" 21 | # Chain ID of registered network that you want to connect to 22 | THIRD_PARTY_CHAIN_ID="" 23 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@iden3/eslint-config"], 3 | "rules": { 4 | // no console.log 5 | "no-console": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: Kolezhniuk, vmidyllic, volodymyr-basiuk 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Install SDK 16 | 2. call function with param 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | ** Environment info (please complete the following information):** 25 | - OS version [e.g. Mac OS] 26 | - Node version: [e.g. 18.16] 27 | - Browser [e.g. chrome, safari] 28 | - Package version [e.g. 1.0.0] 29 | - Build [e.g. umd, cjs] 30 | 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | allow: 8 | - dependency-name: "@iden3*" 9 | - dependency-name: "@0xpolygonid*" 10 | reviewers: 11 | - "Kolezhniuk" 12 | - "vmidyllic" 13 | - "volodymyr-basiuk" 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # circuits 41 | circuits_data 42 | 43 | .vscode 44 | circuits 45 | latest.zip 46 | dist 47 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | "@iden3/eslint-config/prettier" -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (C) 2024 ZKID Labs AG 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2024 ZKID Labs AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # js-sdk-examples 2 | 3 | ## Setup 4 | 5 | 1. Download the zk circuits into `./circuits` by running `dl_circuits.sh`. This will download the latest files from `https://circuits.privado.id/latest.zip` 6 | 7 | ```bash 8 | ./dl_circuits.sh 9 | ``` 10 | 11 | - Polygon Amoy or Main RPC - You can get one in any of the providers of this list 12 | - [Chainstack](https://chainstack.com/) 13 | - [Ankr](https://ankr.com/) 14 | - [QuickNode](https://quicknode.com/) 15 | - [Alchemy](https://www.alchemy.com/) 16 | - [Infura](https://www.infura.io/) 17 | 18 | 2. Copy over the `.env.example` into `.env` 19 | You'll need to fill in `RPC_URL` and `WALLET_KEY` with your own endpoint and key respectively. The default env vars assume you will be using the Polygon Amoy network. 20 | 21 | ```bash 22 | cp .env.example .env 23 | ``` 24 | 25 | `example.env` 26 | 27 | ```bash 28 | # reverse hash service url 29 | RHS_URL="https://rhs-staging.polygonid.me" 30 | # state v2 contract address in the amoy network 31 | CONTRACT_ADDRESS="0x1a4cC30f2aA0377b0c3bc9848766D90cb4404124" 32 | # path to the circuits folder 33 | CIRCUITS_PATH="./circuits" 34 | # url to polygon amoy network rpc node 35 | RPC_URL="" 36 | # key in hex format with matic balance 37 | WALLET_KEY="" 38 | # MongoDB connection string, uses in memory Mongo server if not specified 39 | MONGO_DB_CONNECTION="" 40 | # Chain iden 41 | CHAIN_ID="" 42 | ``` 43 | 44 | 3. Install dependencies 45 | 46 | ```bash 47 | npm i 48 | ``` 49 | 50 | ## Run 51 | 52 | You can run each example function independently: 53 | 54 | ```bash 55 | npm run start -- [function] 56 | ``` 57 | 58 | The [function] should be replaced with one of the following options: 59 | 60 | - identityCreation 61 | - issueCredential 62 | - transitState 63 | - transitStateThirdPartyDID 64 | - generateProofs 65 | - handleAuthRequest 66 | - handleAuthRequestWithProfiles 67 | - handleAuthRequestNoIssuerStateTransition 68 | - generateProofsMongo 69 | - handleAuthRequestMongo 70 | 71 | To run all examples 72 | 73 | ```bash 74 | npm run start 75 | ``` 76 | 77 | ## License 78 | 79 | js-sdk-examples is part of the 0xPolygonID project copyright 2024 ZKID Labs AG 80 | 81 | This project is licensed under either of 82 | 83 | - [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) ([`LICENSE-APACHE`](LICENSE-APACHE)) 84 | - [MIT license](https://opensource.org/licenses/MIT) ([`LICENSE-MIT`](LICENSE-MIT)) 85 | 86 | at your option. 87 | -------------------------------------------------------------------------------- /dl_circuits.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Download the latest.zip file 4 | curl -LO https://circuits.privado.id/latest.zip 5 | 6 | # Unzip the file into ./circuits 7 | unzip -d ./circuits latest.zip 8 | 9 | # remove the zip file 10 | rm latest.zip -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | /* eslint-disable no-console */ 3 | import { 4 | EthStateStorage, 5 | CredentialRequest, 6 | CircuitId, 7 | ZeroKnowledgeProofRequest, 8 | AuthorizationRequestMessage, 9 | PROTOCOL_CONSTANTS, 10 | AuthHandler, 11 | core, 12 | CredentialStatusType, 13 | IdentityCreationOptions, 14 | ProofType, 15 | AuthorizationRequestMessageBody, 16 | byteEncoder 17 | } from '@0xpolygonid/js-sdk'; 18 | 19 | import { 20 | initInMemoryDataStorageAndWallets, 21 | initCircuitStorage, 22 | initProofService, 23 | initPackageManager, 24 | initMongoDataStorageAndWallets 25 | } from './walletSetup'; 26 | 27 | import { ethers } from 'ethers'; 28 | import dotenv from 'dotenv'; 29 | import { generateRequestData } from './request'; 30 | dotenv.config(); 31 | 32 | const rhsUrl = process.env.RHS_URL as string; 33 | const walletKey = process.env.WALLET_KEY as string; 34 | 35 | const defaultNetworkConnection = { 36 | rpcUrl: process.env.RPC_URL as string, 37 | contractAddress: process.env.CONTRACT_ADDRESS as string, 38 | chainId: parseInt(process.env.CHAIN_ID as string) 39 | }; 40 | 41 | export const defaultIdentityCreationOptions: IdentityCreationOptions = { 42 | method: core.DidMethod.PolygonId, 43 | blockchain: core.Blockchain.Polygon, 44 | networkId: core.NetworkId.Amoy, 45 | revocationOpts: { 46 | type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 47 | id: rhsUrl 48 | } 49 | }; 50 | 51 | function createKYCAgeCredential(did: core.DID) { 52 | const credentialRequest: CredentialRequest = { 53 | credentialSchema: 54 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json', 55 | type: 'KYCAgeCredential', 56 | credentialSubject: { 57 | id: did.string(), 58 | birthday: 19960424, 59 | documentType: 99 60 | }, 61 | expiration: 12345678888, 62 | revocationOpts: { 63 | type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 64 | id: rhsUrl 65 | } 66 | }; 67 | return credentialRequest; 68 | } 69 | 70 | function createKYCAgeCredentialRequest( 71 | circuitId: CircuitId, 72 | credentialRequest: CredentialRequest 73 | ): ZeroKnowledgeProofRequest { 74 | const proofReqSig: ZeroKnowledgeProofRequest = { 75 | id: 1, 76 | circuitId: CircuitId.AtomicQuerySigV2, 77 | optional: false, 78 | query: { 79 | allowedIssuers: ['*'], 80 | type: credentialRequest.type, 81 | context: 82 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', 83 | credentialSubject: { 84 | documentType: { 85 | $eq: 99 86 | } 87 | } 88 | } 89 | }; 90 | 91 | const proofReqMtp: ZeroKnowledgeProofRequest = { 92 | id: 1, 93 | circuitId: CircuitId.AtomicQueryMTPV2, 94 | optional: false, 95 | query: { 96 | allowedIssuers: ['*'], 97 | type: credentialRequest.type, 98 | context: 99 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', 100 | credentialSubject: { 101 | birthday: { 102 | $lt: 20020101 103 | } 104 | } 105 | } 106 | }; 107 | 108 | switch (circuitId) { 109 | case CircuitId.AtomicQuerySigV2: 110 | return proofReqSig; 111 | case CircuitId.AtomicQueryMTPV2: 112 | return proofReqMtp; 113 | default: 114 | return proofReqSig; 115 | } 116 | } 117 | 118 | async function identityCreation() { 119 | console.log('=============== key creation ==============='); 120 | 121 | const { identityWallet } = await initInMemoryDataStorageAndWallets(defaultNetworkConnection); 122 | const { did, credential } = await identityWallet.createIdentity({ 123 | ...defaultIdentityCreationOptions 124 | }); 125 | 126 | console.log('=============== did ==============='); 127 | console.log(did.string()); 128 | console.log('=============== Auth BJJ credential ==============='); 129 | console.log(JSON.stringify(credential)); 130 | } 131 | 132 | async function issueCredential() { 133 | console.log('=============== issue credential ==============='); 134 | 135 | const { dataStorage, identityWallet } = await initInMemoryDataStorageAndWallets( 136 | defaultNetworkConnection 137 | ); 138 | 139 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 140 | ...defaultIdentityCreationOptions 141 | }); 142 | 143 | console.log('=============== user did ==============='); 144 | console.log(userDID.string()); 145 | 146 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 147 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 148 | 149 | console.log('=============== issuer did ==============='); 150 | console.log(issuerDID.string()); 151 | const credentialRequest = createKYCAgeCredential(userDID); 152 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 153 | 154 | console.log('=============== credential ==============='); 155 | console.log(JSON.stringify(credential)); 156 | 157 | await dataStorage.credential.saveCredential(credential); 158 | } 159 | 160 | async function transitState() { 161 | console.log('=============== transit state ==============='); 162 | 163 | const { dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 164 | defaultNetworkConnection 165 | ); 166 | 167 | const circuitStorage = await initCircuitStorage(); 168 | const proofService = await initProofService( 169 | identityWallet, 170 | credentialWallet, 171 | dataStorage.states, 172 | circuitStorage 173 | ); 174 | 175 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 176 | ...defaultIdentityCreationOptions 177 | }); 178 | 179 | console.log('=============== user did ==============='); 180 | console.log(userDID.string()); 181 | 182 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 183 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 184 | 185 | console.log('=============== issuerDID did ==============='); 186 | console.log(issuerDID.string()); 187 | 188 | const credentialRequest = createKYCAgeCredential(userDID); 189 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 190 | 191 | await dataStorage.credential.saveCredential(credential); 192 | 193 | console.log('================= generate Iden3SparseMerkleTreeProof ======================='); 194 | 195 | const res = await identityWallet.addCredentialsToMerkleTree([credential], issuerDID); 196 | 197 | console.log('================= push states to rhs ==================='); 198 | 199 | await identityWallet.publishRevocationInfoByCredentialStatusType( 200 | issuerDID, 201 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 202 | { rhsUrl } 203 | ); 204 | 205 | console.log('================= publish to blockchain ==================='); 206 | 207 | const ethSigner = new ethers.Wallet(walletKey, dataStorage.states.getRpcProvider()); 208 | const txId = await proofService.transitState( 209 | issuerDID, 210 | res.oldTreeState, 211 | true, 212 | dataStorage.states, 213 | ethSigner 214 | ); 215 | console.log(txId); 216 | } 217 | 218 | async function transitStateThirdPartyDID() { 219 | console.log('=============== THIRD PARTY DID: transit state ==============='); 220 | core.registerDidMethodNetwork({ 221 | method: 'thirdparty', 222 | methodByte: 0b1000_0001, 223 | blockchain: 'linea', 224 | network: 'test', 225 | networkFlag: 0b01000001 | 0b00000001, 226 | chainId: 11155112 227 | }); 228 | 229 | core.registerDidMethodNetwork({ 230 | method: 'iden3', 231 | blockchain: 'linea', 232 | network: 'test', 233 | networkFlag: 0b11000001 | 0b00000011 234 | }); 235 | 236 | const { dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 237 | { 238 | rpcUrl: process.env.THIRD_PARTY_RPC_URL as string, 239 | contractAddress: process.env.THIRD_PARTY_CONTRACT_ADDRESS as string, 240 | chainId: parseInt(process.env.THIRD_PARTY_CHAIN_ID as string) 241 | } 242 | ); 243 | 244 | const circuitStorage = await initCircuitStorage(); 245 | const proofService = await initProofService( 246 | identityWallet, 247 | credentialWallet, 248 | dataStorage.states, 249 | circuitStorage 250 | ); 251 | 252 | const method = core.DidMethod.thirdparty; 253 | const blockchain = core.Blockchain.linea; 254 | const networkId = core.NetworkId.test; 255 | const { did: userDID } = await identityWallet.createIdentity({ 256 | method, 257 | blockchain, 258 | networkId, 259 | revocationOpts: { 260 | type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 261 | id: rhsUrl 262 | } 263 | }); 264 | 265 | console.log('=============== third party: user did ==============='); 266 | console.log(userDID.string()); 267 | 268 | const { did: issuerDID } = await identityWallet.createIdentity({ 269 | method: core.DidMethod.Iden3, 270 | blockchain: core.Blockchain.linea, 271 | networkId: core.NetworkId.test, 272 | revocationOpts: { 273 | type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 274 | id: rhsUrl 275 | } 276 | }); 277 | console.log('=============== third party: issuer did ==============='); 278 | console.log(issuerDID.string()); 279 | 280 | const credentialRequest = createKYCAgeCredential(userDID); 281 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 282 | 283 | await dataStorage.credential.saveCredential(credential); 284 | 285 | console.log( 286 | '================= third party: generate Iden3SparseMerkleTreeProof =======================' 287 | ); 288 | 289 | const res = await identityWallet.addCredentialsToMerkleTree([credential], issuerDID); 290 | 291 | console.log('================= third party: push states to rhs ==================='); 292 | 293 | await identityWallet.publishRevocationInfoByCredentialStatusType( 294 | issuerDID, 295 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 296 | { rhsUrl } 297 | ); 298 | 299 | console.log('================= publish to blockchain ==================='); 300 | 301 | const ethSigner = new ethers.Wallet( 302 | process.env.THIRD_PARTY_WALLET_KEY as string, 303 | dataStorage.states.getRpcProvider() 304 | ); 305 | const txId = await proofService.transitState( 306 | issuerDID, 307 | res.oldTreeState, 308 | true, 309 | dataStorage.states, 310 | ethSigner 311 | ); 312 | console.log(txId); 313 | } 314 | 315 | async function generateProofs(useMongoStore = false) { 316 | console.log('=============== generate proofs ==============='); 317 | 318 | let dataStorage, credentialWallet, identityWallet; 319 | if (useMongoStore) { 320 | ({ dataStorage, credentialWallet, identityWallet } = await initMongoDataStorageAndWallets( 321 | defaultNetworkConnection 322 | )); 323 | } else { 324 | ({ dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 325 | defaultNetworkConnection 326 | )); 327 | } 328 | 329 | const circuitStorage = await initCircuitStorage(); 330 | const proofService = await initProofService( 331 | identityWallet, 332 | credentialWallet, 333 | dataStorage.states, 334 | circuitStorage 335 | ); 336 | 337 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 338 | ...defaultIdentityCreationOptions 339 | }); 340 | 341 | console.log('=============== user did ==============='); 342 | console.log(userDID.string()); 343 | 344 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 345 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 346 | 347 | const credentialRequest = createKYCAgeCredential(userDID); 348 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 349 | 350 | await dataStorage.credential.saveCredential(credential); 351 | 352 | console.log('================= generate Iden3SparseMerkleTreeProof ======================='); 353 | 354 | const res = await identityWallet.addCredentialsToMerkleTree([credential], issuerDID); 355 | 356 | console.log('================= push states to rhs ==================='); 357 | 358 | await identityWallet.publishRevocationInfoByCredentialStatusType( 359 | issuerDID, 360 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 361 | { rhsUrl } 362 | ); 363 | 364 | console.log('================= publish to blockchain ==================='); 365 | 366 | const ethSigner = new ethers.Wallet(walletKey, dataStorage.states.getRpcProvider()); 367 | const txId = await proofService.transitState( 368 | issuerDID, 369 | res.oldTreeState, 370 | true, 371 | dataStorage.states, 372 | ethSigner 373 | ); 374 | console.log(txId); 375 | 376 | console.log('================= generate credentialAtomicSigV2 ==================='); 377 | 378 | const proofReqSig: ZeroKnowledgeProofRequest = createKYCAgeCredentialRequest( 379 | CircuitId.AtomicQuerySigV2, 380 | credentialRequest 381 | ); 382 | 383 | const { proof, pub_signals } = await proofService.generateProof(proofReqSig, userDID); 384 | 385 | const sigProofOk = await proofService.verifyProof( 386 | { proof, pub_signals }, 387 | CircuitId.AtomicQuerySigV2 388 | ); 389 | console.log('valid: ', sigProofOk); 390 | 391 | console.log('================= generate credentialAtomicMTPV2 ==================='); 392 | 393 | const credsWithIden3MTPProof = await identityWallet.generateIden3SparseMerkleTreeProof( 394 | issuerDID, 395 | res.credentials, 396 | txId 397 | ); 398 | 399 | console.log(credsWithIden3MTPProof); 400 | await credentialWallet.saveAll(credsWithIden3MTPProof); 401 | 402 | const proofReqMtp: ZeroKnowledgeProofRequest = createKYCAgeCredentialRequest( 403 | CircuitId.AtomicQueryMTPV2, 404 | credentialRequest 405 | ); 406 | 407 | const { proof: proofMTP, pub_signals: pub_signalsMTP } = await proofService.generateProof( 408 | proofReqMtp, 409 | userDID 410 | ); 411 | 412 | console.log(JSON.stringify(proofMTP)); 413 | const mtpProofOk = await proofService.verifyProof( 414 | { proof: proofMTP, pub_signals: pub_signalsMTP }, 415 | CircuitId.AtomicQueryMTPV2 416 | ); 417 | console.log('valid: ', mtpProofOk); 418 | 419 | const { proof: proof2, pub_signals: pub_signals2 } = await proofService.generateProof( 420 | proofReqSig, 421 | userDID 422 | ); 423 | 424 | const sigProof2Ok = await proofService.verifyProof( 425 | { proof: proof2, pub_signals: pub_signals2 }, 426 | CircuitId.AtomicQuerySigV2 427 | ); 428 | console.log('valid: ', sigProof2Ok); 429 | } 430 | 431 | async function handleAuthRequest(useMongoStore = false) { 432 | console.log('=============== handle auth request ==============='); 433 | 434 | let dataStorage, credentialWallet, identityWallet; 435 | if (useMongoStore) { 436 | ({ dataStorage, credentialWallet, identityWallet } = await initMongoDataStorageAndWallets( 437 | defaultNetworkConnection 438 | )); 439 | } else { 440 | ({ dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 441 | defaultNetworkConnection 442 | )); 443 | } 444 | 445 | const circuitStorage = await initCircuitStorage(); 446 | const proofService = await initProofService( 447 | identityWallet, 448 | credentialWallet, 449 | dataStorage.states, 450 | circuitStorage 451 | ); 452 | 453 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 454 | ...defaultIdentityCreationOptions 455 | }); 456 | 457 | console.log('=============== user did ==============='); 458 | console.log(userDID.string()); 459 | 460 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 461 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 462 | 463 | const credentialRequest = createKYCAgeCredential(userDID); 464 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 465 | 466 | await dataStorage.credential.saveCredential(credential); 467 | 468 | console.log('================= generate Iden3SparseMerkleTreeProof ======================='); 469 | 470 | const res = await identityWallet.addCredentialsToMerkleTree([credential], issuerDID); 471 | 472 | console.log('================= push states to rhs ==================='); 473 | 474 | await identityWallet.publishRevocationInfoByCredentialStatusType( 475 | issuerDID, 476 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 477 | { rhsUrl } 478 | ); 479 | 480 | console.log('================= publish to blockchain ==================='); 481 | 482 | const ethSigner = new ethers.Wallet(walletKey, dataStorage.states.getRpcProvider()); 483 | const txId = await proofService.transitState( 484 | issuerDID, 485 | res.oldTreeState, 486 | true, 487 | dataStorage.states, 488 | ethSigner 489 | ); 490 | console.log(txId); 491 | 492 | console.log('================= generate credentialAtomicSigV2 ==================='); 493 | 494 | const proofReqSig: ZeroKnowledgeProofRequest = createKYCAgeCredentialRequest( 495 | CircuitId.AtomicQuerySigV2, 496 | credentialRequest 497 | ); 498 | 499 | console.log('================= credential auth request ==================='); 500 | 501 | const authRequest: AuthorizationRequestMessage = { 502 | id: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 503 | thid: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 504 | typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage, 505 | from: issuerDID.string(), 506 | type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE, 507 | body: { 508 | callbackUrl: 'http://testcallback.com', 509 | message: 'message to sign', 510 | scope: [proofReqSig], 511 | reason: 'verify age' 512 | } 513 | }; 514 | console.log(JSON.stringify(authRequest)); 515 | 516 | const credsWithIden3MTPProof = await identityWallet.generateIden3SparseMerkleTreeProof( 517 | issuerDID, 518 | res.credentials, 519 | txId 520 | ); 521 | 522 | console.log(credsWithIden3MTPProof); 523 | await credentialWallet.saveAll(credsWithIden3MTPProof); 524 | 525 | const authRawRequest = new TextEncoder().encode(JSON.stringify(authRequest)); 526 | 527 | // * on the user side */ 528 | 529 | console.log('============== handle auth request =============='); 530 | const authV2Data = await circuitStorage.loadCircuitData(CircuitId.AuthV2); 531 | const pm = await initPackageManager( 532 | authV2Data, 533 | proofService.generateAuthV2Inputs.bind(proofService), 534 | proofService.verifyState.bind(proofService) 535 | ); 536 | 537 | const authHandler = new AuthHandler(pm, proofService); 538 | const authHandlerRequest = await authHandler.handleAuthorizationRequest(userDID, authRawRequest); 539 | console.log(JSON.stringify(authHandlerRequest, null, 2)); 540 | } 541 | 542 | async function handleAuthRequestWithProfiles() { 543 | console.log('=============== handle auth request with profiles ==============='); 544 | 545 | const { dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 546 | defaultNetworkConnection 547 | ); 548 | 549 | const circuitStorage = await initCircuitStorage(); 550 | const proofService = await initProofService( 551 | identityWallet, 552 | credentialWallet, 553 | dataStorage.states, 554 | circuitStorage 555 | ); 556 | 557 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 558 | ...defaultIdentityCreationOptions 559 | }); 560 | 561 | console.log('=============== user did ==============='); 562 | console.log(userDID.string()); 563 | 564 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 565 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 566 | 567 | // credential is issued on the profile! 568 | const profileDID = await identityWallet.createProfile(userDID, 50, issuerDID.string()); 569 | 570 | const credentialRequest = createKYCAgeCredential(profileDID); 571 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 572 | 573 | await dataStorage.credential.saveCredential(credential); 574 | 575 | console.log('================= generate credentialAtomicSigV2 ==================='); 576 | 577 | const proofReqSig: ZeroKnowledgeProofRequest = createKYCAgeCredentialRequest( 578 | CircuitId.AtomicQuerySigV2, 579 | credentialRequest 580 | ); 581 | 582 | console.log('================= credential auth request ==================='); 583 | const verifierDID = 'did:example:123#JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw'; 584 | 585 | const authRequest: AuthorizationRequestMessage = { 586 | id: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 587 | thid: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 588 | typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage, 589 | from: verifierDID, 590 | type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE, 591 | body: { 592 | callbackUrl: 'http://testcallback.com', 593 | message: 'message to sign', 594 | scope: [proofReqSig], 595 | reason: 'verify age' 596 | } 597 | }; 598 | console.log(JSON.stringify(authRequest)); 599 | 600 | const authRawRequest = new TextEncoder().encode(JSON.stringify(authRequest)); 601 | 602 | // * on the user side */ 603 | 604 | console.log('============== handle auth request =============='); 605 | const authV2Data = await circuitStorage.loadCircuitData(CircuitId.AuthV2); 606 | const pm = await initPackageManager( 607 | authV2Data, 608 | proofService.generateAuthV2Inputs.bind(proofService), 609 | proofService.verifyState.bind(proofService) 610 | ); 611 | 612 | const authHandler = new AuthHandler(pm, proofService); 613 | 614 | const authProfile = await identityWallet.getProfileByVerifier(authRequest.from); 615 | 616 | // let's check that we didn't create profile for verifier 617 | const authProfileDID = authProfile 618 | ? core.DID.parse(authProfile.id) 619 | : await identityWallet.createProfile(userDID, 100, authRequest.from); 620 | 621 | const resp = await authHandler.handleAuthorizationRequest(authProfileDID, authRawRequest); 622 | 623 | console.log(resp); 624 | } 625 | 626 | async function handleAuthRequestWithProfilesV3CircuitBeta() { 627 | console.log('=============== handle auth request with profiles v3 circuits beta ==============='); 628 | 629 | const { dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 630 | defaultNetworkConnection 631 | ); 632 | 633 | const circuitStorage = await initCircuitStorage(); 634 | const proofService = await initProofService( 635 | identityWallet, 636 | credentialWallet, 637 | dataStorage.states, 638 | circuitStorage 639 | ); 640 | 641 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 642 | ...defaultIdentityCreationOptions 643 | }); 644 | 645 | console.log('=============== user did ==============='); 646 | console.log(userDID.string()); 647 | 648 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 649 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 650 | 651 | // credential is issued on the profile! 652 | const profileDID = await identityWallet.createProfile(userDID, 50, issuerDID.string()); 653 | 654 | const credentialRequest = createKYCAgeCredential(profileDID); 655 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 656 | 657 | await dataStorage.credential.saveCredential(credential); 658 | 659 | console.log('================= generate credentialAtomicV3 ==================='); 660 | 661 | const proofReq: ZeroKnowledgeProofRequest = { 662 | id: 19, 663 | circuitId: CircuitId.AtomicQueryV3, 664 | params: { 665 | nullifierSessionId: '123443290439234342342423423423423' 666 | }, 667 | query: { 668 | groupId: 1, 669 | allowedIssuers: ['*'], 670 | proofType: ProofType.BJJSignature, 671 | type: credentialRequest.type, 672 | context: 673 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', 674 | credentialSubject: { 675 | documentType: {} 676 | } 677 | } 678 | }; 679 | 680 | const linkedProof: ZeroKnowledgeProofRequest = { 681 | id: 20, 682 | circuitId: CircuitId.LinkedMultiQuery10, 683 | optional: false, 684 | query: { 685 | groupId: 1, 686 | proofType: ProofType.BJJSignature, 687 | allowedIssuers: ['*'], 688 | type: credentialRequest.type, 689 | context: 690 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', 691 | credentialSubject: { 692 | birthday: { 693 | $lt: 20010101 694 | } 695 | } 696 | } 697 | }; 698 | 699 | console.log('================= credential auth request ==================='); 700 | const verifierDID = 'did:polygonid:polygon:mumbai:2qLWqgjWa1cGnmPwCreXuPQrfLrRrzDL1evD6AG7p7'; 701 | 702 | const authRequest: AuthorizationRequestMessage = { 703 | id: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 704 | thid: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 705 | typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage, 706 | from: verifierDID, 707 | type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE, 708 | body: { 709 | callbackUrl: 'http://testcallback.com', 710 | message: 'v3 beta', 711 | scope: [proofReq, linkedProof], 712 | reason: 'selective disclosure of document type,' 713 | } 714 | }; 715 | console.log(JSON.stringify(authRequest)); 716 | 717 | const authRawRequest = new TextEncoder().encode(JSON.stringify(authRequest)); 718 | 719 | // * on the user side */ 720 | 721 | console.log('============== handle auth request =============='); 722 | const authV2Data = await circuitStorage.loadCircuitData(CircuitId.AuthV2); 723 | const pm = await initPackageManager( 724 | authV2Data, 725 | proofService.generateAuthV2Inputs.bind(proofService), 726 | proofService.verifyState.bind(proofService) 727 | ); 728 | 729 | const authHandler = new AuthHandler(pm, proofService); 730 | 731 | const authProfile = await identityWallet.getProfileByVerifier(authRequest.from); 732 | 733 | // let's check that we didn't create profile for verifier 734 | const authProfileDID = authProfile 735 | ? core.DID.parse(authProfile.id) 736 | : await identityWallet.createProfile(userDID, 100, authRequest.from); 737 | 738 | const resp = await authHandler.handleAuthorizationRequest(authProfileDID, authRawRequest); 739 | 740 | console.log(resp); 741 | } 742 | 743 | async function handleAuthRequestNoIssuerStateTransition() { 744 | console.log('=============== handle auth request no issuer state transition ==============='); 745 | 746 | const { dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 747 | defaultNetworkConnection 748 | ); 749 | 750 | const circuitStorage = await initCircuitStorage(); 751 | const proofService = await initProofService( 752 | identityWallet, 753 | credentialWallet, 754 | dataStorage.states, 755 | circuitStorage 756 | ); 757 | 758 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 759 | ...defaultIdentityCreationOptions 760 | }); 761 | 762 | console.log('=============== user did ==============='); 763 | console.log(userDID.string()); 764 | 765 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 766 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 767 | 768 | const credentialRequest = createKYCAgeCredential(userDID); 769 | const credential = await identityWallet.issueCredential(issuerDID, credentialRequest); 770 | 771 | await dataStorage.credential.saveCredential(credential); 772 | 773 | console.log('================= generate credentialAtomicSigV2 ==================='); 774 | 775 | const proofReqSig: ZeroKnowledgeProofRequest = createKYCAgeCredentialRequest( 776 | CircuitId.AtomicQuerySigV2, 777 | credentialRequest 778 | ); 779 | 780 | const authRequest: AuthorizationRequestMessage = { 781 | id: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 782 | thid: 'fe6354fe-3db2-48c2-a779-e39c2dda8d90', 783 | typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage, 784 | from: issuerDID.string(), 785 | type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE, 786 | body: { 787 | callbackUrl: 'http://testcallback.com', 788 | message: 'message to sign', 789 | scope: [proofReqSig], 790 | reason: 'verify age' 791 | } 792 | }; 793 | 794 | const authRawRequest = new TextEncoder().encode(JSON.stringify(authRequest)); 795 | 796 | // * on the user side */ 797 | 798 | console.log('============== handle auth request =============='); 799 | const authV2Data = await circuitStorage.loadCircuitData(CircuitId.AuthV2); 800 | const pm = await initPackageManager( 801 | authV2Data, 802 | proofService.generateAuthV2Inputs.bind(proofService), 803 | proofService.verifyState.bind(proofService) 804 | ); 805 | 806 | const authHandler = new AuthHandler(pm, proofService); 807 | const authHandlerRequest = await authHandler.handleAuthorizationRequest(userDID, authRawRequest); 808 | console.log(JSON.stringify(authHandlerRequest, null, 2)); 809 | } 810 | 811 | async function handleAuthRequestV3CircuitsBetaStateTransition() { 812 | console.log('=============== handle auth request no issuer state transition V3 ==============='); 813 | 814 | const { dataStorage, credentialWallet, identityWallet } = await initInMemoryDataStorageAndWallets( 815 | defaultNetworkConnection 816 | ); 817 | 818 | const circuitStorage = await initCircuitStorage(); 819 | const proofService = await initProofService( 820 | identityWallet, 821 | credentialWallet, 822 | dataStorage.states, 823 | circuitStorage 824 | ); 825 | 826 | const authV2Data = await circuitStorage.loadCircuitData(CircuitId.AuthV2); 827 | const pm = await initPackageManager( 828 | authV2Data, 829 | proofService.generateAuthV2Inputs.bind(proofService), 830 | proofService.verifyState.bind(proofService) 831 | ); 832 | 833 | const authHandler = new AuthHandler(pm, proofService); 834 | 835 | const { did: issuerDID, credential: issuerAuthBJJCredential } = 836 | await identityWallet.createIdentity({ ...defaultIdentityCreationOptions }); 837 | 838 | console.log('=============== user did ===============', issuerDID.string()); 839 | 840 | const { did: userDID, credential: authBJJCredentialUser } = await identityWallet.createIdentity({ 841 | ...defaultIdentityCreationOptions 842 | }); 843 | 844 | console.log('=============== user did ===============', userDID.string()); 845 | 846 | const profileDID = await identityWallet.createProfile(userDID, 777, issuerDID.string()); 847 | 848 | const claimReq: CredentialRequest = { 849 | credentialSchema: 850 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/kyc-nonmerklized.json', 851 | type: 'KYCAgeCredential', 852 | credentialSubject: { 853 | id: userDID.string(), 854 | birthday: 19960424, 855 | documentType: 99 856 | }, 857 | expiration: 2793526400, 858 | revocationOpts: { 859 | type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 860 | id: rhsUrl 861 | } 862 | }; 863 | const issuedCred = await identityWallet.issueCredential(issuerDID, claimReq); 864 | await credentialWallet.save(issuedCred); 865 | console.log('=============== issued birthday credential ==============='); 866 | 867 | const res = await identityWallet.addCredentialsToMerkleTree([issuedCred], issuerDID); 868 | console.log('=============== added to merkle tree ==============='); 869 | 870 | await identityWallet.publishRevocationInfoByCredentialStatusType( 871 | issuerDID, 872 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 873 | { rhsUrl } 874 | ); 875 | console.log('=============== published to rhs ==============='); 876 | 877 | const ethSigner = new ethers.Wallet(walletKey, dataStorage.states.getRpcProvider()); 878 | 879 | const txId = await proofService.transitState( 880 | issuerDID, 881 | res.oldTreeState, 882 | true, 883 | dataStorage.states, 884 | ethSigner 885 | ); 886 | 887 | console.log('=============== state transition ===============', txId); 888 | 889 | const credsWithIden3MTPProof = await identityWallet.generateIden3SparseMerkleTreeProof( 890 | issuerDID, 891 | res.credentials, 892 | txId 893 | ); 894 | 895 | await credentialWallet.saveAll(credsWithIden3MTPProof); 896 | 897 | console.log('=============== saved credentials with mtp proof ==============='); 898 | 899 | const employeeCredRequest: CredentialRequest = { 900 | credentialSchema: 901 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCEmployee-v101.json', 902 | type: 'KYCEmployee', 903 | credentialSubject: { 904 | id: profileDID.string(), 905 | ZKPexperiance: true, 906 | hireDate: '2023-12-11', 907 | position: 'boss', 908 | salary: 200, 909 | documentType: 1 910 | }, 911 | revocationOpts: { 912 | type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 913 | id: rhsUrl 914 | } 915 | }; 916 | const employeeCred = await identityWallet.issueCredential(issuerDID, employeeCredRequest); 917 | 918 | await credentialWallet.save(employeeCred); 919 | 920 | console.log('=============== issued employee credential ==============='); 921 | 922 | console.log( 923 | '=============== generate ZeroKnowledgeProofRequest MTP + SIG + with Linked proof ===================' 924 | ); 925 | 926 | const proofReqs: ZeroKnowledgeProofRequest[] = [ 927 | { 928 | id: 1, 929 | circuitId: CircuitId.AtomicQueryV3, 930 | optional: false, 931 | query: { 932 | allowedIssuers: ['*'], 933 | type: claimReq.type, 934 | proofType: ProofType.Iden3SparseMerkleTreeProof, 935 | context: 936 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld', 937 | credentialSubject: { 938 | documentType: { 939 | $eq: 99 940 | } 941 | } 942 | } 943 | }, 944 | { 945 | id: 2, 946 | circuitId: CircuitId.AtomicQueryV3, 947 | optional: false, 948 | params: { 949 | nullifierSessionId: 12345 950 | }, 951 | query: { 952 | groupId: 1, 953 | proofType: ProofType.BJJSignature, 954 | allowedIssuers: ['*'], 955 | type: 'KYCEmployee', 956 | context: 957 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld', 958 | skipClaimRevocationCheck: true, 959 | credentialSubject: { 960 | salary: { 961 | $eq: 200 962 | } 963 | } 964 | } 965 | }, 966 | { 967 | id: 3, 968 | circuitId: CircuitId.LinkedMultiQuery10, 969 | optional: false, 970 | query: { 971 | groupId: 1, 972 | proofType: ProofType.Iden3SparseMerkleTreeProof, 973 | allowedIssuers: ['*'], 974 | type: 'KYCEmployee', 975 | skipClaimRevocationCheck: true, 976 | context: 977 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld', 978 | credentialSubject: { 979 | salary: { 980 | $ne: 300 981 | } 982 | } 983 | } 984 | } 985 | ]; 986 | 987 | const authReqBody: AuthorizationRequestMessageBody = { 988 | callbackUrl: 'http://localhost:8080/callback?id=1234442-123123-123123', 989 | reason: 'reason', 990 | message: 'mesage', 991 | scope: proofReqs 992 | }; 993 | 994 | const id = globalThis.crypto.randomUUID(); 995 | const authReq: AuthorizationRequestMessage = { 996 | id, 997 | typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage, 998 | type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE, 999 | thid: id, 1000 | body: authReqBody, 1001 | from: issuerDID.string() 1002 | }; 1003 | 1004 | const msgBytes = byteEncoder.encode(JSON.stringify(authReq)); 1005 | console.log('=============== auth request ==============='); 1006 | 1007 | const authHandlerRequest = await authHandler.handleAuthorizationRequest(userDID, msgBytes); 1008 | console.log(JSON.stringify(authHandlerRequest, null, 2)); 1009 | } 1010 | 1011 | async function main(choice: string) { 1012 | switch (choice) { 1013 | case 'identityCreation': 1014 | await identityCreation(); 1015 | break; 1016 | case 'issueCredential': 1017 | await issueCredential(); 1018 | break; 1019 | case 'transitState': 1020 | await transitState(); 1021 | break; 1022 | case 'generateProofs': 1023 | await generateProofs(); 1024 | break; 1025 | case 'handleAuthRequest': 1026 | await handleAuthRequest(); 1027 | break; 1028 | case 'handleAuthRequestWithProfiles': 1029 | await handleAuthRequestWithProfiles(); 1030 | break; 1031 | case 'handleAuthRequestWithProfilesV3CircuitBeta': 1032 | await handleAuthRequestWithProfilesV3CircuitBeta(); 1033 | break; 1034 | case 'handleAuthRequestNoIssuerStateTransition': 1035 | await handleAuthRequestNoIssuerStateTransition(); 1036 | break; 1037 | case 'generateRequestData': 1038 | await generateRequestData(); 1039 | break; 1040 | case 'generateProofsMongo': 1041 | await generateProofs(true); 1042 | break; 1043 | case 'handleAuthRequestMongo': 1044 | await handleAuthRequest(true); 1045 | break; 1046 | 1047 | case 'transitStateThirdPartyDID': 1048 | await transitStateThirdPartyDID(); 1049 | break; 1050 | 1051 | case 'handleAuthRequestV3CircuitsBetaStateTransition': 1052 | await handleAuthRequestV3CircuitsBetaStateTransition(); 1053 | break; 1054 | 1055 | default: 1056 | // default run all 1057 | await identityCreation(); 1058 | await issueCredential(); 1059 | await transitState(); 1060 | await generateProofs(); 1061 | await handleAuthRequest(); 1062 | await handleAuthRequestWithProfiles(); 1063 | await handleAuthRequestWithProfilesV3CircuitBeta(); 1064 | await handleAuthRequestNoIssuerStateTransition(); 1065 | await generateRequestData(); 1066 | await generateProofs(true); 1067 | await handleAuthRequest(true); 1068 | await handleAuthRequestV3CircuitsBetaStateTransition(); 1069 | } 1070 | } 1071 | 1072 | (async function () { 1073 | const args = process.argv.slice(2); 1074 | await main(args[0]); 1075 | })(); 1076 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdk-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.ts", 6 | "scripts": { 7 | "start": "tsx index.ts", 8 | "prestart": "npm run build", 9 | "build": "tsc", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "lint": "eslint --fix --ext .js,.ts src/**", 12 | "format": "prettier --write \"*.ts\" " 13 | }, 14 | "author": "", 15 | "license": "MIT or Apache-2.0", 16 | "peerDependencies": { 17 | "@0xpolygonid/js-sdk": "1.28.0", 18 | "@0xpolygonid/mongo-storage": "github:0xPolygonID/nodejs-storage-example", 19 | "@iden3/js-crypto": "1.2.0", 20 | "@iden3/js-jsonld-merklization": "1.5.0", 21 | "@iden3/js-jwz": "1.9.0", 22 | "@iden3/js-merkletree": "1.4.0" 23 | }, 24 | "dependencies": { 25 | "dotenv": "^16.4.7", 26 | "ethers": "6.13.4", 27 | "mongodb-memory-server": "^8.16.0", 28 | "mongodb": "^6.1.0" 29 | }, 30 | "devDependencies": { 31 | "@iden3/eslint-config": "https://github.com/iden3/eslint-config", 32 | "eslint-config-prettier": "^8.8.0", 33 | "eslint-plugin-prettier": "^4.2.1", 34 | "prettier": "^2.7.1", 35 | "tsx": "^4.19.2", 36 | "typescript": "^5.7.2" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /request.ts: -------------------------------------------------------------------------------- 1 | import { byteEncoder, createSchemaHash } from '@0xpolygonid/js-sdk'; 2 | import { Path, getDocumentLoader, Merklizer } from '@iden3/js-jsonld-merklization'; 3 | 4 | const pathToCredentialSubject = 'https://www.w3.org/2018/credentials#credentialSubject'; 5 | 6 | export async function generateRequestData() { 7 | const url = `https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld`; 8 | const type = 'KYCAgeCredential'; 9 | const fieldName = 'birthday'; // in form of field.field2.field3 field must be present in the credential subject 10 | 11 | const opts = { ipfsGatewayURL: 'https://ipfs.io' }; // can be your IFPS gateway if your work with ipfs schemas or empty object 12 | const ldCtx = (await getDocumentLoader(opts)(url)).document; 13 | const ldJSONStr = JSON.stringify(ldCtx); 14 | // const ldBytes = byteEncoder.encode(ldJSONStr); 15 | const typeId = await Path.getTypeIDFromContext(ldJSONStr, type); 16 | const schemaHash = createSchemaHash(byteEncoder.encode(typeId)); 17 | console.log('schemaId', schemaHash.bigInt().toString()); 18 | 19 | // you can use custom IPFS 20 | const path = await Path.getContextPathKey(ldJSONStr, type, fieldName, opts); 21 | path.prepend([pathToCredentialSubject]); 22 | const pathBigInt = await path.mtEntry(); 23 | 24 | console.log('path', pathBigInt.toString()); 25 | 26 | // you can hash the value according to the datatype (that's how it is stored in core claim structure) 27 | 28 | const fieldInfo = { 29 | pathToField: 'KYCEmployee.position', 30 | value: 'developer' 31 | }; 32 | 33 | const datatype = await Path.newTypeFromContext(ldJSONStr, fieldInfo.pathToField); 34 | console.log(datatype); // make sure it is http://www.w3.org/2001/XMLSchema#string 35 | const hashedValue = await Merklizer.hashValue(datatype, fieldInfo.value); 36 | console.log(hashedValue); 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2020", 15 | /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 16 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 17 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 18 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 19 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 20 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 21 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 22 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 23 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 24 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 25 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 26 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 27 | 28 | /* Modules */ 29 | "module": "commonjs", /* Specify what module code is generated. */ 30 | "rootDir": "./", /* Specify the root folder within your source files. */ 31 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 32 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 33 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 34 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 35 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 36 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 37 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 38 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 39 | // "resolveJsonModule": true, /* Enable importing .json files. */ 40 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 41 | 42 | /* JavaScript Support */ 43 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 44 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 45 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 46 | 47 | /* Emit */ 48 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 49 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 50 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 51 | "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 52 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 53 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 54 | // "removeComments": true, /* Disable emitting comments. */ 55 | // "noEmit": true, /* Disable emitting files from a compilation. */ 56 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 57 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 58 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 59 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 62 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 63 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 64 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 65 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 66 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 67 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 68 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 69 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 70 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 71 | 72 | /* Interop Constraints */ 73 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 74 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 75 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 76 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 77 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 78 | 79 | /* Type Checking */ 80 | "strict": true, /* Enable all strict type-checking options. */ 81 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 82 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 83 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 84 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 85 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 86 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 87 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 88 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 89 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 90 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 91 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 92 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 93 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 94 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 95 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 96 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 97 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 98 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 99 | 100 | /* Completeness */ 101 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 102 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /walletSetup.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-non-null-assertion */ 2 | import { proving } from '@iden3/js-jwz'; 3 | import { 4 | BjjProvider, 5 | CredentialStorage, 6 | CredentialWallet, 7 | defaultEthConnectionConfig, 8 | EthStateStorage, 9 | ICredentialWallet, 10 | IDataStorage, 11 | Identity, 12 | IdentityStorage, 13 | IdentityWallet, 14 | IIdentityWallet, 15 | InMemoryDataSource, 16 | InMemoryMerkleTreeStorage, 17 | InMemoryPrivateKeyStore, 18 | KMS, 19 | KmsKeyType, 20 | Profile, 21 | W3CCredential, 22 | EthConnectionConfig, 23 | CircuitData, 24 | IStateStorage, 25 | ProofService, 26 | ICircuitStorage, 27 | CredentialStatusType, 28 | CredentialStatusResolverRegistry, 29 | IssuerResolver, 30 | RHSResolver, 31 | OnChainResolver, 32 | AuthDataPrepareFunc, 33 | StateVerificationFunc, 34 | DataPrepareHandlerFunc, 35 | VerificationHandlerFunc, 36 | IPackageManager, 37 | VerificationParams, 38 | ProvingParams, 39 | ZKPPacker, 40 | PlainPacker, 41 | PackageManager, 42 | AgentResolver, 43 | FSCircuitStorage, 44 | AbstractPrivateKeyStore, 45 | CredentialStatusPublisherRegistry, 46 | Iden3SmtRhsCredentialStatusPublisher 47 | } from '@0xpolygonid/js-sdk'; 48 | import path from 'path'; 49 | import dotenv from 'dotenv'; 50 | dotenv.config(); 51 | import { MongoDataSourceFactory, MerkleTreeMongodDBStorage } from '@0xpolygonid/mongo-storage'; 52 | import { MongoMemoryServer } from 'mongodb-memory-server'; 53 | import { MongoClient, Db } from 'mongodb'; 54 | 55 | export type NetworkConfig = { 56 | contractAddress: string; 57 | rpcUrl: string; 58 | chainId: number; 59 | }; 60 | 61 | const circuitsFolder = process.env.CIRCUITS_PATH as string; 62 | const mongoDbConnection = process.env.MONGO_DB_CONNECTION as string; 63 | 64 | export function initInMemoryDataStorage({ 65 | contractAddress, 66 | rpcUrl, 67 | chainId 68 | }: NetworkConfig): IDataStorage { 69 | const conf: EthConnectionConfig = { 70 | ...defaultEthConnectionConfig, 71 | contractAddress, 72 | url: rpcUrl, 73 | chainId 74 | }; 75 | 76 | // change here priority fees in case transaction is stuck or processing too long 77 | // conf.maxPriorityFeePerGas = '250000000000' - 250 gwei 78 | // conf.maxFeePerGas = '250000000000' - 250 gwei 79 | 80 | const dataStorage = { 81 | credential: new CredentialStorage(new InMemoryDataSource()), 82 | identity: new IdentityStorage( 83 | new InMemoryDataSource(), 84 | new InMemoryDataSource() 85 | ), 86 | mt: new InMemoryMerkleTreeStorage(40), 87 | 88 | states: new EthStateStorage(conf) 89 | }; 90 | 91 | return dataStorage; 92 | } 93 | 94 | export async function initMongoDataStorage({ 95 | rpcUrl, 96 | contractAddress, 97 | chainId 98 | }: NetworkConfig): Promise { 99 | let url = mongoDbConnection; 100 | if (!url) { 101 | const mongodb = await MongoMemoryServer.create(); 102 | url = mongodb.getUri(); 103 | } 104 | const client = new MongoClient(url); 105 | await client.connect(); 106 | const db: Db = client.db('mongodb-sdk-example'); 107 | 108 | const conf: EthConnectionConfig = { 109 | ...defaultEthConnectionConfig, 110 | chainId, 111 | contractAddress, 112 | url: rpcUrl 113 | }; 114 | 115 | const dataStorage = { 116 | credential: new CredentialStorage( 117 | await MongoDataSourceFactory(db, 'credentials') 118 | ), 119 | identity: new IdentityStorage( 120 | await MongoDataSourceFactory(db, 'identity'), 121 | await MongoDataSourceFactory(db, 'profile') 122 | ), 123 | mt: await MerkleTreeMongodDBStorage.setup(db, 40), 124 | states: new EthStateStorage(conf) 125 | }; 126 | 127 | return dataStorage; 128 | } 129 | 130 | export async function initIdentityWallet( 131 | dataStorage: IDataStorage, 132 | credentialWallet: ICredentialWallet, 133 | keyStore: AbstractPrivateKeyStore 134 | ): Promise { 135 | const bjjProvider = new BjjProvider(KmsKeyType.BabyJubJub, keyStore); 136 | const kms = new KMS(); 137 | kms.registerKeyProvider(KmsKeyType.BabyJubJub, bjjProvider); 138 | 139 | const credentialStatusPublisherRegistry = new CredentialStatusPublisherRegistry(); 140 | credentialStatusPublisherRegistry.register( 141 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 142 | new Iden3SmtRhsCredentialStatusPublisher() 143 | ); 144 | 145 | return new IdentityWallet(kms, dataStorage, credentialWallet, { 146 | credentialStatusPublisherRegistry 147 | }); 148 | } 149 | 150 | export async function initInMemoryDataStorageAndWallets(config: NetworkConfig) { 151 | const dataStorage = initInMemoryDataStorage(config); 152 | const credentialWallet = await initCredentialWallet(dataStorage); 153 | const memoryKeyStore = new InMemoryPrivateKeyStore(); 154 | 155 | const identityWallet = await initIdentityWallet(dataStorage, credentialWallet, memoryKeyStore); 156 | 157 | return { 158 | dataStorage, 159 | credentialWallet, 160 | identityWallet 161 | }; 162 | } 163 | 164 | export async function initMongoDataStorageAndWallets(config: NetworkConfig) { 165 | const dataStorage = await initMongoDataStorage(config); 166 | const credentialWallet = await initCredentialWallet(dataStorage); 167 | const memoryKeyStore = new InMemoryPrivateKeyStore(); 168 | 169 | const identityWallet = await initIdentityWallet(dataStorage, credentialWallet, memoryKeyStore); 170 | 171 | return { 172 | dataStorage, 173 | credentialWallet, 174 | identityWallet 175 | }; 176 | } 177 | 178 | export async function initCredentialWallet(dataStorage: IDataStorage): Promise { 179 | const resolvers = new CredentialStatusResolverRegistry(); 180 | resolvers.register(CredentialStatusType.SparseMerkleTreeProof, new IssuerResolver()); 181 | resolvers.register( 182 | CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, 183 | new RHSResolver(dataStorage.states) 184 | ); 185 | resolvers.register( 186 | CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023, 187 | new OnChainResolver([defaultEthConnectionConfig]) 188 | ); 189 | resolvers.register(CredentialStatusType.Iden3commRevocationStatusV1, new AgentResolver()); 190 | 191 | return new CredentialWallet(dataStorage, resolvers); 192 | } 193 | 194 | export async function initCircuitStorage(): Promise { 195 | return new FSCircuitStorage({ 196 | dirname: path.join(__dirname, circuitsFolder) 197 | }); 198 | } 199 | export async function initProofService( 200 | identityWallet: IIdentityWallet, 201 | credentialWallet: ICredentialWallet, 202 | stateStorage: IStateStorage, 203 | circuitStorage: ICircuitStorage 204 | ): Promise { 205 | return new ProofService(identityWallet, credentialWallet, circuitStorage, stateStorage, { 206 | ipfsGatewayURL: 'https://ipfs.io' 207 | }); 208 | } 209 | 210 | export async function initPackageManager( 211 | circuitData: CircuitData, 212 | prepareFn: AuthDataPrepareFunc, 213 | stateVerificationFn: StateVerificationFunc 214 | ): Promise { 215 | const authInputsHandler = new DataPrepareHandlerFunc(prepareFn); 216 | 217 | const verificationFn = new VerificationHandlerFunc(stateVerificationFn); 218 | const mapKey = proving.provingMethodGroth16AuthV2Instance.methodAlg.toString(); 219 | const verificationParamMap: Map = new Map([ 220 | [ 221 | mapKey, 222 | { 223 | key: circuitData.verificationKey!, 224 | verificationFn 225 | } 226 | ] 227 | ]); 228 | 229 | const provingParamMap: Map = new Map(); 230 | provingParamMap.set(mapKey, { 231 | dataPreparer: authInputsHandler, 232 | provingKey: circuitData.provingKey!, 233 | wasm: circuitData.wasm! 234 | }); 235 | 236 | const mgr: IPackageManager = new PackageManager(); 237 | const packer = new ZKPPacker(provingParamMap, verificationParamMap); 238 | const plainPacker = new PlainPacker(); 239 | mgr.registerPackers([packer, plainPacker]); 240 | 241 | return mgr; 242 | } 243 | --------------------------------------------------------------------------------