From dad41d739fe0b3d9db5e84aaaed612cec89b1a71 Mon Sep 17 00:00:00 2001 From: Ilya Date: Wed, 4 Dec 2024 12:10:10 +0100 Subject: [PATCH] Feature/onchain non merklized credential converter (#290) support onchain issuer --- package-lock.json | 486 ++++++------------ package.json | 3 +- src/credentials/credential-wallet.ts | 102 +--- src/credentials/models.ts | 8 + src/iden3comm/handlers/fetch.ts | 49 ++ src/storage/blockchain/index.ts | 1 + .../onchain-non-merklized-issuer-adapter.ts | 327 ++++++++++++ src/storage/blockchain/onchain-issuer.ts | 104 ++++ src/storage/interfaces/index.ts | 1 + src/storage/interfaces/onchain-issuer.ts | 13 + src/verifiable/credential.ts | 111 +++- tests/adapter/onchain-issuer.test.ts | 47 ++ ...chain-non-merklized-issuer-adapter.test.ts | 174 +++++++ tests/handlers/fetch.test.ts | 45 +- 14 files changed, 1057 insertions(+), 414 deletions(-) create mode 100644 src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts create mode 100644 src/storage/blockchain/onchain-issuer.ts create mode 100644 src/storage/interfaces/onchain-issuer.ts create mode 100644 tests/adapter/onchain-issuer.test.ts create mode 100644 tests/adapter/onchain-non-merklized-issuer-adapter.test.ts diff --git a/package-lock.json b/package-lock.json index 4799c1ee..5032f9de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.24.1", "license": "MIT or Apache-2.0", "dependencies": { + "@iden3/onchain-non-merklized-issuer-base-abi": "^0.0.3", "@noble/curves": "^1.4.0", "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -51,7 +52,7 @@ "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "mocha": "10.2.0", - "nock": "^14.0.0-beta.15", + "nock": "^14.0.0-beta.16", "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup": "^4.14.3", @@ -476,9 +477,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-npm": { - "version": "5.1.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.11.tgz", - "integrity": "sha512-5ricJyVMw5TmqR0NfsZS8jEJu1+DLzyUXyjpVFnffPuEtz9jF2XswLK0swZqc9uwWrz0M7IhGVCnmq90srVZCA==", + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.13.tgz", + "integrity": "sha512-7S1Pwq16M4sqvv/op7iHErc6Diz+DXsBYRMS0dDj6HUS44VXMvgejXa3RMd5jwBmcHzkInFm3DW1eb2exBs0cg==", "dev": true, "license": "MIT" }, @@ -528,9 +529,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-rust": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.9.tgz", - "integrity": "sha512-Dhr6TIZsMV92xcikKIWei6p/qswS4M+gTkivpWwz4/1oaVk2nRrxJmCdRoVkJlZkkAc17rjxrS12mpnJZI0iWw==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.10.tgz", + "integrity": "sha512-6o5C8566VGTTctgcwfF3Iy7314W0oMlFFSQOadQ0OEdJ9Z9ERX/PDimrzP3LGuOrvhtEFoK8pj+BLnunNwRNrw==", "dev": true, "license": "MIT" }, @@ -542,9 +543,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-software-terms": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.1.13.tgz", - "integrity": "sha512-S8TLDjY+piV8nmzn4/acwKjDbUtOqfJ9Cb3gZ9egjU/Fm8DBaQ7ziR1S2wntxlGLud9cly+LoWnEoWJYDZFveQ==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.1.17.tgz", + "integrity": "sha512-QORIk1R5DV8oOQ+oAlUWE7UomaJwUucqu2srrc2+PmkoI6R1fJwwg2uHCPBWlIb4PGDNEdXLv9BAD13H+0wytQ==", "dev": true, "license": "MIT" }, @@ -770,23 +771,6 @@ "license": "Python-2.0", "peer": true }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -975,26 +959,6 @@ "node": ">=14" } }, - "node_modules/@iden3/js-jsonld-merklization/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@iden3/js-jsonld-merklization/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC", - "peer": true - }, "node_modules/@iden3/js-jwz": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@iden3/js-jwz/-/js-jwz-1.8.0.tgz", @@ -1021,6 +985,12 @@ "idb-keyval": "^6.2.0" } }, + "node_modules/@iden3/onchain-non-merklized-issuer-base-abi": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@iden3/onchain-non-merklized-issuer-base-abi/-/onchain-non-merklized-issuer-base-abi-0.0.3.tgz", + "integrity": "sha512-4Mt5iP54KEzh0vbyhwKINx8bdZDyDJ6At92dPi3VKbKvk4dN24MlOQx5BfRakkZYJe7xlvMo/QaOjc/zRAlADg==", + "license": "MIT or Apache-2.0" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1258,35 +1228,6 @@ "@rushstack/node-core-library": "5.9.0" } }, - "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", @@ -1301,13 +1242,6 @@ "node": ">=14.17" } }, - "node_modules/@microsoft/api-extractor/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/@microsoft/tsdoc": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", @@ -1661,9 +1595,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz", - "integrity": "sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.3.tgz", + "integrity": "sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==", "cpu": [ "arm" ], @@ -1675,9 +1609,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.4.tgz", - "integrity": "sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.3.tgz", + "integrity": "sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==", "cpu": [ "arm64" ], @@ -1689,9 +1623,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz", - "integrity": "sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.3.tgz", + "integrity": "sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==", "cpu": [ "arm64" ], @@ -1703,9 +1637,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.4.tgz", - "integrity": "sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.3.tgz", + "integrity": "sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==", "cpu": [ "x64" ], @@ -1717,9 +1651,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.4.tgz", - "integrity": "sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.3.tgz", + "integrity": "sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==", "cpu": [ "arm64" ], @@ -1731,9 +1665,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.4.tgz", - "integrity": "sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.3.tgz", + "integrity": "sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==", "cpu": [ "x64" ], @@ -1745,9 +1679,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.4.tgz", - "integrity": "sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.3.tgz", + "integrity": "sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==", "cpu": [ "arm" ], @@ -1759,9 +1693,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.4.tgz", - "integrity": "sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.3.tgz", + "integrity": "sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==", "cpu": [ "arm" ], @@ -1773,9 +1707,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.4.tgz", - "integrity": "sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.3.tgz", + "integrity": "sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==", "cpu": [ "arm64" ], @@ -1787,9 +1721,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.4.tgz", - "integrity": "sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.3.tgz", + "integrity": "sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==", "cpu": [ "arm64" ], @@ -1801,9 +1735,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.4.tgz", - "integrity": "sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.3.tgz", + "integrity": "sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==", "cpu": [ "ppc64" ], @@ -1815,9 +1749,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.4.tgz", - "integrity": "sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.3.tgz", + "integrity": "sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==", "cpu": [ "riscv64" ], @@ -1829,9 +1763,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.4.tgz", - "integrity": "sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.3.tgz", + "integrity": "sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==", "cpu": [ "s390x" ], @@ -1843,9 +1777,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.4.tgz", - "integrity": "sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.3.tgz", + "integrity": "sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==", "cpu": [ "x64" ], @@ -1857,9 +1791,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.4.tgz", - "integrity": "sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.3.tgz", + "integrity": "sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==", "cpu": [ "x64" ], @@ -1871,9 +1805,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.4.tgz", - "integrity": "sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.3.tgz", + "integrity": "sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==", "cpu": [ "arm64" ], @@ -1885,9 +1819,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.4.tgz", - "integrity": "sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.3.tgz", + "integrity": "sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==", "cpu": [ "ia32" ], @@ -1899,9 +1833,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.4.tgz", - "integrity": "sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.3.tgz", + "integrity": "sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==", "cpu": [ "x64" ], @@ -1972,42 +1906,6 @@ } } }, - "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/@rushstack/rig-package": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz", @@ -2205,9 +2103,9 @@ "license": "MIT" }, "node_modules/@types/mocha": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", - "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", "dev": true, "license": "MIT" }, @@ -2292,19 +2190,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", @@ -2422,19 +2307,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/utils": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", @@ -2462,19 +2334,6 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", @@ -3158,9 +3017,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001678", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001678.tgz", - "integrity": "sha512-RR+4U/05gNtps58PEBDZcPWTgEO2MBeoPZ96aQcjmfkBWRIDfN451fW2qyDA9/+HohLLIL5GqiMwA+IB1pWarw==", + "version": "1.0.30001683", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", + "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", "dev": true, "funding": [ { @@ -3583,9 +3442,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.4.tgz", - "integrity": "sha512-9KdyVPPtLHjPAD7tcuzSFs64UfHlLJt7U6qP4/bFVLyjLceyizj6s6jO6YBaV5d0G7g/9KnY/dOpLR4Rcg8YDg==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -3906,9 +3765,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.52", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.52.tgz", - "integrity": "sha512-xtoijJTZ+qeucLBDNztDOuQBE1ksqjvNjvqFoST3nGC7fSpqJ+X6BdTBaY5BHG+IhWWmpc6b/KfpeuEDupEPOQ==", + "version": "1.5.63", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", + "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", "dev": true, "license": "ISC", "peer": true @@ -4267,23 +4126,6 @@ "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4801,9 +4643,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true, "license": "ISC", "peer": true @@ -5013,6 +4855,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -5655,24 +5514,6 @@ "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==", "license": "Apache-2.0" }, - "node_modules/jsonld/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jsonld/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/jsonpath": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", @@ -5855,10 +5696,22 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.13", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", + "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", "dev": true, "license": "MIT", "dependencies": { @@ -6254,13 +6107,13 @@ "peer": true }, "node_modules/nock": { - "version": "14.0.0-beta.15", - "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.0-beta.15.tgz", - "integrity": "sha512-rp72chatxoZbR/2cYHwtb+IX6n6kkanYKGN2PKn4c12JBrj9n4xGUKFykuQHB+Gkz3fynlikFbMH2LI6VoebuQ==", + "version": "14.0.0-beta.16", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.0-beta.16.tgz", + "integrity": "sha512-H6ZyT+Naz9wfy0gNrhD0m+VIkCq9li/eaNQPEUEjXg06gsLR3/jDctROt44Z+iT3gFnkTQ0wXtwKJPdvbueBbg==", "dev": true, "license": "MIT", "dependencies": { - "@mswjs/interceptors": "^0.36.4", + "@mswjs/interceptors": "^0.36.6", "json-stringify-safe": "^5.0.1", "propagate": "^2.0.0" }, @@ -6556,19 +6409,6 @@ "rimraf": "bin.js" } }, - "node_modules/patch-package/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/patch-package/node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -7012,9 +6852,9 @@ } }, "node_modules/rollup": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.4.tgz", - "integrity": "sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.3.tgz", + "integrity": "sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7028,24 +6868,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.24.4", - "@rollup/rollup-android-arm64": "4.24.4", - "@rollup/rollup-darwin-arm64": "4.24.4", - "@rollup/rollup-darwin-x64": "4.24.4", - "@rollup/rollup-freebsd-arm64": "4.24.4", - "@rollup/rollup-freebsd-x64": "4.24.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.24.4", - "@rollup/rollup-linux-arm-musleabihf": "4.24.4", - "@rollup/rollup-linux-arm64-gnu": "4.24.4", - "@rollup/rollup-linux-arm64-musl": "4.24.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.24.4", - "@rollup/rollup-linux-riscv64-gnu": "4.24.4", - "@rollup/rollup-linux-s390x-gnu": "4.24.4", - "@rollup/rollup-linux-x64-gnu": "4.24.4", - "@rollup/rollup-linux-x64-musl": "4.24.4", - "@rollup/rollup-win32-arm64-msvc": "4.24.4", - "@rollup/rollup-win32-ia32-msvc": "4.24.4", - "@rollup/rollup-win32-x64-msvc": "4.24.4", + "@rollup/rollup-android-arm-eabi": "4.27.3", + "@rollup/rollup-android-arm64": "4.27.3", + "@rollup/rollup-darwin-arm64": "4.27.3", + "@rollup/rollup-darwin-x64": "4.27.3", + "@rollup/rollup-freebsd-arm64": "4.27.3", + "@rollup/rollup-freebsd-x64": "4.27.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.3", + "@rollup/rollup-linux-arm-musleabihf": "4.27.3", + "@rollup/rollup-linux-arm64-gnu": "4.27.3", + "@rollup/rollup-linux-arm64-musl": "4.27.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.3", + "@rollup/rollup-linux-riscv64-gnu": "4.27.3", + "@rollup/rollup-linux-s390x-gnu": "4.27.3", + "@rollup/rollup-linux-x64-gnu": "4.27.3", + "@rollup/rollup-linux-x64-musl": "4.27.3", + "@rollup/rollup-win32-arm64-msvc": "4.27.3", + "@rollup/rollup-win32-ia32-msvc": "4.27.3", + "@rollup/rollup-win32-x64-msvc": "4.27.3", "fsevents": "~2.3.2" } }, @@ -7156,6 +6996,21 @@ "license": "MIT", "peer": true }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -7652,19 +7507,6 @@ "webpack": "^5.0.0" } }, - "node_modules/ts-loader/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-loader/node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -8249,10 +8091,16 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/yaml": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", - "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", + "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 6e96f26e..8e19f95c 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "mocha": "10.2.0", - "nock": "^14.0.0-beta.15", + "nock": "^14.0.0-beta.16", "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup": "^4.14.3", @@ -98,6 +98,7 @@ "snarkjs": "0.7.4" }, "dependencies": { + "@iden3/onchain-non-merklized-issuer-base-abi": "^0.0.3", "@noble/curves": "^1.4.0", "ajv": "8.12.0", "ajv-formats": "2.1.1", diff --git a/src/credentials/credential-wallet.ts b/src/credentials/credential-wallet.ts index 54a4ce27..411017bf 100644 --- a/src/credentials/credential-wallet.ts +++ b/src/credentials/credential-wallet.ts @@ -1,4 +1,4 @@ -import { DID, getChainId } from '@iden3/js-iden3-core'; +import { DID } from '@iden3/js-iden3-core'; import { IDataStorage } from '../storage/interfaces'; import { W3CCredential, @@ -266,101 +266,23 @@ export class CredentialWallet implements ICredentialWallet { if (!schema.$metadata.uris['jsonLdContext']) { throw new Error('jsonLdContext is missing is the schema'); } - request.context = request.context ?? []; + // do copy of request to avoid mutation + const r = { ...request }; + r.context = r.context ?? []; if ( - request.displayMethod?.type === DisplayMethodType.Iden3BasicDisplayMethodV1 && - !request.context.includes(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD) + r.displayMethod?.type === DisplayMethodType.Iden3BasicDisplayMethodV1 && + !r.context.includes(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD) ) { - request.context.push(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD); + r.context.push(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD); } - const context = [ - VerifiableConstants.JSONLD_SCHEMA.W3C_CREDENTIAL_2018, - ...request.context, - VerifiableConstants.JSONLD_SCHEMA.IDEN3_CREDENTIAL, - schema.$metadata.uris['jsonLdContext'] - ]; + r.context.push(schema.$metadata.uris['jsonLdContext']); + r.expiration = r.expiration ? r.expiration * 1000 : undefined; + r.id = r.id ? r.id : `urn:${uuid.v4()}`; + r.issuanceDate = r.issuanceDate ? r.issuanceDate * 1000 : Date.now(); - const credentialType = [ - VerifiableConstants.CREDENTIAL_TYPE.W3C_VERIFIABLE_CREDENTIAL, - request.type - ]; - - const expirationDate = - !request.expiration || request.expiration == 0 ? null : request.expiration; - - const credentialSubject = request.credentialSubject; - credentialSubject['type'] = request.type; - - const cr = new W3CCredential(); - cr.id = `urn:${uuid.v4()}`; - cr['@context'] = context; - cr.type = credentialType; - cr.expirationDate = expirationDate ? new Date(expirationDate * 1000).toISOString() : undefined; - cr.refreshService = request.refreshService; - cr.displayMethod = request.displayMethod; - cr.issuanceDate = new Date().toISOString(); - cr.credentialSubject = credentialSubject; - cr.issuer = issuer.string(); - cr.credentialSchema = { - id: request.credentialSchema, - type: VerifiableConstants.JSON_SCHEMA_VALIDATOR - }; - - cr.credentialStatus = this.buildCredentialStatus(request, issuer); - - return cr; + return W3CCredential.fromCredentialRequest(issuer, r); }; - /** - * Builds credential status - * @param {CredentialRequest} request - * @returns `CredentialStatus` - */ - private buildCredentialStatus(request: CredentialRequest, issuer: DID): CredentialStatus { - const credentialStatus: CredentialStatus = { - id: request.revocationOpts.id, - type: request.revocationOpts.type, - revocationNonce: request.revocationOpts.nonce - }; - - switch (request.revocationOpts.type) { - case CredentialStatusType.SparseMerkleTreeProof: - return { - ...credentialStatus, - id: `${credentialStatus.id.replace(/\/$/, '')}/${credentialStatus.revocationNonce}` - }; - case CredentialStatusType.Iden3ReverseSparseMerkleTreeProof: - return { - ...credentialStatus, - id: request.revocationOpts.issuerState - ? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${ - request.revocationOpts.issuerState - }` - : `${credentialStatus.id.replace(/\/$/, '')}` - }; - case CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: { - const issuerId = DID.idFromDID(issuer); - const chainId = getChainId(DID.blockchainFromId(issuerId), DID.networkIdFromId(issuerId)); - const searchParams = [ - ['revocationNonce', request.revocationOpts.nonce?.toString() || ''], - ['contractAddress', `${chainId}:${request.revocationOpts.id}`], - ['state', request.revocationOpts.issuerState || ''] - ] - .filter(([, value]) => Boolean(value)) - .map(([key, value]) => `${key}=${value}`) - .join('&'); - - return { - ...credentialStatus, - // `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)` - id: `${issuer.string()}/credentialStatus?${searchParams}` - }; - } - default: - return credentialStatus; - } - } - /** * {@inheritDoc ICredentialWallet.findById} */ diff --git a/src/credentials/models.ts b/src/credentials/models.ts index db529f21..9d0b6e2b 100644 --- a/src/credentials/models.ts +++ b/src/credentials/models.ts @@ -23,6 +23,10 @@ export type PublishMode = 'sync' | 'async' | 'callback'; * @interface CredentialRequest */ export interface CredentialRequest { + /** + * Credential ID + */ + id?: string; /** * JSON credential schema */ @@ -64,6 +68,10 @@ export interface CredentialRequest { * merklizedRootPosition (index / value / none) */ merklizedRootPosition?: MerklizedRootPosition; + /** + * issuance Date + */ + issuanceDate?: number; /** * Revocation options diff --git a/src/iden3comm/handlers/fetch.ts b/src/iden3comm/handlers/fetch.ts index a2f82afc..2e9613d7 100644 --- a/src/iden3comm/handlers/fetch.ts +++ b/src/iden3comm/handlers/fetch.ts @@ -6,6 +6,7 @@ import { CredentialFetchRequestMessage, CredentialIssuanceMessage, CredentialsOfferMessage, + CredentialsOnchainOfferMessage, IPackageManager, JWSPackerParams, MessageFetchRequestMessage @@ -24,6 +25,7 @@ import { IProtocolMessageHandler } from './message-handler'; import { verifyExpiresTime } from './common'; +import { IOnchainIssuer } from '../../storage'; /** * @@ -128,6 +130,7 @@ export class FetchHandler private readonly _packerMgr: IPackageManager, private readonly opts?: { credentialWallet: ICredentialWallet; + onchainIssuer?: IOnchainIssuer; } ) { super(); @@ -152,11 +155,43 @@ export class FetchHandler return this.handleFetchRequest(message as CredentialFetchRequestMessage); case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE: return this.handleIssuanceResponseMsg(message as CredentialIssuanceMessage); + case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE: { + const result = await this.handleOnchainOfferMessage( + message as CredentialsOnchainOfferMessage + ); + if (Array.isArray(result)) { + const credWallet = this.opts?.credentialWallet; + if (!credWallet) throw new Error('Credential wallet is not provided'); + await credWallet.saveAll(result); + return null; + } + return result as BasicMessage; + } default: return super.handle(message, ctx); } } + private async handleOnchainOfferMessage( + offerMessage: CredentialsOnchainOfferMessage + ): Promise { + if (!this.opts?.onchainIssuer) { + throw new Error('onchain issuer is not provided'); + } + const credentials: W3CCredential[] = []; + for (const credentialInfo of offerMessage.body.credentials) { + const issuerDID = DID.parse(offerMessage.from); + const userDID = DID.parse(offerMessage.to); + const credential = await this.opts.onchainIssuer.getCredential( + issuerDID, + userDID, + BigInt(credentialInfo.id) + ); + credentials.push(credential); + } + return credentials; + } + private async handleOfferMessage( offerMessage: CredentialsOfferMessage, ctx: { @@ -275,6 +310,20 @@ export class FetchHandler throw new Error('invalid protocol message response'); } + /** + * Handles only messages with credentials/1.0/onchain-offer type + * @beta + */ + async handleOnchainOffer(offer: Uint8Array): Promise { + const offerMessage = await FetchHandler.unpackMessage( + this._packerMgr, + offer, + PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE + ); + + return this.handleOnchainOfferMessage(offerMessage); + } + private async handleFetchRequest( msgRequest: CredentialFetchRequestMessage ): Promise { diff --git a/src/storage/blockchain/index.ts b/src/storage/blockchain/index.ts index 4f59682a..9f746007 100644 --- a/src/storage/blockchain/index.ts +++ b/src/storage/blockchain/index.ts @@ -1,5 +1,6 @@ export * from './state'; export * from './onchain-zkp-verifier'; export * from './onchain-revocation'; +export * from './onchain-issuer'; export * from './did-resolver-readonly-storage'; export * from './erc20-helper'; diff --git a/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts b/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts new file mode 100644 index 00000000..636a677f --- /dev/null +++ b/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts @@ -0,0 +1,327 @@ +import { Claim, DID, Id } from '@iden3/js-iden3-core'; +import { NonMerklizedIssuerBase__factory } from '@iden3/onchain-non-merklized-issuer-base-abi'; +import { NonMerklizedIssuerBase } from '@iden3/onchain-non-merklized-issuer-base-abi'; +import { INonMerklizedIssuer } from '@iden3/onchain-non-merklized-issuer-base-abi'; +import { + CredentialStatusType, + DisplayMethod, + DisplayMethodType, + Iden3SparseMerkleTreeProof, + W3CCredential +} from '../../../../../../verifiable'; +import { Merklizer, Path } from '@iden3/js-jsonld-merklization'; +import { XSDNS } from '../../../../../../circuits'; +import { Hash, Proof } from '@iden3/js-merkletree'; +import { JsonDocumentObject } from '../../../../../../iden3comm'; +import { ethers } from 'ethers'; +import { getDateFromUnixTimestamp } from '@iden3/js-iden3-core'; +import { Options } from '@iden3/js-jsonld-merklization'; +import { EthConnectionConfig } from '../../../../state'; + +enum NonMerklizedIssuerInterfaces { + InterfaceDetection = '0x01ffc9a7', + InterfaceNonMerklizedIssuer = '0x58874949', + InterfaceGetCredential = '0x5d1ca631' +} + +enum ValueHashes { + BooleanTrue = '18586133768512220936620570745912940619677854269274689475585506675881198879027', + BooleanFalse = '19014214495641488759237505126948346942972912379615652741039992445865937985820' +} + +/** + * `OnchainNonMerklizedIssuerAdapter` provides functionality to interact with a non-merklized on-chain credential issuer. + * This adapter enables interface detection, credential retrieval, and conversion to the W3C Verifiable Credential format. + * + * @public + * @beta + * @class OnchainNonMerklizedIssuerAdapter + */ +export class OnchainNonMerklizedIssuerAdapter { + private readonly _contract: NonMerklizedIssuerBase; + private readonly _contractAddress: string; + private readonly _chainId: number; + + private readonly _issuerDid: DID; + + private readonly _merklizationOptions?: Options; + + /** + * Initializes an instance of `OnchainNonMerklizedIssuerAdapter`. + * + * @param ethConnectionConfig The configuration for the Ethereum connection. + * @param issuerDid The decentralized identifier (DID) of the issuer. + * @param merklizationOptions Optional settings for merklization. + */ + constructor( + ethConnectionConfig: EthConnectionConfig, + issuerDid: DID, + options?: { + merklizationOptions?: Options; + } + ) { + if (!ethConnectionConfig.chainId) { + throw new Error('Chain ID is required'); + } + this._chainId = ethConnectionConfig.chainId; + + this._contractAddress = ethers.getAddress( + ethers.hexlify(Id.ethAddressFromId(DID.idFromDID(issuerDid))) + ); + this._contract = NonMerklizedIssuerBase__factory.connect( + this._contractAddress, + new ethers.JsonRpcProvider(ethConnectionConfig.url) + ); + + this._issuerDid = issuerDid; + this._merklizationOptions = options?.merklizationOptions; + } + + /** + * Checks if the contract supports required interfaces. + * Throws an error if any required interface is unsupported. + * + * @throws Error - If required interfaces are not supported. + */ + public async isInterfaceSupported() { + const supportedInterfaces = [ + { + name: 'Interface detection ERC-165', + value: NonMerklizedIssuerInterfaces.InterfaceDetection + }, + { + name: 'Interface non-merklized issuer', + value: NonMerklizedIssuerInterfaces.InterfaceNonMerklizedIssuer + }, + { + name: 'Interface get credential', + value: NonMerklizedIssuerInterfaces.InterfaceGetCredential + } + ]; + + const unsupportedInterfaces = await Promise.all( + supportedInterfaces.map(async (interfaceObj) => { + const isSupported = await this._contract.supportsInterface(interfaceObj.value); + return isSupported ? null : interfaceObj.name; + }) + ); + + const unsupportedInterfacesFiltered = unsupportedInterfaces.filter( + (interfaceName) => interfaceName !== null + ); + + if (unsupportedInterfacesFiltered.length > 0) { + throw new Error(`Unsupported interfaces: ${unsupportedInterfacesFiltered.join(', ')}`); + } + } + + /** + * Retrieves a credential from the on-chain non-merklized contract. + * @param userId The user's core.Id. + * @param credentialId The unique identifier of the credential. + */ + public async getCredential( + userId: Id, + credentialId: bigint + ): Promise<{ + credentialData: INonMerklizedIssuer.CredentialDataStructOutput; + coreClaimBigInts: bigint[]; + credentialSubjectFields: INonMerklizedIssuer.SubjectFieldStructOutput[]; + }> { + const [credentialData, coreClaimBigInts, credentialSubjectFields] = + await this._contract.getCredential(userId.bigInt(), credentialId); + return { credentialData, coreClaimBigInts, credentialSubjectFields }; + } + + /** + * Retrieves the credential IDs of a user. + * @param userId The user's core.Id. + * @returns An array of credential IDs. + */ + public async getUserCredentialsIds(userId: Id): Promise { + return this._contract.getUserCredentialIds(userId.bigInt()); + } + + /** + * Converts on-chain credential to a verifiable credential. + * + * @param credentialData Data structure of the credential from the contract. + * @param coreClaimBigInts Claim data in bigint format. + * @param credentialSubjectFields Subject fields of the credential. + */ + public async convertOnChainInfoToW3CCredential( + credentialData: INonMerklizedIssuer.CredentialDataStructOutput, + coreClaimBigInts: bigint[], + credentialSubjectFields: INonMerklizedIssuer.SubjectFieldStructOutput[] + ): Promise { + const c = new Claim().unMarshalJson(JSON.stringify(coreClaimBigInts.map((b) => b.toString()))); + + const credentialSubject = await this.convertCredentialSubject( + c, + credentialData.context, + credentialData._type, + credentialSubjectFields + ); + + const credentialRequest = { + id: this.credentialId(credentialData.id), + credentialSchema: credentialData.credentialSchema.id, + type: credentialData._type, + credentialSubject: credentialSubject, + expiration: c.getExpirationDate()?.getTime(), + displayMethod: this.convertDisplayMethod(credentialData.displayMethod), + context: credentialData.context, + revocationOpts: { + id: this._contractAddress, + nonce: Number(c.getRevocationNonce()), + type: CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023 + }, + issuanceDate: getDateFromUnixTimestamp(Number(credentialData.issuanceDate)).getTime() + }; + + const existenceProof = await this.existenceProof(c); + const w3c = W3CCredential.fromCredentialRequest(this._issuerDid, credentialRequest); + w3c.proof = [existenceProof]; + return w3c; + } + + private credentialId(id: bigint): string { + return `urn:iden3:onchain:${this._chainId}:${this._contractAddress}:${id}`; + } + + private async convertCredentialSubject( + coreClaim: Claim, + contractContexts: string[], + credentialType: string, + credentialSubjectFields: INonMerklizedIssuer.SubjectFieldStructOutput[] + ): Promise { + const contractContextsStr = JSON.stringify({ + '@context': contractContexts + }); + + const credentialSubject = {} as JsonDocumentObject; + for (const f of credentialSubjectFields) { + const dataType = await Path.newTypeFromContext( + contractContextsStr, + `${credentialType}.${f.key}`, + this._merklizationOptions + ); + switch (dataType) { + case XSDNS.Boolean: { + switch (f.rawValue.toString()) { + case ValueHashes.BooleanTrue: + credentialSubject[f.key] = true; + break; + case ValueHashes.BooleanFalse: + credentialSubject[f.key] = false; + break; + } + break; + } + case (XSDNS.NonNegativeInteger, + XSDNS.NonPositiveInteger, + XSDNS.NegativeInteger, + XSDNS.PositiveInteger): { + credentialSubject[f.key] = f.value.toString(); + break; + } + case XSDNS.Integer: { + credentialSubject[f.key] = Number(f.value); + break; + } + case XSDNS.String: { + this.validateSourceValue(dataType, f.value, f.rawValue); + credentialSubject[f.key] = f.rawValue; + break; + } + case XSDNS.DateTime: { + const timestamp = BigInt(f.rawValue); + const sourceTimestamp = getDateFromUnixTimestamp(Number(timestamp)).toISOString(); + this.validateSourceValue(dataType, f.value, sourceTimestamp); + credentialSubject[f.key] = sourceTimestamp; + break; + } + case XSDNS.Double: { + const rawFloat = Number(f.rawValue); + this.validateSourceValue(dataType, f.value, rawFloat); + credentialSubject[f.key] = rawFloat; + break; + } + default: { + throw new Error(`Unsupported data type ${dataType}`); + } + } + } + credentialSubject['type'] = credentialType; + + const subjectId = coreClaim.getId(); + const subjectDid = DID.parseFromId(subjectId); + credentialSubject['id'] = subjectDid.string(); + + return credentialSubject; + } + + private async existenceProof(coreClaim: Claim): Promise { + const [mtpProof, stateInfo] = await this._contract.getClaimProofWithStateInfo( + coreClaim.hIndex() + ); + if (!mtpProof.existence) { + throw new Error('Claim does not exist'); + } + const latestStateHash = Hash.fromBigInt(stateInfo.state); + const latestClaimsOfRootHash = Hash.fromBigInt(stateInfo.claimsRoot); + const latestRevocationOfRootHash = Hash.fromBigInt(stateInfo.revocationsRoot); + const latestRootsOfRootHash = Hash.fromBigInt(stateInfo.rootsRoot); + + const p = new Proof({ + siblings: mtpProof.siblings.map((s) => Hash.fromBigInt(s)), + existence: mtpProof.existence, + nodeAux: mtpProof.auxExistence + ? { + key: Hash.fromBigInt(mtpProof.auxIndex), + value: Hash.fromBigInt(mtpProof.auxValue) + } + : undefined + }); + + return new Iden3SparseMerkleTreeProof({ + issuerData: { + id: this._issuerDid, + state: { + value: latestStateHash, + claimsTreeRoot: latestClaimsOfRootHash, + revocationTreeRoot: latestRevocationOfRootHash, + rootOfRoots: latestRootsOfRootHash + } + }, + mtp: p, + coreClaim: coreClaim + }); + } + + private async validateSourceValue(dataType: string, originHash: bigint, source: unknown) { + const sourceHash = await Merklizer.hashValue(dataType, source); + if (sourceHash !== originHash) { + throw new Error(`Invalid source value for ${dataType} type`); + } + } + + private convertDisplayMethod( + onchainDisplayMethod: INonMerklizedIssuer.DisplayMethodStructOutput + ): DisplayMethod | undefined { + if (!onchainDisplayMethod.id || !onchainDisplayMethod._type) { + return undefined; + } + switch (onchainDisplayMethod._type) { + case DisplayMethodType.Iden3BasicDisplayMethodV1: { + return { + id: onchainDisplayMethod.id, + type: DisplayMethodType.Iden3BasicDisplayMethodV1 + }; + } + default: { + throw new Error(`Unsupported display method type ${onchainDisplayMethod._type}`); + } + } + } +} diff --git a/src/storage/blockchain/onchain-issuer.ts b/src/storage/blockchain/onchain-issuer.ts new file mode 100644 index 00000000..02e01fde --- /dev/null +++ b/src/storage/blockchain/onchain-issuer.ts @@ -0,0 +1,104 @@ +import { DID, Id, chainIDfromDID } from '@iden3/js-iden3-core'; +import { Contract, ethers } from 'ethers'; +import { INonMerklizedIssuerABI as abi } from '@iden3/onchain-non-merklized-issuer-base-abi'; +import { Options } from '@iden3/js-jsonld-merklization'; +import { W3CCredential } from '../../verifiable'; +import { OnchainNonMerklizedIssuerAdapter } from './onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter'; +import { EthConnectionConfig } from './state'; +import { IOnchainIssuer } from '../interfaces/onchain-issuer'; + +interface OnchainIssuerOptions { + merklizationOptions?: Options; +} + +/** + * Represents an adapter for interacting with on-chain issuers. + * + * @public + * @beta + * @class OnchainIssuer + */ +export class OnchainIssuer implements IOnchainIssuer { + private readonly _ethConnectionConfig: EthConnectionConfig[]; + private readonly _onchainIssuerOptions?: OnchainIssuerOptions; + + /** + * Initializes an instance of `Adapter`. + * @param config The configuration for the Ethereum connection. + * @param merklizationOptions Optional settings for merklization. + */ + constructor(config: EthConnectionConfig[], options?: OnchainIssuerOptions) { + this._ethConnectionConfig = config; + this._onchainIssuerOptions = options; + } + + /** + * Retrieves a credential from the on-chain issuer. + * @param issuerDID The issuer's core.DID. + * @param userId The user's core.Id. + * @param credentialId The unique identifier of the credential. + */ + public async getCredential( + issuerDID: DID, + userDID: DID, + credentialId: bigint + ): Promise { + const { contract, connection } = this.getContractConnection(issuerDID); + const response = await contract.getCredentialAdapterVersion(); + switch (response) { + case '0.0.1': { + const adapter = new OnchainNonMerklizedIssuerAdapter(connection, issuerDID, { + merklizationOptions: this._onchainIssuerOptions?.merklizationOptions + }); + await adapter.isInterfaceSupported(); + const { credentialData, coreClaimBigInts, credentialSubjectFields } = + await adapter.getCredential(DID.idFromDID(userDID), credentialId); + return await adapter.convertOnChainInfoToW3CCredential( + credentialData, + coreClaimBigInts, + credentialSubjectFields + ); + } + default: + throw new Error(`Unsupported adapter version ${response}`); + } + } + + /** + * Retrieves the credential identifiers for a user from the on-chain issuer. + * @param issuerDID The issuer's core.DID. + * @param userId The user's core.Id. + */ + public async getUserCredentialIds(issuerDID: DID, userDID: DID): Promise { + const { contract, connection } = this.getContractConnection(issuerDID); + const response = await contract.getCredentialAdapterVersion(); + switch (response) { + case '0.0.1': { + const adapter = new OnchainNonMerklizedIssuerAdapter(connection, issuerDID, { + merklizationOptions: this._onchainIssuerOptions?.merklizationOptions + }); + await adapter.isInterfaceSupported(); + return await adapter.getUserCredentialsIds(DID.idFromDID(userDID)); + } + default: + throw new Error(`Unsupported adapter version ${response}`); + } + } + + private getContractConnection(did: DID): { contract: Contract; connection: EthConnectionConfig } { + const issuerId = DID.idFromDID(did); + const chainId = chainIDfromDID(did); + const contractAddress = ethers.getAddress(ethers.hexlify(Id.ethAddressFromId(issuerId))); + const connection = this._ethConnectionConfig.find((c) => c.chainId === chainId); + if (!connection) { + throw new Error(`No connection found for chain ID ${chainId}`); + } + if (!connection.url) { + throw new Error(`No URL found for chain ID ${chainId}`); + } + + const contract = new Contract(contractAddress, abi, new ethers.JsonRpcProvider(connection.url)); + + return { contract, connection }; + } +} diff --git a/src/storage/interfaces/index.ts b/src/storage/interfaces/index.ts index a24d2597..8086ee77 100644 --- a/src/storage/interfaces/index.ts +++ b/src/storage/interfaces/index.ts @@ -7,3 +7,4 @@ export * from './data-source'; export * from './circuits'; export * from './onchain-zkp-verifier'; export * from './onchain-revocation'; +export * from './onchain-issuer'; diff --git a/src/storage/interfaces/onchain-issuer.ts b/src/storage/interfaces/onchain-issuer.ts new file mode 100644 index 00000000..f4c7f9b1 --- /dev/null +++ b/src/storage/interfaces/onchain-issuer.ts @@ -0,0 +1,13 @@ +import { DID } from '@iden3/js-iden3-core'; +import { W3CCredential } from '../../verifiable'; + +/** + * Interface that allows the processing of the on-chain issuer + * + * @beta + * @interface IOnchainIssuer + */ +export interface IOnchainIssuer { + getCredential(issuerDID: DID, userDID: DID, credentialId: bigint): Promise; + getUserCredentialIds(issuerDID: DID, userDID: DID): Promise; +} diff --git a/src/verifiable/credential.ts b/src/verifiable/credential.ts index 2fdd31d7..bcbeb587 100644 --- a/src/verifiable/credential.ts +++ b/src/verifiable/credential.ts @@ -11,15 +11,22 @@ import { DID, MerklizedRootPosition as MerklizedRootPositionCore, IdPosition, - ClaimOptions + ClaimOptions, + getChainId } from '@iden3/js-iden3-core'; import { Proof, Hash, rootFromProof, verifyProof } from '@iden3/js-merkletree'; import { Merklizer, Options } from '@iden3/js-jsonld-merklization'; import { PublicKey, poseidon } from '@iden3/js-crypto'; -import { CredentialStatusResolverRegistry } from '../credentials'; +import { CredentialRequest, CredentialStatusResolverRegistry } from '../credentials'; import { getUserDIDFromCredential } from '../credentials/utils'; import { byteEncoder, validateDIDDocumentAuth } from '../utils'; -import { MerklizedRootPosition, ProofType, SubjectPosition } from './constants'; +import { + CredentialStatusType, + MerklizedRootPosition, + ProofType, + SubjectPosition, + VerifiableConstants +} from './constants'; import { calculateCoreSchemaHash, CoreClaimCreationOptions, @@ -52,6 +59,104 @@ export class W3CCredential { credentialSchema!: CredentialSchema; proof?: object | unknown[]; + /** + * + * @param issuer - DID of the issuer + * @param request - Credential request + * @returns - W3C Credential + */ + static fromCredentialRequest(issuer: DID, request: CredentialRequest): W3CCredential { + if (!request.id) { + throw new Error('Credential id is required'); + } + if (!request.context) { + throw new Error('Credential context is required'); + } + + const context = [ + VerifiableConstants.JSONLD_SCHEMA.W3C_CREDENTIAL_2018, + VerifiableConstants.JSONLD_SCHEMA.IDEN3_CREDENTIAL, + ...request.context + ]; + + const credentialType = [ + VerifiableConstants.CREDENTIAL_TYPE.W3C_VERIFIABLE_CREDENTIAL, + request.type + ]; + + const credentialSubject = request.credentialSubject; + credentialSubject['type'] = request.type; + + const cr = new W3CCredential(); + cr.id = request.id; + cr['@context'] = context; + cr.type = credentialType; + cr.credentialSubject = credentialSubject; + cr.issuer = issuer.string(); + cr.credentialSchema = { + id: request.credentialSchema, + type: VerifiableConstants.JSON_SCHEMA_VALIDATOR + }; + cr.credentialStatus = W3CCredential.buildCredentialStatus(request, issuer); + + request.expiration && (cr.expirationDate = new Date(request.expiration).toISOString()); + request.refreshService && (cr.refreshService = request.refreshService); + request.displayMethod && (cr.displayMethod = request.displayMethod); + request.issuanceDate && (cr.issuanceDate = new Date(request.issuanceDate).toISOString()); + + return cr; + } + + /** + * Builds credential status + * @param {CredentialRequest} request + * @returns `CredentialStatus` + */ + private static buildCredentialStatus(request: CredentialRequest, issuer: DID): CredentialStatus { + const credentialStatus: CredentialStatus = { + id: request.revocationOpts.id, + type: request.revocationOpts.type, + revocationNonce: request.revocationOpts.nonce + }; + + switch (request.revocationOpts.type) { + case CredentialStatusType.SparseMerkleTreeProof: + return { + ...credentialStatus, + id: `${credentialStatus.id.replace(/\/$/, '')}/${credentialStatus.revocationNonce}` + }; + case CredentialStatusType.Iden3ReverseSparseMerkleTreeProof: + return { + ...credentialStatus, + id: request.revocationOpts.issuerState + ? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${ + request.revocationOpts.issuerState + }` + : `${credentialStatus.id.replace(/\/$/, '')}` + }; + case CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: { + const issuerId = DID.idFromDID(issuer); + const chainId = getChainId(DID.blockchainFromId(issuerId), DID.networkIdFromId(issuerId)); + const searchParams = [ + ['revocationNonce', request.revocationOpts.nonce?.toString() || ''], + ['contractAddress', `${chainId}:${request.revocationOpts.id}`], + ['state', request.revocationOpts.issuerState || ''] + ] + .filter(([, value]) => Boolean(value)) + .map(([key, value]) => `${key}=${value}`) + .join('&'); + + return { + ...credentialStatus, + // `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)` + id: `${issuer.string()}/credentialStatus?${searchParams}` + }; + } + default: + return credentialStatus; + } + } + toJSON() { return { ...this, diff --git a/tests/adapter/onchain-issuer.test.ts b/tests/adapter/onchain-issuer.test.ts new file mode 100644 index 00000000..43b409a3 --- /dev/null +++ b/tests/adapter/onchain-issuer.test.ts @@ -0,0 +1,47 @@ +import { OnchainIssuer } from '../../src/storage/blockchain/onchain-issuer'; +import { RPC_URL, IPFS_URL } from '../helpers'; +import { DID } from '@iden3/js-iden3-core'; +import { W3CCredential } from '../../src/verifiable'; +import { expect } from 'chai'; +import { defaultEthConnectionConfig } from '../../src'; + +// prettier-ignore +const balanceCredentialHttpSchema = + {"id":"urn:iden3:onchain:80002:0x19875eA86503734f2f9Ed461463e0312A3b42563:6","@context":["https://www.w3.org/2018/credentials/v1","https://schema.iden3.io/core/jsonld/iden3proofs.jsonld","https://gist.githubusercontent.com/ilya-korotya/660496c859f8d31a7d2a92ca5e970967/raw/6b5fc14fe630c17bfa52e05e08fdc8394c5ea0ce/non-merklized-non-zero-balance.jsonld","https://schema.iden3.io/core/jsonld/displayMethod.jsonld"],"type":["VerifiableCredential","Balance"],"expirationDate":"2024-05-24T10:29:56.000Z","issuanceDate":"2024-04-24T10:29:56.000Z","credentialSubject":{"address":"955350806412517903000132372584919937355495621189","balance":"439010757238782730","id":"did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ","type":"Balance"},"credentialStatus":{"id":"did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ/credentialStatus?revocationNonce=6\u0026contractAddress=80002:0x19875eA86503734f2f9Ed461463e0312A3b42563","type":"Iden3OnchainSparseMerkleTreeProof2023","revocationNonce":6},"issuer":"did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ","credentialSchema":{"id":"https://gist.githubusercontent.com/ilya-korotya/e10cd79a8cc26ab6e40400a11838617e/raw/575edc33d485e2a4c806baad97e21117f3c90a9f/non-merklized-non-zero-balance.json","type":"JsonSchema2023"},"proof":[{"type":"Iden3SparseMerkleTreeProof","issuerData":{"id":"did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ","state":{"rootOfRoots":"4078a4330d42e9d112b61500e538dc229cce10e2ffc50861c26c115b263c3214","claimsTreeRoot":"b087bb8fe253f1b04f8357f0844796bbec597e4def7fd76a19814d8159dcbb05","revocationTreeRoot":"0000000000000000000000000000000000000000000000000000000000000000","value":"006143913300b027d1d70878468aa0530dfea5a042f8325a826d409df7911512"}},"coreClaim":"f52f1795c533d7b4aa4e7ab02485f86f0a00000000000000000000000000000002130000000000000019875ea86503734f2f9ed461463e0312a3b425635f070045c28dba443bdace6830060f2d2784fa696957a70000000000000000000000000afbca2df5ad17060000000000000000000000000000000000000000000000000600000000000000246c50660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","mtp":{"existence":true,"siblings":["13848368485573735212679136988282305230819438728637424764846468785502433652840","1096649694805431452149042575143897926182559273612207814941177729902834445226","12160962874465332870109484495496045222172553451373175361415786953298859195139","3819622883660148852432672044432820232715025265850740602622985339171079887367","14062102965326789511040283612678585475708167692394425899926219149423935791693","8688920842723779052034352461580251823545042582416894537724528294186594808930","19295275136572781615245322801038686629126714006877213606851647038393713692426"]}}],"displayMethod":{"id":"ipfs://QmS8eY8ZCiAAW8qgx3T6SQ3HDGeddwLZsjPXNAZExQwRY4","type":"Iden3BasicDisplayMethodV1"}}; +// prettier-ignore +const balanceCredentialIpfsSchema = + {"id":"urn:iden3:onchain:80002:0xFDb204CCC55794C861366dBc2Cd6BBBd25752894:0","@context":["https://www.w3.org/2018/credentials/v1","https://schema.iden3.io/core/jsonld/iden3proofs.jsonld","ipfs://Qma5B4jNwiHtRd5RXGoRncV79EZvB7LsfpHgv8Vi4xitV1","https://schema.iden3.io/core/jsonld/displayMethod.jsonld"],"type":["VerifiableCredential","Balance"],"expirationDate":"2024-05-24T16:23:56.000Z","issuanceDate":"2024-04-24T16:23:56.000Z","credentialSubject":{"address":"657065114158124047812701241180089030040156354062","balance":"34206141476401658683","id":"did:polygonid:polygon:amoy:2qZYiH9CFMoo6oTjSEot3qzkHFHhjLRLKp8yfwCYng","type":"Balance"},"credentialStatus":{"id":"did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB/credentialStatus?revocationNonce=0\u0026contractAddress=80002:0xFDb204CCC55794C861366dBc2Cd6BBBd25752894","type":"Iden3OnchainSparseMerkleTreeProof2023","revocationNonce":0},"issuer":"did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB","credentialSchema":{"id":"ipfs://QmcC7i1PCU8ymJscGjs8pqmZEWtBGWPFLmQ8s7P6QzELN6","type":"JsonSchema2023"},"proof":[{"type":"Iden3SparseMerkleTreeProof","issuerData":{"id":"did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB","state":{"rootOfRoots":"ae476a5ee415f804663e9449c285e49e5cf239d1d2b95e77bf84543974acc113","claimsTreeRoot":"87df6035bab67e067892307e74c55c7c1a324e4b69a9390ee734c20ccac1fb18","revocationTreeRoot":"0000000000000000000000000000000000000000000000000000000000000000","value":"32a269e965d1486d20749ef071e1a03713703487edee224a7768ee1394288f11"}},"coreClaim":"f52f1795c533d7b4aa4e7ab02485f86f0a0000000000000000000000000000000213d0591345a3d71ee61cd299b38959df8dea1f4a4f75a2bd4f25b8215f0d000eb6cb518d3dd33341899bcec9dcc68998d117730000000000000000000000003b3baddd70a0b4da01000000000000000000000000000000000000000000000000000000000000001cbf50660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","mtp":{"existence":true,"siblings":["0","11379033735565694648078358700935740809038384149401106458334374311488117433921"]}}],"displayMethod":{"id":"ipfs://QmS8eY8ZCiAAW8qgx3T6SQ3HDGeddwLZsjPXNAZExQwRY4","type":"Iden3BasicDisplayMethodV1"}}; + +describe('OnchainIssuer', () => { + const copyDefaultEthConnectionConfig = { ...defaultEthConnectionConfig }; + copyDefaultEthConnectionConfig.url = RPC_URL; + copyDefaultEthConnectionConfig.chainId = 80002; + + it('Test adapter for v0.0.1 HTTP schema', async () => { + const issuerDid = DID.parse( + 'did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ' + ); + const userDid = DID.parse( + 'did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ' + ); + const adapter = new OnchainIssuer([copyDefaultEthConnectionConfig]); + const cred = await adapter.getCredential(issuerDid, userDid, BigInt(6)); + expect(W3CCredential.fromJSON(balanceCredentialHttpSchema)).to.deep.equal(cred); + }); + + it('Test adapter for v0.0.1 IPFS schema', async () => { + const issuerDid = DID.parse( + 'did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB' + ); + const userId = DID.parse( + 'did:polygonid:polygon:amoy:2qZYiH9CFMoo6oTjSEot3qzkHFHhjLRLKp8yfwCYng' + ); + const adapter = new OnchainIssuer([copyDefaultEthConnectionConfig], { + merklizationOptions: { + ipfsNodeURL: IPFS_URL + } + }); + const cred = await adapter.getCredential(issuerDid, userId, BigInt(0)); + expect(W3CCredential.fromJSON(balanceCredentialIpfsSchema)).to.deep.equal(cred); + }); +}); diff --git a/tests/adapter/onchain-non-merklized-issuer-adapter.test.ts b/tests/adapter/onchain-non-merklized-issuer-adapter.test.ts new file mode 100644 index 00000000..8588c980 --- /dev/null +++ b/tests/adapter/onchain-non-merklized-issuer-adapter.test.ts @@ -0,0 +1,174 @@ +import { OnchainNonMerklizedIssuerAdapter } from '../../src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter'; +import { ethers } from 'ethers'; +import nock from 'nock'; +import { DID } from '@iden3/js-iden3-core'; +import { + NonMerklizedIssuerBaseABI as abi, + INonMerklizedIssuer +} from '@iden3/onchain-non-merklized-issuer-base-abi'; +import { expect } from 'chai'; +import { W3CCredential } from '../../src/verifiable'; +import { IPFS_URL } from '../helpers'; +import { defaultEthConnectionConfig } from '../../src'; + +// prettier-ignore +const w3cHttpSchemaExpect = + {"id":"urn:iden3:onchain:80001:0xc84e8ac5385E0813f01aA9C698ED44C831961670:0","@context":["https://www.w3.org/2018/credentials/v1","https://schema.iden3.io/core/jsonld/iden3proofs.jsonld","https://gist.githubusercontent.com/ilya-korotya/660496c859f8d31a7d2a92ca5e970967/raw/6b5fc14fe630c17bfa52e05e08fdc8394c5ea0ce/non-merklized-non-zero-balance.jsonld","https://schema.iden3.io/core/jsonld/displayMethod.jsonld"],"type":["VerifiableCredential","Balance"],"expirationDate":"2024-03-23T11:05:26.000Z","issuanceDate":"2024-02-22T11:05:26.000Z","credentialSubject":{"address":"657065114158124047812701241180089030040156354062","balance":"174130123440549329","id":"did:polygonid:polygon:mumbai:2qJFtKfABTJi2yUAcUhuvUnDojuNwUJjhuXQDhUg3e","type":"Balance"},"credentialStatus":{"id":"did:polygonid:polygon:mumbai:2qCU58EJgrEMJvPfhUCnFCwuKQTkX8VmJX2sJCH6C8/credentialStatus?revocationNonce=0\u0026contractAddress=80001:0xc84e8ac5385E0813f01aA9C698ED44C831961670","type":"Iden3OnchainSparseMerkleTreeProof2023","revocationNonce":0},"issuer":"did:polygonid:polygon:mumbai:2qCU58EJgrEMJvPfhUCnFCwuKQTkX8VmJX2sJCH6C8","credentialSchema":{"id":"https://gist.githubusercontent.com/ilya-korotya/e10cd79a8cc26ab6e40400a11838617e/raw/575edc33d485e2a4c806baad97e21117f3c90a9f/non-merklized-non-zero-balance.json","type":"JsonSchema2023"},"proof":[{"type":"Iden3SparseMerkleTreeProof","issuerData":{"id":"did:polygonid:polygon:mumbai:2qCU58EJgrEMJvPfhUCnFCwuKQTkX8VmJX2sJCH6C8","state":{"rootOfRoots":"19a633fecfa2117672bbcfb65307e3bd73101cd3dd49b849ea231b5927afc70e","claimsTreeRoot":"3ca701ead4d7da0eb5c4950ac0950a7ae92f4acc853a24698489f5a9b08fc72e","revocationTreeRoot":"0000000000000000000000000000000000000000000000000000000000000000","value":"6f5dd91f13004cca5c8b31524239de77ce149a9073d7ace737a1b7cffb96ab26"}},"coreClaim":"f52f1795c533d7b4aa4e7ab02485f86f0a00000000000000000000000000000002127f89ff6f78c9637e437575d1123c3862b93876abb197b010ea1dad600d000eb6cb518d3dd33341899bcec9dcc68998d11773000000000000000000000000d16d5eb86ca26a02000000000000000000000000000000000000000000000000000000000000000076b7fe650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","mtp":{"existence":true,"siblings":["4692761366944891051814480185546124875872606319832740381039122455881379612023"]}}],"displayMethod":{"id":"ipfs://QmS8eY8ZCiAAW8qgx3T6SQ3HDGeddwLZsjPXNAZExQwRY4","type":"Iden3BasicDisplayMethodV1"}}; +// prettier-ignore +const w3cIpfsSchemaExpect = + {"@context":["https://www.w3.org/2018/credentials/v1","https://schema.iden3.io/core/jsonld/iden3proofs.jsonld","ipfs://Qma5B4jNwiHtRd5RXGoRncV79EZvB7LsfpHgv8Vi4xitV1","https://schema.iden3.io/core/jsonld/displayMethod.jsonld"],"credentialSchema":{"id":"ipfs://QmcC7i1PCU8ymJscGjs8pqmZEWtBGWPFLmQ8s7P6QzELN6","type":"JsonSchema2023"},"credentialStatus":{"id":"did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB/credentialStatus?revocationNonce=0&contractAddress=80002:0xFDb204CCC55794C861366dBc2Cd6BBBd25752894","revocationNonce":0,"type":"Iden3OnchainSparseMerkleTreeProof2023"},"credentialSubject":{"address":"657065114158124047812701241180089030040156354062","balance":"34206141476401658683","id":"did:polygonid:polygon:amoy:2qZYiH9CFMoo6oTjSEot3qzkHFHhjLRLKp8yfwCYng","type":"Balance"},"displayMethod":{"id":"ipfs://QmS8eY8ZCiAAW8qgx3T6SQ3HDGeddwLZsjPXNAZExQwRY4","type":"Iden3BasicDisplayMethodV1"},"expirationDate":"2024-05-24T16:23:56.000Z","id":"urn:iden3:onchain:80002:0xFDb204CCC55794C861366dBc2Cd6BBBd25752894:0","issuanceDate":"2024-04-24T16:23:56.000Z","issuer":"did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB","proof":[{"coreClaim":"f52f1795c533d7b4aa4e7ab02485f86f0a0000000000000000000000000000000213d0591345a3d71ee61cd299b38959df8dea1f4a4f75a2bd4f25b8215f0d000eb6cb518d3dd33341899bcec9dcc68998d117730000000000000000000000003b3baddd70a0b4da01000000000000000000000000000000000000000000000000000000000000001cbf50660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","issuerData":{"id":"did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB","state":{"claimsTreeRoot":"3ca701ead4d7da0eb5c4950ac0950a7ae92f4acc853a24698489f5a9b08fc72e","revocationTreeRoot":"0000000000000000000000000000000000000000000000000000000000000000","rootOfRoots":"19a633fecfa2117672bbcfb65307e3bd73101cd3dd49b849ea231b5927afc70e","value":"6f5dd91f13004cca5c8b31524239de77ce149a9073d7ace737a1b7cffb96ab26"}},"mtp":{"existence":true,"siblings":["4692761366944891051814480185546124875872606319832740381039122455881379612023"]},"type":"Iden3SparseMerkleTreeProof"}],"type":["VerifiableCredential","Balance"]}; + +const mockedState = + '0x00000000000000000000000000000000000000000000000000000000000000a026ab96fbcfb7a137e7acd773909a14ce77de394252318b5cca4c00131fd95d6f2ec78fb0a9f5898469243a85cc4a2fe97a0a95c00a95c4b50edad7d4ea01a73c00000000000000000000000000000000000000000000000000000000000000000ec7af27591b23ea49b849ddd31c1073bde30753b6cfbb727611a2cffe33a6192ec78fb0a9f5898469243a85cc4a2fe97a0a95c00a95c4b50edad7d4ea01a73c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010015bbb043d40cadbd377aeb19ef410cd8adb55a41c63707a628fefa0fac2c3ba126280d1f3ca6d144c0fedf0519644786c96d821dcc947576ecbbb4a175279ab700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280a6002414282733c9a4a2b7ccf5ad7cd2d9eea2c6cf0c03d7dbac53da6a60577000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; + +describe('Convertor v0.0.1', () => { + it('Test adapter with https schema', async () => { + nock('http://localhost:8545') + .post('/', { + id: 1, + jsonrpc: '2.0', + method: 'eth_chainId', + params: [] + }) + .reply(200, { + jsonrpc: '2.0', + id: 1, + result: '0x1' + }); + + nock('http://localhost:8545') + .post('/', [ + { + method: 'eth_chainId', + params: [], + id: 1, + jsonrpc: '2.0' + }, + { + method: 'eth_call', + params: [ + { + to: '0xc84e8ac5385e0813f01aa9c698ed44c831961670', + data: '0xb37feda415bbb043d40cadbd377aeb19ef410cd8adb55a41c63707a628fefa0fac2c3ba1' + }, + 'latest' + ], + id: 2, + jsonrpc: '2.0' + } + ]) + .reply(200, [ + { + jsonrpc: '2.0', + id: 1, + result: '0x1' + }, + { + jsonrpc: '2.0', + id: 2, + result: mockedState + } + ]); + + const issuerDid = DID.parse( + 'did:polygonid:polygon:mumbai:2qCU58EJgrEMJvPfhUCnFCwuKQTkX8VmJX2sJCH6C8' + ); + const hexResponse = + '0x00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000a6ff88524b07a4eaab4d733c595172ff5000d60ad1dea10b097b1ab7638b962383c12d17575437e63c9786fff897f12020000000000000000000000007317d19889c6dcc9ce9b894133d33d8d51cbb60e000000000000000000000000000000000000000000000000026aa26cb85e6dd1000000000000000000000000000000000000000065feb77600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000065d72a7600000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a368747470733a2f2f676973742e67697468756275736572636f6e74656e742e636f6d2f696c79612d6b6f726f7479612f36363034393663383539663864333161376432613932636135653937303936372f7261772f366235666331346665363330633137626661353265303565303866646338333934633565613063652f6e6f6e2d6d65726b6c697a65642d6e6f6e2d7a65726f2d62616c616e63652e6a736f6e6c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003868747470733a2f2f736368656d612e6964656e332e696f2f636f72652f6a736f6e6c642f646973706c61794d6574686f642e6a736f6e6c640000000000000000000000000000000000000000000000000000000000000000000000000000000742616c616e6365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a168747470733a2f2f676973742e67697468756275736572636f6e74656e742e636f6d2f696c79612d6b6f726f7479612f65313063643739613863633236616236653430343030613131383338363137652f7261772f353735656463333364343835653261346338303662616164393765323131313766336339306139662f6e6f6e2d6d65726b6c697a65642d6e6f6e2d7a65726f2d62616c616e63652e6a736f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a736f6e536368656d6132303233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d53386559385a436941415738716778335436535133484447656464774c5a736a50584e415a45785177525934000000000000000000000000000000000000000000000000000000000000000000000000000000000000194964656e334261736963446973706c61794d6574686f645631000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000026aa26cb85e6dd100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000762616c616e636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000007317d19889c6dcc9ce9b894133d33d8d51cbb60e00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000761646472657373000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; + + const iface = new ethers.Interface(abi); + const res = iface.decodeFunctionResult('getCredential', hexResponse); + + const adapter = new OnchainNonMerklizedIssuerAdapter( + { + ...defaultEthConnectionConfig, + url: 'http://localhost:8545', + chainId: 80001 + }, + issuerDid + ); + const w3cCredential = await adapter.convertOnChainInfoToW3CCredential( + res[0] as INonMerklizedIssuer.CredentialDataStructOutput, + res[1] as bigint[], + res[2] as INonMerklizedIssuer.SubjectFieldStructOutput[] + ); + expect(W3CCredential.fromJSON(w3cHttpSchemaExpect)).to.deep.equal(w3cCredential); + }); + it('Test adapter with ipfs schema', async () => { + nock('http://localhost:8545') + .post('/', { + id: 1, + jsonrpc: '2.0', + method: 'eth_chainId', + params: [] + }) + .reply(200, { + jsonrpc: '2.0', + id: 1, + result: '0x1' + }); + + nock('http://localhost:8545') + .post('/', [ + { + method: 'eth_chainId', + params: [], + id: 1, + jsonrpc: '2.0' + }, + { + method: 'eth_call', + params: [ + { + to: '0xfdb204ccc55794c861366dbc2cd6bbbd25752894', + data: '0xb37feda41cc706418245dd0f41d3eadc04b1a03c35e8885bac81a23749e7c756c9568c18' + }, + 'latest' + ], + id: 2, + jsonrpc: '2.0' + } + ]) + .reply(200, [ + { + jsonrpc: '2.0', + id: 1, + result: '0x1' + }, + { + jsonrpc: '2.0', + id: 2, + result: mockedState + } + ]); + + const issuerDid = DID.parse( + 'did:polygonid:polygon:amoy:2qQ68JkRcf3z3923i5rrszrsJ4kdu4GKWARQ5eftsB' + ); + const hexResponse = + '0x00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000a6ff88524b07a4eaab4d733c595172ff5000d5f21b8254fbda2754f4a1fea8ddf5989b399d21ce61ed7a3451359d013020000000000000000000000007317d19889c6dcc9ce9b894133d33d8d51cbb60e000000000000000000000000000000000000000000000001dab4a070ddad3b3b00000000000000000000000000000000000000006650bf1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000006629321c000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d613542346a4e776948745264355258476f526e63563739455a7642374c7366704867763856693478697456310000000000000000000000000000000000000000000000000000000000000000000000000000000000003868747470733a2f2f736368656d612e6964656e332e696f2f636f72652f6a736f6e6c642f646973706c61794d6574686f642e6a736f6e6c640000000000000000000000000000000000000000000000000000000000000000000000000000000742616c616e636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d634337693150435538796d4a7363476a733870716d5a45577442475750464c6d513873375036517a454c4e360000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a736f6e536368656d6132303233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d53386559385a436941415738716778335436535133484447656464774c5a736a50584e415a45785177525934000000000000000000000000000000000000000000000000000000000000000000000000000000000000194964656e334261736963446973706c61794d6574686f645631000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000001dab4a070ddad3b3b00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000762616c616e636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000007317d19889c6dcc9ce9b894133d33d8d51cbb60e00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000761646472657373000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; + + const iface = new ethers.Interface(abi); + const res = iface.decodeFunctionResult('getCredential', hexResponse); + + const adapter = new OnchainNonMerklizedIssuerAdapter( + { + ...defaultEthConnectionConfig, + url: 'http://localhost:8545', + chainId: 80002 + }, + issuerDid, + { + merklizationOptions: { + ipfsNodeURL: IPFS_URL + } + } + ); + const w3cCredential = await adapter.convertOnChainInfoToW3CCredential( + res[0] as INonMerklizedIssuer.CredentialDataStructOutput, + res[1] as bigint[], + res[2] as INonMerklizedIssuer.SubjectFieldStructOutput[] + ); + expect(W3CCredential.fromJSON(w3cIpfsSchemaExpect)).to.deep.eq(w3cCredential); + }); +}); diff --git a/tests/handlers/fetch.test.ts b/tests/handlers/fetch.test.ts index 5470539b..d1abef10 100644 --- a/tests/handlers/fetch.test.ts +++ b/tests/handlers/fetch.test.ts @@ -1,5 +1,6 @@ import { CredentialsOfferMessage, + CredentialsOnchainOfferMessage, FetchHandler, IPackageManager, IDataStorage, @@ -23,6 +24,7 @@ import { import { MOCK_STATE_STORAGE, RHS_URL, + RPC_URL, SEED_ISSUER, SEED_USER, createIdentity, @@ -31,6 +33,9 @@ import { registerKeyProvidersInMemoryKMS } from '../helpers'; +import { OnchainIssuer } from '../../src/storage/blockchain/onchain-issuer'; +import { defaultEthConnectionConfig } from '../../src'; + import * as uuid from 'uuid'; import { expect } from 'chai'; import path from 'path'; @@ -137,7 +142,14 @@ describe('fetch', () => { proofService.verifyState.bind(proofService) ); fetchHandler = new FetchHandler(packageMgr, { - credentialWallet: credWallet + credentialWallet: credWallet, + onchainIssuer: new OnchainIssuer([ + { + ...defaultEthConnectionConfig, + url: RPC_URL, + chainId: 80002 + } + ]) }); msgHandler = new MessageHandler({ @@ -287,4 +299,35 @@ describe('fetch', () => { expect(response).to.be.null; expect(await credWallet.list()).to.have.length(5); }); + + it('onchain credential offer', async () => { + const { did: userDID } = await createIdentity(idWallet, { + seed: SEED_ISSUER + }); + + const onchainOffer: CredentialsOnchainOfferMessage = { + id: uuid.v4(), + typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage, + type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE, + thid: uuid.v4(), + body: { + credentials: [{ id: '6', description: 'balance credential' }], + transaction_data: { + contract_address: '0x19875eA86503734f2f9Ed461463e0312A3b42563', + method_id: '0', + chain_id: 80002 + } + }, + from: 'did:polygonid:polygon:amoy:2qQ68JkRcf3xyDFsGSWU5QqxbKpzM75quxS628JgvJ', + to: userDID.string() + }; + + const bytes = await packageMgr.packMessage( + PROTOCOL_CONSTANTS.MediaType.PlainMessage, + onchainOffer, + {} + ); + const response = await fetchHandler.handleOnchainOffer(bytes); + console.log(response); + }); });