From 7cc1891ffebceb4eebf1421d3bc348926efa3f10 Mon Sep 17 00:00:00 2001 From: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:46:03 +0800 Subject: [PATCH 01/14] chore: back merge (#75) * fix: add w3c credential status check (#72) * fix: add w3c credential status check * fix: update test * fix: update enum status codes * fix: remove console * chore(release): 1.5.4 [skip ci] ## [1.5.4](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.5.4) (2025-06-17) ### Bug Fixes * add w3c credential status check ([#72](https://github.com/TrustVC/trustvc/issues/72)) ([0111cb3](https://github.com/TrustVC/trustvc/commit/0111cb3e48ac86f0cea715ceb5277d199f139763)) * fix: upgrade package (#73) * chore(release): 1.5.5 [skip ci] ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) ### Bug Fixes * upgrade package ([#73](https://github.com/TrustVC/trustvc/issues/73)) ([3c6c9c7](https://github.com/TrustVC/trustvc/commit/3c6c9c73675ec43e0514d9afe5df4444f6e4400b)) --------- Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Co-authored-by: semantic-release-bot --- CHANGELOG.md | 14 + package-lock.json | 317 +++++------------- package.json | 12 +- src/__tests__/core/verify.test.ts | 16 +- src/utils/fragment/index.ts | 55 ++- .../document-status/w3cCredentialStatus.ts | 41 ++- 6 files changed, 199 insertions(+), 256 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b19e8de..1ef622b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) + + +### Bug Fixes + +* upgrade package ([#73](https://github.com/TrustVC/trustvc/issues/73)) ([3c6c9c7](https://github.com/TrustVC/trustvc/commit/3c6c9c73675ec43e0514d9afe5df4444f6e4400b)) + +## [1.5.4](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.5.4) (2025-06-17) + + +### Bug Fixes + +* add w3c credential status check ([#72](https://github.com/TrustVC/trustvc/issues/72)) ([0111cb3](https://github.com/TrustVC/trustvc/commit/0111cb3e48ac86f0cea715ceb5277d199f139763)) + ## [1.5.3](https://github.com/TrustVC/trustvc/compare/v1.5.2...v1.5.3) (2025-06-13) diff --git a/package-lock.json b/package-lock.json index b680742..b78e0e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,27 +1,27 @@ { "name": "@trustvc/trustvc", - "version": "1.5.3", + "version": "1.5.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.5.3", + "version": "1.5.5", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", - "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.3", + "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.4", "@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0", "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.3.0", "@tradetrust-tt/tradetrust": "^6.10.1", - "@tradetrust-tt/tradetrust-utils": "^2.3.1", + "@tradetrust-tt/tradetrust-utils": "^2.3.2", "@tradetrust-tt/tt-verify": "^9.4.0", "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-credential-status": "^1.2.12", - "@trustvc/w3c-issuer": "^1.2.3", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", "@trustvc/w3c-vc": "^1.2.17", "ethers": "^5.8.0", - "ethersV6": "npm:ethers@^6.14.3", + "ethersV6": "npm:ethers@^6.14.4", "js-sha3": "^0.9.3", "ts-chacha20": "^1.2.0" }, @@ -214,24 +214,24 @@ } }, "node_modules/@aws-sdk/client-kms": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.826.0.tgz", - "integrity": "sha512-97UFikkyIbeul0USWmn5TE+L41uufkhPt8ASHX6wFrkQ7iWvSXO1JJym0jNJeg5TWBVYUUZARZSl8/a+QiG7Lg==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.830.0.tgz", + "integrity": "sha512-y24IvqKn21nF13tkhsKMCKcz0/z6UEePvpV5JAWwZSUmNJj2spagucD/ksykNqBPalbNZIuTicUqtHyBtYAWYQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.826.0", - "@aws-sdk/credential-provider-node": "3.826.0", + "@aws-sdk/credential-provider-node": "3.830.0", "@aws-sdk/middleware-host-header": "3.821.0", "@aws-sdk/middleware-logger": "3.821.0", "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.826.0", + "@aws-sdk/middleware-user-agent": "3.828.0", "@aws-sdk/region-config-resolver": "3.821.0", "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.826.0", + "@aws-sdk/util-user-agent-node": "3.828.0", "@smithy/config-resolver": "^4.1.4", "@smithy/core": "^3.5.3", "@smithy/fetch-http-handler": "^5.0.4", @@ -264,9 +264,9 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.826.0.tgz", - "integrity": "sha512-/FEKnUC3xPkLL4RuRydwzx+y4b55HIX6qLPbGnyIs+sNmCUyc/62ijtV1Ml+b++YzEF6jWNBsJOxeyZdgrJ3Ig==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.830.0.tgz", + "integrity": "sha512-5zCEpfI+zwX2SIa258L+TItNbBoAvQQ6w74qdFM6YJufQ1F9tvwjTX8T+eSTT9nsFIvfYnUaGalWwJVfmJUgVQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -275,12 +275,12 @@ "@aws-sdk/middleware-host-header": "3.821.0", "@aws-sdk/middleware-logger": "3.821.0", "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.826.0", + "@aws-sdk/middleware-user-agent": "3.828.0", "@aws-sdk/region-config-resolver": "3.821.0", "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.826.0", + "@aws-sdk/util-user-agent-node": "3.828.0", "@smithy/config-resolver": "^4.1.4", "@smithy/core": "^3.5.3", "@smithy/fetch-http-handler": "^5.0.4", @@ -376,18 +376,18 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.826.0.tgz", - "integrity": "sha512-g7n+qSklq/Lzjxe2Ke5QFNCgYn26a3ydZnbFIk8QqYin4pzG+qiunaqJjpV3c/EeHMlfK8bBc7MXAylKzGRccQ==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.830.0.tgz", + "integrity": "sha512-zeQenzvh8JRY5nULd8izdjVGoCM1tgsVVsrLSwDkHxZTTW0hW/bmOmXfvdaE0wDdomXW7m2CkQDSmP7XdvNXZg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.826.0", "@aws-sdk/credential-provider-env": "3.826.0", "@aws-sdk/credential-provider-http": "3.826.0", "@aws-sdk/credential-provider-process": "3.826.0", - "@aws-sdk/credential-provider-sso": "3.826.0", - "@aws-sdk/credential-provider-web-identity": "3.826.0", - "@aws-sdk/nested-clients": "3.826.0", + "@aws-sdk/credential-provider-sso": "3.830.0", + "@aws-sdk/credential-provider-web-identity": "3.830.0", + "@aws-sdk/nested-clients": "3.830.0", "@aws-sdk/types": "3.821.0", "@smithy/credential-provider-imds": "^4.0.6", "@smithy/property-provider": "^4.0.4", @@ -400,17 +400,17 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.826.0.tgz", - "integrity": "sha512-UfIJXxHjmSxH6bea00HBPLkjNI2D04enQA/xNLZvB+4xtzt1/gYdCis1P4/73f5aGVVVB4/zQMobBbnjkrmbQw==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.830.0.tgz", + "integrity": "sha512-X/2LrTgwtK1pkWrvofxQBI8VTi6QVLtSMpsKKPPnJQ0vgqC0e4czSIs3ZxiEsOkCBaQ2usXSiKyh0ccsQ6k2OA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "3.826.0", "@aws-sdk/credential-provider-http": "3.826.0", - "@aws-sdk/credential-provider-ini": "3.826.0", + "@aws-sdk/credential-provider-ini": "3.830.0", "@aws-sdk/credential-provider-process": "3.826.0", - "@aws-sdk/credential-provider-sso": "3.826.0", - "@aws-sdk/credential-provider-web-identity": "3.826.0", + "@aws-sdk/credential-provider-sso": "3.830.0", + "@aws-sdk/credential-provider-web-identity": "3.830.0", "@aws-sdk/types": "3.821.0", "@smithy/credential-provider-imds": "^4.0.6", "@smithy/property-provider": "^4.0.4", @@ -440,14 +440,14 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.826.0.tgz", - "integrity": "sha512-F19J3zcfoom6OnQ0MyAtvduVKQXPgkz9i5ExSO01J2CzjbyMhCDA99qAjHYe+LwhW+W7P/jzBPd0+uOQ2Nhh9Q==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.830.0.tgz", + "integrity": "sha512-+VdRpZmfekzpySqZikAKx6l5ndnLGluioIgUG4ZznrButgFD/iogzFtGmBDFB3ZLViX1l4pMXru0zFwJEZT21Q==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.826.0", + "@aws-sdk/client-sso": "3.830.0", "@aws-sdk/core": "3.826.0", - "@aws-sdk/token-providers": "3.826.0", + "@aws-sdk/token-providers": "3.830.0", "@aws-sdk/types": "3.821.0", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -459,13 +459,13 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.826.0.tgz", - "integrity": "sha512-o27GZ6Hy7qhuvMFVUL2eFEpBzf33Jaa/x3u3SHwU0nL7ko7jmbpeF0x4+wmagpI9X2IvVlUxIs0VaQ3YayPLEA==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.830.0.tgz", + "integrity": "sha512-hPYrKsZeeOdLROJ59T6Y8yZ0iwC/60L3qhZXjapBFjbqBtMaQiMTI645K6xVXBioA6vxXq7B4aLOhYqk6Fy/Ww==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.826.0", - "@aws-sdk/nested-clients": "3.826.0", + "@aws-sdk/nested-clients": "3.830.0", "@aws-sdk/types": "3.821.0", "@smithy/property-provider": "^4.0.4", "@smithy/types": "^4.3.1", @@ -520,14 +520,14 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.826.0.tgz", - "integrity": "sha512-j404+EcfBbtTlAhyObjXbdKwwDXO1pCxHvR5Fw8FXNvp/H330j6YnXgs3SJ6d3bZUwUJ/ztPx2S5AlBbLVLDFw==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.828.0.tgz", + "integrity": "sha512-nixvI/SETXRdmrVab4D9LvXT3lrXkwAWGWk2GVvQvzlqN1/M/RfClj+o37Sn4FqRkGH9o9g7Fqb1YqZ4mqDAtA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.826.0", "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", "@smithy/core": "^3.5.3", "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", @@ -538,9 +538,9 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.826.0.tgz", - "integrity": "sha512-p7olPq0uTtHqGuXI1GSc/gzKDvV55PMbLtnmupEDfnY9SoRu+QatbWQ6da9sI1lhOcNmRMgiNQBXFzaUFrG+SQ==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.830.0.tgz", + "integrity": "sha512-5N5YTlBr1vtxf7+t+UaIQ625KEAmm7fY9o1e3MgGOi/paBoI0+axr3ud24qLIy0NSzFlAHEaxUSWxcERNjIoZw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -549,12 +549,12 @@ "@aws-sdk/middleware-host-header": "3.821.0", "@aws-sdk/middleware-logger": "3.821.0", "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.826.0", + "@aws-sdk/middleware-user-agent": "3.828.0", "@aws-sdk/region-config-resolver": "3.821.0", "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.826.0", + "@aws-sdk/util-user-agent-node": "3.828.0", "@smithy/config-resolver": "^4.1.4", "@smithy/core": "^3.5.3", "@smithy/fetch-http-handler": "^5.0.4", @@ -604,13 +604,13 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.826.0.tgz", - "integrity": "sha512-iCOcVAqGPSHtQL8ZBXifZMEcHyUl9wJ8HvLZ5l1ohA/3ZNP+dqEPGi7jfhR5jZKs+xyp2jxByFqfil9PjI9c5A==", + "version": "3.830.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.830.0.tgz", + "integrity": "sha512-aJ4guFwj92nV9D+EgJPaCFKK0I3y2uMchiDfh69Zqnmwfxxxfxat6F79VA7PS0BdbjRfhLbn+Ghjftnomu2c1g==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.826.0", - "@aws-sdk/nested-clients": "3.826.0", + "@aws-sdk/nested-clients": "3.830.0", "@aws-sdk/types": "3.821.0", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -635,9 +635,9 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.821.0.tgz", - "integrity": "sha512-Uknt/zUZnLE76zaAAPEayOeF5/4IZ2puTFXvcSCWHsi9m3tqbb9UozlnlVqvCZLCRWfQryZQoG2W4XSS3qgk5A==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.828.0.tgz", + "integrity": "sha512-RvKch111SblqdkPzg3oCIdlGxlQs+k+P7Etory9FmxPHyPDvsP1j1c74PmgYqtzzMWmoXTjd+c9naUHh9xG8xg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.821.0", @@ -674,12 +674,12 @@ } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.826.0.tgz", - "integrity": "sha512-wHw6bZQWIMcFF/8r03aY9Itp6JLBYY4absGGhCDK1dc3tPEfi8NVSdb05a/Oz+g4TVaDdxLo0OQ/OKMS1DFRHQ==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.828.0.tgz", + "integrity": "sha512-LdN6fTBzTlQmc8O8f1wiZN0qF3yBWVGis7NwpWK7FUEzP9bEZRxYfIkV9oV9zpt6iNRze1SedK3JQVB/udxBoA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.826.0", + "@aws-sdk/middleware-user-agent": "3.828.0", "@aws-sdk/types": "3.821.0", "@smithy/node-config-provider": "^4.1.3", "@smithy/types": "^4.3.1", @@ -5105,12 +5105,12 @@ } }, "node_modules/@tradetrust-tt/ethers-aws-kms-signer": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/ethers-aws-kms-signer/-/ethers-aws-kms-signer-2.1.3.tgz", - "integrity": "sha512-CdF4jFHDFZPVDBhJMP2wU7nywtM6xmBDfgaWdjmwW/0dQbEZ1AJ6UzJKsrFYEtNybUDFtsDcyxtuja84AQzqqQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/ethers-aws-kms-signer/-/ethers-aws-kms-signer-2.1.4.tgz", + "integrity": "sha512-bwsPF9TOlkXUICwUIt3FJCBQZ8zJTbT3AlPdj+7dGEgPTY6sAH71BzFYFQ1aJnZht1Sww6y8ix14FK4M54lRsQ==", "license": "MIT", "dependencies": { - "@aws-sdk/client-kms": "^3.826.0", + "@aws-sdk/client-kms": "^3.830.0", "@ethersproject/abstract-provider": "^5.8.0", "@ethersproject/abstract-signer": "^5.8.0", "@ethersproject/bytes": "^5.8.0", @@ -5118,9 +5118,8 @@ "@ethersproject/keccak256": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/transactions": "^5.8.0", - "@types/node": "^18.19.111", + "@types/node": "^18.19.112", "asn1.js": "^5.4.1", - "aws-sdk": "^2.1692.0", "bn.js": "^5.2.2", "debug": "^4.4.1" }, @@ -5188,9 +5187,9 @@ } }, "node_modules/@tradetrust-tt/tradetrust-utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.3.1.tgz", - "integrity": "sha512-ts0nyqEN62qpUXXSZ59nYBqajcKzMYKOi5cBpwlTYbOS4cRi6PcVZmM273xLmf2XLwNb8BA6agLpAx3ll5IWZw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.3.2.tgz", + "integrity": "sha512-T3rikZ3v0qqB3xzmq+KM30OEziyesHgN0CRQrhEvLlQw5IULtmcuwLZGHLE8KyaI8Zd7mqbuubJlfyEMNXJZuA==", "dependencies": { "@tradetrust-tt/tt-verify": "^9.4.0", "dotenv": "^16.4.5", @@ -5398,9 +5397,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.111", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.111.tgz", - "integrity": "sha512-90sGdgA+QLJr1F9X79tQuEut0gEYIfkX9pydI4XGRgvFo9g2JWswefI+WUSUHPYVBHYSEfTEqBxA5hQvAZB3Mw==", + "version": "18.19.112", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.112.tgz", + "integrity": "sha512-i+Vukt9POdS/MBI7YrrkkI5fMfwFtOjphSmt4WXYLfwqsfr6z/HdCx7LqT9M7JktGob8WNgj8nFB4TbGNE4Cog==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -6211,69 +6210,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sdk": { - "version": "2.1692.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", - "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-sdk/node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/aws-sdk/node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "license": "BSD-3-Clause" - }, - "node_modules/aws-sdk/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/aws-sdk/node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -6314,6 +6250,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, "funding": [ { "type": "github", @@ -8998,9 +8935,9 @@ }, "node_modules/ethersV6": { "name": "ethers", - "version": "6.14.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.14.3.tgz", - "integrity": "sha512-qq7ft/oCJohoTcsNPFaXSQUm457MA5iWqkf1Mb11ujONdg7jBI6sAOrHaTi3j0CBqIGFSCeR/RMc+qwRRub7IA==", + "version": "6.14.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.14.4.tgz", + "integrity": "sha512-Jm/dzRs2Z9iBrT6e9TvGxyb5YVKAPLlpna7hjxH7KH/++DSh2T/JVmQUv7iHI5E55hDbp/gEVvstWYXVxXFzsA==", "funding": [ { "type": "individual", @@ -9121,15 +9058,6 @@ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "license": "MIT", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/execa": { "version": "9.5.2", "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", @@ -10502,22 +10430,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -11120,15 +11032,6 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, - "node_modules/jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", - "license": "Apache-2.0", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", @@ -16996,12 +16899,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", - "license": "ISC" - }, "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", @@ -19143,50 +19040,12 @@ "punycode": "^2.1.0" } }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "license": "MIT", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", - "license": "MIT" - }, - "node_modules/url/node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -20262,28 +20121,6 @@ } } }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 29b336a..cc57a0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.5.3", + "version": "1.5.5", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -111,18 +111,18 @@ }, "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", - "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.3", + "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.4", "@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0", "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.3.0", "@tradetrust-tt/tradetrust": "^6.10.1", - "@tradetrust-tt/tradetrust-utils": "^2.3.1", + "@tradetrust-tt/tradetrust-utils": "^2.3.2", "@tradetrust-tt/tt-verify": "^9.4.0", "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-credential-status": "^1.2.12", - "@trustvc/w3c-issuer": "^1.2.3", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", "@trustvc/w3c-vc": "^1.2.17", "ethers": "^5.8.0", - "ethersV6": "npm:ethers@^6.14.3", + "ethersV6": "npm:ethers@^6.14.4", "js-sha3": "^0.9.3", "ts-chacha20": "^1.2.0" }, diff --git a/src/__tests__/core/verify.test.ts b/src/__tests__/core/verify.test.ts index 88cda4c..6fb349b 100644 --- a/src/__tests__/core/verify.test.ts +++ b/src/__tests__/core/verify.test.ts @@ -8,6 +8,7 @@ import { WRAPPED_DOCUMENT_DID_TOKEN_REGISTRY_V3, WRAPPED_DOCUMENT_DNS_TXT_V2, } from '../fixtures/fixtures'; +import { W3CCredentialStatusCode } from 'src/verify/fragments/document-status/w3cCredentialStatus'; const providerUrl = 'https://rpc-amoy.polygon.technology'; @@ -98,7 +99,7 @@ describe.concurrent('W3C verify', () => { expect.objectContaining({ name: 'W3CSignatureIntegrity', reason: { - code: 0, + code: W3CCredentialStatusCode.SKIPPED, codeString: 'SKIPPED', message: "Document either has no proof or proof.type is not 'BbsBlsSignature2020'.", }, @@ -120,7 +121,7 @@ describe.concurrent('W3C verify', () => { expect.objectContaining({ name: 'W3CIssuerIdentity', reason: { - code: 0, + code: W3CCredentialStatusCode.SKIPPED, codeString: 'SKIPPED', message: 'Document has no issuer field.', }, @@ -188,7 +189,7 @@ describe.concurrent('W3C verify', () => { expect.objectContaining({ name: 'W3CCredentialStatus', reason: { - code: 0, + code: W3CCredentialStatusCode.SKIPPED, codeString: 'SKIPPED', message: 'Document does not have a valid credentialStatus or type.', }, @@ -237,12 +238,13 @@ describe.concurrent('W3C verify', () => { statusListIndex: '131072', }, }; - expect(await verifyDocument(tampered)).toEqual( expect.arrayContaining([ expect.objectContaining({ name: 'W3CCredentialStatus', reason: { + code: W3CCredentialStatusCode.UNEXPECTED_ERROR, + codeString: 'ERROR', message: 'Invalid statusListIndex: Index out of range: min=0, max=131071', }, status: 'ERROR', @@ -328,7 +330,7 @@ describe.concurrent('W3C verify', () => { expect.objectContaining({ name: 'TransferableRecords', reason: { - code: 9, + code: W3CCredentialStatusCode.UNRECOGNIZED_DOCUMENT, codeString: 'UNRECOGNIZED_DOCUMENT', message: "Document's credentialStatus does not have tokenRegistry", }, @@ -358,7 +360,7 @@ describe.concurrent('W3C verify', () => { expect.objectContaining({ name: 'TransferableRecords', reason: { - code: 9, + code: W3CCredentialStatusCode.UNRECOGNIZED_DOCUMENT, codeString: 'UNRECOGNIZED_DOCUMENT', message: "Document's credentialStatus does not have tokenNetwork.chainId", }, @@ -384,7 +386,7 @@ describe.concurrent('W3C verify', () => { expect.objectContaining({ name: 'TransferableRecords', reason: { - code: 1, + code: W3CCredentialStatusCode.DOCUMENT_NOT_ISSUED, codeString: 'DOCUMENT_NOT_MINTED', message: 'Document has not been issued under token registry', }, diff --git a/src/utils/fragment/index.ts b/src/utils/fragment/index.ts index ed30ae7..0d972bb 100644 --- a/src/utils/fragment/index.ts +++ b/src/utils/fragment/index.ts @@ -1 +1,54 @@ -export { errorMessageHandling, interpretFragments } from '@tradetrust-tt/tradetrust-utils'; +import { + errorMessageHandling as OAErrorMessageHandling, + CONSTANTS, + interpretFragments, +} from '@tradetrust-tt/tradetrust-utils'; +import { InvalidVerificationFragment, utils, VerificationFragment } from '@tradetrust-tt/tt-verify'; +import { W3CCredentialStatusCode } from '../../verify/fragments/document-status/w3cCredentialStatus'; +import { CredentialStatusResult } from '@trustvc/w3c-vc'; + +const getW3CCredentialStatusFragment = + utils.getFragmentByName>( + 'W3CCredentialStatus', + ); + +const w3cCredentialStatusRevoked = (fragments: VerificationFragment[]): boolean => { + const issuedFragment = getW3CCredentialStatusFragment(fragments); + return ( + issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_REVOKED || + issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_REVOKED_AND_SUSPENDED + ); +}; + +const w3cCredentialStatusSuspended = (fragments: VerificationFragment[]): boolean => { + const issuedFragment = getW3CCredentialStatusFragment(fragments); + //checking for both revoked and suspended + return ( + issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_SUSPENDED || + issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_REVOKED_AND_SUSPENDED + ); +}; + +const errorMessageHandling = (fragments: VerificationFragment[]): string[] => { + const errors = []; + const isW3cFragments = fragments.some( + (f) => f.name.startsWith('W3C') || f.name === 'TransferableRecords', + ); + if (isW3cFragments) { + if (w3cCredentialStatusRevoked(fragments)) { + errors.push(CONSTANTS.TYPES.REVOKED); + } + if (w3cCredentialStatusSuspended(fragments)) { + errors.push(CONSTANTS.TYPES.SUSPENDED); + } + + return errors; + } else return OAErrorMessageHandling(fragments); +}; + +export { + interpretFragments, + errorMessageHandling, + w3cCredentialStatusRevoked, + w3cCredentialStatusSuspended, +}; diff --git a/src/verify/fragments/document-status/w3cCredentialStatus.ts b/src/verify/fragments/document-status/w3cCredentialStatus.ts index 7fc72eb..69eace2 100644 --- a/src/verify/fragments/document-status/w3cCredentialStatus.ts +++ b/src/verify/fragments/document-status/w3cCredentialStatus.ts @@ -5,14 +5,28 @@ import { } from '@trustvc/w3c-credential-status'; import { CredentialStatus, isSignedDocument, verifyCredentialStatus } from '@trustvc/w3c-vc'; import { SignedVerifiableCredential } from '../../..'; - +//w3cCredentialStatus enums +export enum W3CCredentialStatusCode { + SKIPPED = 0, + DOCUMENT_NOT_ISSUED = 1, + DOCUMENT_REVOKED = 11, + DOCUMENT_SUSPENDED = 12, + DOCUMENT_REVOKED_AND_SUSPENDED = 101, + STATUS_LIST_NOT_FOUND = 404, + INVALID_VALIDATION_METHOD = 8, + UNRECOGNIZED_DOCUMENT = 9, + SERVER_ERROR = 500, + UNEXPECTED_ERROR = 4, + INVALID_ARGUMENT = 6, + INVALID_ISSUERS = 7, +} export const w3cCredentialStatus: Verifier = { skip: async () => { return { type: 'DOCUMENT_STATUS', name: 'W3CCredentialStatus', reason: { - code: 0, + code: W3CCredentialStatusCode.SKIPPED, codeString: 'SKIPPED', message: `Document does not have a valid credentialStatus or type.`, }, @@ -47,12 +61,18 @@ export const w3cCredentialStatus: Verifier = { verifyCredentialStatus(cs, cs?.type as CredentialStatusType, verifierOptions), ), ); + const purposes = verificationResult.map((item) => item.purpose); + const hasRevocation = purposes.includes('revocation'); + const hasSuspension = purposes.includes('suspension'); + const hasRevocationAndSuspension = hasRevocation && hasSuspension; if (verificationResult.some((r) => r.error)) { return { type: 'DOCUMENT_STATUS', name: 'W3CCredentialStatus', reason: { + code: W3CCredentialStatusCode.UNEXPECTED_ERROR, + codeString: 'ERROR', message: verificationResult.map((r) => r.error).join(', '), }, data: verificationResult, @@ -71,6 +91,23 @@ export const w3cCredentialStatus: Verifier = { name: 'W3CCredentialStatus', data: verificationResult, status: 'INVALID', + reason: { + code: hasRevocationAndSuspension + ? W3CCredentialStatusCode.DOCUMENT_REVOKED_AND_SUSPENDED + : hasRevocation + ? W3CCredentialStatusCode.DOCUMENT_REVOKED + : W3CCredentialStatusCode.DOCUMENT_SUSPENDED, + codeString: hasRevocationAndSuspension + ? 'REVOKED_AND_SUSPENDED' + : hasRevocation + ? 'REVOKED' + : 'SUSPENDED', + message: hasRevocationAndSuspension + ? 'Document has been revoked and suspended.' + : hasRevocation + ? 'Document has been revoked.' + : 'Document has been suspended.', + }, }; } }, From 5690fcda798192609b0060fab0a3f3f77dca8012 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Mon, 30 Jun 2025 10:30:19 +0530 Subject: [PATCH 02/14] feat: token registry functions (#74) --- package-lock.json | 75 ++ .../transfers.test.ts | 874 ++++++++++++++++++ src/index.ts | 2 +- src/token-registry-functions/index.ts | 1 + src/token-registry-functions/transfer.ts | 536 +++++++++++ 5 files changed, 1487 insertions(+), 1 deletion(-) create mode 100644 src/__tests__/token-registry-functions/transfers.test.ts create mode 100644 src/token-registry-functions/index.ts create mode 100644 src/token-registry-functions/transfer.ts diff --git a/package-lock.json b/package-lock.json index b78e0e4..dacc2c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,6 +70,81 @@ "ethers": "^5.8.0" } }, + "../token-registry": { + "name": "@tradetrust-tt/token-registry", + "version": "4.0.0", + "extraneous": true, + "license": "Apache-2.0", + "dependencies": { + "@typechain/ethers-v5": "10.2.1" + }, + "devDependencies": { + "@babel/cli": "^7.13.16", + "@babel/core": "^7.14.6", + "@babel/eslint-parser": "^7.18.9", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/preset-env": "^7.14.0", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "@commitlint/cli": "^12.1.1", + "@commitlint/config-conventional": "^12.1.1", + "@commitlint/prompt": "^12.1.1", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.6.2", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.2", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomicfoundation/hardhat-verify": "^2.0.8", + "@nomiclabs/hardhat-ethers": "^2.0.2", + "@openzeppelin/contracts": "^4.5.0", + "@openzeppelin/contracts-upgradeable": "^4.5.2", + "@typechain/hardhat": "^6.1.2", + "@types/chai": "^4.2.22", + "@types/chai-as-promised": "^7.1.4", + "@types/faker": "^5.5.8", + "@types/jest": "^26.0.23", + "@types/mocha": "^9.0.0", + "@types/node": "^15.14.9", + "@types/uuid": "^8.3.3", + "@typescript-eslint/eslint-plugin": "^5.30.7", + "@typescript-eslint/parser": "^5.30.7", + "babel-jest": "^26.6.3", + "babel-plugin-module-resolver": "^4.1.0", + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "commitizen": "^4.2.4", + "dotenv": "^8.6.0", + "eslint": "^7.29.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-chai-expect": "^2.2.0", + "eslint-plugin-chai-friendly": "^0.6.0", + "eslint-plugin-import": "^2.20.0", + "eslint-plugin-prettier": "^3.1.2", + "ethers": "^5.6.9", + "faker": "^5.5.3", + "git-cz": "^4.7.6", + "hardhat": "^2.10.1", + "hardhat-gas-reporter": "^1.0.8", + "hardhat-watcher": "^2.3.0", + "jest": "^27.2.4", + "prettier": "^2.4.1", + "prettier-plugin-solidity": "^1.0.0-dev.23", + "semantic-release": "^19.0.3", + "solhint": "^3.3.6", + "solhint-plugin-prettier": "^0.0.5", + "solidity-coverage": "^0.7.21", + "solium": "^1.2.5", + "ts-node": "^10.9.1", + "typechain": "^8.1.0", + "typescript": "^4.7.4", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "ethers": ">=5.0.8" + } + }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", diff --git a/src/__tests__/token-registry-functions/transfers.test.ts b/src/__tests__/token-registry-functions/transfers.test.ts new file mode 100644 index 0000000..c87447c --- /dev/null +++ b/src/__tests__/token-registry-functions/transfers.test.ts @@ -0,0 +1,874 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; +import { + ethers as ethersV6, + JsonRpcProvider as JsonRpcProviderV6, + Network, + Wallet as WalletV6, +} from 'ethersV6'; +import * as coreModule from 'src/core'; +import { encrypt } from 'src/core'; +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { + transferBeneficiary, + transferHolder, + transferOwners, + nominate, +} from 'src/token-registry-functions'; + +// Mocks + +vi.mock('src/core', () => ({ + encrypt: vi.fn(() => 'encrypted_remarks'), + getTitleEscrowAddress: vi.fn(() => Promise.resolve('0xv5contract')), + isTitleEscrowVersion: vi.fn(() => Promise.resolve(true)), + TitleEscrowInterface: { + V4: '0xTitleEscrowIdV4', + V5: '0xTitleEscrowIdV5', + }, +})); + +vi.mock('src/token-registry-v5', () => { + return { + v5Contracts: { + TitleEscrow__factory: { + connect: vi.fn(() => mockV5TitleEscrowContract), + }, + TradeTrustToken__factory: { + connect: vi.fn(() => mockV5TradeTrustTokenContract), + }, + TitleEscrowFactory__factory: { + connect: vi.fn(() => mockV5TitleEscrowFactoryContract), + }, + }, + v5SupportInterfaceIds: { + TitleEscrow: '0xTitleEscrowIdV5', + TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV5', + }, + }; +}); + +vi.mock('src/token-registry-v4', () => { + return { + v4Contracts: { + TitleEscrow__factory: { + connect: vi.fn(() => mockV4TitleEscrowContract), + }, + TradeTrustToken__factory: { + connect: vi.fn(() => mockV4TradeTrustTokenContract), + }, + TitleEscrowFactory__factory: { + connect: vi.fn(() => mockV4TitleEscrowFactoryContract), + }, + v4SupportInterfaceIds: { + TitleEscrow: '0xTitleEscrowIdV4', + TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV4', + }, + }, + }; +}); + +const mockV5TitleEscrowFactoryContract = { + callStatic: { + getEscrowAddress: vi.fn(), + }, + getEscrowAddress: vi.fn(() => Promise.resolve('0xV5titleescrow')), +}; + +const mockV5TradeTrustTokenContract = { + supportsInterface: vi.fn(), + titleEscrowFactory: vi.fn(() => Promise.resolve('0xV5titleescrowfactory')), +}; + +const mockV5TitleEscrowContract = { + supportsInterface: vi.fn(), + callStatic: { + transferHolder: vi.fn(), + transferBeneficiary: vi.fn(), + transferOwners: vi.fn(), + nominate: vi.fn(), + }, + transferHolder: vi.fn(() => Promise.resolve('v5_transfer_holder_tx_hash')), + transferBeneficiary: vi.fn(() => Promise.resolve('v5_transfer_beneficiary_tx_hash')), + transferOwners: vi.fn(() => Promise.resolve('v5_transfer_owners_tx_hash')), + nominate: vi.fn(() => Promise.resolve('v5_nominate_tx_hash')), + holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), + beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), +}; + +const mockV4TitleEscrowContract = { + callStatic: { + transferHolder: vi.fn(), + transferBeneficiary: vi.fn(), + transferOwners: vi.fn(), + nominate: vi.fn(), + }, + transferHolder: vi.fn(() => Promise.resolve('v4_transfer_holder_tx_hash')), + transferBeneficiary: vi.fn(() => Promise.resolve('v4_transfer_beneficiary_tx_hash')), + transferOwners: vi.fn(() => Promise.resolve('v4_transfer_owners_tx_hash')), + nominate: vi.fn(() => Promise.resolve('v4_nominate_tx_hash')), + holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), + beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), +}; +const mockV4TitleEscrowFactoryContract = { + callStatic: { + getEscrowAddress: vi.fn(), + }, + getAddress: vi.fn(() => Promise.resolve('0xV4titleescrow')), +}; + +const mockV4TradeTrustTokenContract = { + titleEscrowFactory: vi.fn(() => Promise.resolve('0xV4titleescrowfactory')), +}; + +const PRIVATE_KEY = '0x59c6995e998f97a5a004497e5f1ebce0c16828d44b3f8d0bfa3a89d271d5b6b9'; // random local key + +const providerV5 = new ethersV5.providers.JsonRpcProvider(); +const providerV6 = new JsonRpcProviderV6(); + +interface ProviderInfo { + Provider: typeof providerV5 | typeof providerV6; + ethersVersion: 'v5' | 'v6'; + titleEscrowVersion: 'v4' | 'v5'; +} + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v4', + }, +]; +describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEscrowVersion }) => { + beforeEach(() => { + vi.clearAllMocks(); + }); + let wallet: ethersV5.Wallet | ethersV6.Wallet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + // wallet = { + // ...wallet, + // address: '0xcurrent_holder', + // getChainId: vi.fn().mockResolvedValue(CHAIN_ID.mainnet as unknown as number), + // } as any; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.mainnet as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: CHAIN_ID.mainnet, + } as unknown as Network); + // vi.spyOn(wallet, 'getAddress').mockResolvedValue('0xcurrent_holder'); + } + const isV5TT = titleEscrowVersion === 'v5'; + const mockTitleEscrowContract = isV5TT ? mockV5TitleEscrowContract : mockV4TitleEscrowContract; + const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + + describe(`transfer holder with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + const params = isV5TT + ? { + holderAddress: '0xholder', + remarks: '0xencrypted_remarks', + tokenId: 1, + } + : { + holderAddress: '0xholder', + tokenId: 1, + }; + + const txHash = isV5TT ? 'v5_transfer_holder_tx_hash' : 'v4_transfer_holder_tx_hash'; + + it('throws error if titleEscrowAddress is missing ', async () => { + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => Promise.resolve('')); + + await expect( + transferHolder( + { + titleEscrowAddress: '', + }, + wallet, + params, + { titleEscrowVersion }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('handles both v5 and v4 contracts when TR version is not provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferHolder.mockResolvedValue(true); + + const tx = await transferHolder( + { + titleEscrowAddress: titleEscrowAddress, + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xholder', '0xencrypted_remarks', undefined] + : ['0xholder', undefined]; + + expect(mockTitleEscrowContract.transferHolder).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + + it(`detects version automatically via supportsInterface for ${titleEscrowAddress}`, async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferHolder.mockResolvedValue(true); + + const tx = await transferHolder( + { + titleEscrowAddress: '0xauto', + }, + wallet, + params, + {}, // no isV5TT provided + ); + + expect(coreModule.isTitleEscrowVersion).toHaveBeenCalledWith({ + provider: wallet.provider, + titleEscrowAddress: '0xauto', + versionInterface: isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4', + }); + expect(tx).toBe(txHash); + }); + + it('calls gas station when gas options are missing', async () => { + const gasStationMock = vi.fn().mockResolvedValue({ + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + const mockChainId = CHAIN_ID.mainnet; + + // to allow overriding + const { SUPPORTED_CHAINS: SUPPORTED_CHAINS } = await import( + '@tradetrust-tt/tradetrust-utils' + ); + const originalChainData = SUPPORTED_CHAINS[mockChainId].gasStation; + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: gasStationMock, + }; + + mockTitleEscrowContract.callStatic.transferHolder.mockResolvedValue(true); + + await transferHolder( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ); + const resultOptions = isV5TT ? ['0xholder', '0xencrypted_remarks'] : ['0xholder']; + + expect(gasStationMock).toHaveBeenCalled(); + expect(mockTitleEscrowContract.transferHolder).toHaveBeenCalledWith(...resultOptions, { + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: originalChainData, + }; + }); + + it('throws error when callStatic fails', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferHolder.mockRejectedValue( + new Error('Simulated failure'), + ); + + await expect( + transferHolder( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ), + ).rejects.toThrow('Pre-check (callStatic) for transferHolder failed'); + }); + + it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => + Promise.resolve(titleEscrowAddress), + ); + mockTitleEscrowContract.callStatic.transferHolder.mockResolvedValue(true); + + const tx = await transferHolder( + { + tokenId: 1, + tokenRegistryAddress: '0xtokenregistry', + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xholder', '0xencrypted_remarks', undefined] + : ['0xholder', undefined]; + + expect(mockTitleEscrowContract.transferHolder).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + }); + + describe(`transfer beneficiary with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + const params = isV5TT + ? { newBeneficiaryAddress: '0xbeneficiary', remarks: '0xencrypted_remarks', tokenId: 1 } + : { newBeneficiaryAddress: '0xbeneficiary', tokenId: 1 }; + + const txHash = isV5TT ? 'v5_transfer_beneficiary_tx_hash' : 'v4_transfer_beneficiary_tx_hash'; + + it('throws error if titleEscrowAddress is missing ', async () => { + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => Promise.resolve('')); + + await expect( + transferBeneficiary( + { + titleEscrowAddress: '', + }, + wallet, + params, + { titleEscrowVersion }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('handles both v5 and v4 contracts when TR version is not provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferBeneficiary.mockResolvedValue(true); + + const tx = await transferBeneficiary( + { + titleEscrowAddress: titleEscrowAddress, + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xencrypted_remarks', undefined] + : ['0xbeneficiary', undefined]; + + expect(mockTitleEscrowContract.transferBeneficiary).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + + it(`detects version automatically via supportsInterface for ${titleEscrowVersion}`, async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferBeneficiary.mockResolvedValue(true); + + const tx = await transferBeneficiary( + { + titleEscrowAddress: '0xauto', + }, + wallet, + params, + {}, // no isV5TT provided + ); + + expect(coreModule.isTitleEscrowVersion).toHaveBeenCalledWith({ + provider: wallet.provider, + titleEscrowAddress: '0xauto', + versionInterface: isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4', + }); + expect(tx).toBe(txHash); + }); + + it('calls gas station when gas options are missing', async () => { + const gasStationMock = vi.fn().mockResolvedValue({ + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + const mockChainId = CHAIN_ID.mainnet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any); + vi.spyOn(wallet, 'getChainId').mockResolvedValue(mockChainId as unknown as number); + } else { + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: mockChainId, + } as unknown as Network); + } + + // to allow overriding + const { SUPPORTED_CHAINS: SUPPORTED_CHAINS } = await import( + '@tradetrust-tt/tradetrust-utils' + ); + const originalChainData = SUPPORTED_CHAINS[mockChainId].gasStation; + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: gasStationMock, + }; + + mockTitleEscrowContract.callStatic.transferBeneficiary.mockResolvedValue(true); + + await transferBeneficiary( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ); + const resultOptions = isV5TT ? ['0xbeneficiary', '0xencrypted_remarks'] : ['0xbeneficiary']; + + expect(gasStationMock).toHaveBeenCalled(); + expect(mockTitleEscrowContract.transferBeneficiary).toHaveBeenCalledWith(...resultOptions, { + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: originalChainData, + }; + }); + + it('throws error when callStatic fails', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferBeneficiary.mockRejectedValue( + new Error('Simulated failure'), + ); + + await expect( + transferBeneficiary( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ), + ).rejects.toThrow('Pre-check (callStatic) for transferBeneficiary failed'); + }); + + it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => + Promise.resolve(titleEscrowAddress), + ); + mockTitleEscrowContract.callStatic.transferBeneficiary.mockResolvedValue(true); + + const tx = await transferBeneficiary( + { + tokenId: 1, + tokenRegistryAddress: '0xtokenregistry', + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xencrypted_remarks', undefined] + : ['0xbeneficiary', undefined]; + + expect(mockTitleEscrowContract.transferBeneficiary).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + }); + + describe(`transfer owners with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + const params = isV5TT + ? { + newBeneficiaryAddress: '0xbeneficiary', + newHolderAddress: '0xholder', + remarks: '0xencrypted_remarks', + } + : { newBeneficiaryAddress: '0xbeneficiary', newHolderAddress: '0xholder' }; + + const txHash = isV5TT ? 'v5_transfer_owners_tx_hash' : 'v4_transfer_owners_tx_hash'; + + it('throws error if titleEscrowAddress is missing ', async () => { + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => Promise.resolve('')); + + await expect( + transferOwners( + { + titleEscrowAddress: '', + }, + wallet, + params, + { titleEscrowVersion }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('handles both v5 and v4 contracts when TR version is not provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => + Promise.resolve(titleEscrowAddress), + ); + mockTitleEscrowContract.callStatic.transferBeneficiary.mockResolvedValue(true); + + const tx = await transferOwners( + { + titleEscrowAddress: titleEscrowAddress, + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks', undefined] + : ['0xbeneficiary', '0xholder', undefined]; + + expect(mockTitleEscrowContract.transferOwners).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + + it(`detects version automatically via supportsInterface for ${titleEscrowVersion}`, async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferOwners.mockResolvedValue(true); + + const tx = await transferOwners( + { + titleEscrowAddress: '0xauto', + }, + wallet, + params, + {}, // no isV5TT provided + ); + + expect(coreModule.isTitleEscrowVersion).toHaveBeenCalledWith({ + provider: wallet.provider, + titleEscrowAddress: '0xauto', + versionInterface: isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4', + }); + expect(tx).toBe(txHash); + }); + + it('calls gas station when gas options are missing', async () => { + const gasStationMock = vi.fn().mockResolvedValue({ + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + const mockChainId = CHAIN_ID.mainnet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any); + vi.spyOn(wallet, 'getChainId').mockResolvedValue(mockChainId as unknown as number); + } else { + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: mockChainId, + } as unknown as Network); + } + + // to allow overriding + const { SUPPORTED_CHAINS: SUPPORTED_CHAINS } = await import( + '@tradetrust-tt/tradetrust-utils' + ); + const originalChainData = SUPPORTED_CHAINS[mockChainId].gasStation; + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: gasStationMock, + }; + + mockTitleEscrowContract.callStatic.transferOwners.mockResolvedValue(true); + + await transferOwners( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ); + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks'] + : ['0xbeneficiary', '0xholder']; + + expect(gasStationMock).toHaveBeenCalled(); + expect(mockTitleEscrowContract.transferOwners).toHaveBeenCalledWith(...resultOptions, { + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: originalChainData, + }; + }); + + it('throws error when callStatic fails', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.transferOwners.mockRejectedValue( + new Error('Simulated failure'), + ); + + await expect( + transferOwners( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ), + ).rejects.toThrow('Pre-check (callStatic) for transferOwners failed'); + }); + + it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => + Promise.resolve(titleEscrowAddress), + ); + mockTitleEscrowContract.callStatic.transferOwners.mockResolvedValue(true); + + const tx = await transferOwners( + { + tokenId: 1, + tokenRegistryAddress: '0xtokenregistry', + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks', undefined] + : ['0xbeneficiary', '0xholder', undefined]; + + expect(mockTitleEscrowContract.transferOwners).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + }); + + describe(`nominate with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + const params = isV5TT + ? { newBeneficiaryAddress: '0xbeneficiary', remarks: '0xencrypted_remarks', tokenId: 1 } + : { newBeneficiaryAddress: '0xbeneficiary', tokenId: 1 }; + + const txHash = isV5TT ? 'v5_nominate_tx_hash' : 'v4_nominate_tx_hash'; + + it('throws error if titleEscrowAddress is missing ', async () => { + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => Promise.resolve('')); + + await expect( + nominate( + { + titleEscrowAddress: '', + }, + wallet, + params, + { titleEscrowVersion }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('handles both v5 and v4 contracts when TR version is not provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.nominate.mockResolvedValue(true); + + const tx = await nominate( + { + titleEscrowAddress: titleEscrowAddress, + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xencrypted_remarks', undefined] + : ['0xbeneficiary', undefined]; + + expect(mockTitleEscrowContract.nominate).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + + it(`detects version automatically via supportsInterface for ${titleEscrowVersion}`, async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.nominate.mockResolvedValue(true); + + const tx = await nominate( + { + titleEscrowAddress: '0xauto', + }, + wallet, + params, + {}, // no isV5TT provided + ); + + expect(coreModule.isTitleEscrowVersion).toHaveBeenCalledWith({ + provider: wallet.provider, + titleEscrowAddress: '0xauto', + versionInterface: isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4', + }); + expect(tx).toBe(txHash); + }); + + it('calls gas station when gas options are missing', async () => { + const gasStationMock = vi.fn().mockResolvedValue({ + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + const mockChainId = CHAIN_ID.mainnet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any); + vi.spyOn(wallet, 'getChainId').mockResolvedValue(mockChainId as unknown as number); + } else { + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: mockChainId, + } as unknown as Network); + } + + // to allow overriding + const { SUPPORTED_CHAINS: SUPPORTED_CHAINS } = await import( + '@tradetrust-tt/tradetrust-utils' + ); + const originalChainData = SUPPORTED_CHAINS[mockChainId].gasStation; + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: gasStationMock, + }; + + mockTitleEscrowContract.callStatic.nominate.mockResolvedValue(true); + + await nominate( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ); + const resultOptions = isV5TT ? ['0xbeneficiary', '0xencrypted_remarks'] : ['0xbeneficiary']; + + expect(gasStationMock).toHaveBeenCalled(); + expect(mockTitleEscrowContract.nominate).toHaveBeenCalledWith(...resultOptions, { + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }); + + SUPPORTED_CHAINS[mockChainId] = { + ...SUPPORTED_CHAINS[mockChainId], + gasStation: originalChainData, + }; + }); + + it('throws error when callStatic fails', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + mockTitleEscrowContract.callStatic.nominate.mockRejectedValue(new Error('Simulated failure')); + + await expect( + nominate( + { + titleEscrowAddress: '0xv5contract', + }, + wallet, + params, + { id: 'doc-id', titleEscrowVersion }, + ), + ).rejects.toThrow('Pre-check (callStatic) for nominate failed'); + }); + + it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => + versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), + ); + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockImplementation(() => + Promise.resolve(titleEscrowAddress), + ); + mockTitleEscrowContract.callStatic.nominate.mockResolvedValue(true); + + const tx = await nominate( + { + tokenId: 1, + tokenRegistryAddress: '0xtokenregistry', + }, + wallet, + params, + { id: 'doc-id', chainId: CHAIN_ID.mainnet }, + ); + if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); + + const resultOptions = isV5TT + ? ['0xbeneficiary', '0xencrypted_remarks', undefined] + : ['0xbeneficiary', undefined]; + + expect(mockTitleEscrowContract.nominate).toHaveBeenCalledWith(...resultOptions); + expect(tx).toBe(txHash); + }); + }); +}); diff --git a/src/index.ts b/src/index.ts index 0cec9fa..4728185 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,7 @@ import { v5ComputeInterfaceId, } from './token-registry-v5'; export type { TypedContractMethod } from './token-registry-v5/typedContractMethod'; - +export * from './token-registry-functions'; export * from './core'; export * from './open-attestation'; export * from './verify'; diff --git a/src/token-registry-functions/index.ts b/src/token-registry-functions/index.ts new file mode 100644 index 0000000..6de95ff --- /dev/null +++ b/src/token-registry-functions/index.ts @@ -0,0 +1 @@ +export * from './transfer'; diff --git a/src/token-registry-functions/transfer.ts b/src/token-registry-functions/transfer.ts new file mode 100644 index 0000000..5247762 --- /dev/null +++ b/src/token-registry-functions/transfer.ts @@ -0,0 +1,536 @@ +import { CHAIN_ID, SUPPORTED_CHAINS } from '@tradetrust-tt/tradetrust-utils'; +import { + encrypt, + getTitleEscrowAddress, + isTitleEscrowVersion, + TitleEscrowInterface, +} from 'src/core'; +import { v4Contracts } from 'src/token-registry-v4'; +import { v5Contracts } from 'src/token-registry-v5'; +import { BigNumberish, Signer as SignerV6 } from 'ethersV6'; +import { BigNumber, Signer } from 'ethers'; +import { isV6EthersProvider } from 'src/utils/ethers'; + +interface TransferHolderParams { + holderAddress: string; + remarks?: string; +} +interface TransferBeneficiaryParams { + newBeneficiaryAddress: string; + remarks?: string; +} +interface NominateParams { + newBeneficiaryAddress: string; + remarks?: string; +} +interface TransferOwnersParams { + newHolderAddress: string; + newBeneficiaryAddress: string; + remarks?: string; +} + +interface TransferOptions { + chainId?: CHAIN_ID; + titleEscrowVersion?: 'v4' | 'v5'; + maxFeePerGas?: BigNumberish | string | number | BigNumber; + maxPriorityFeePerGas?: BigNumberish | string | number | BigNumber; + id?: string; +} + +// 🔍 Handles both Ethers v5 and v6 signer types +const getChainIdSafe = async (signer: SignerV6 | Signer): Promise => { + if (isV6EthersProvider(signer.provider)) { + const network = await (signer as Signer).provider?.getNetwork(); + if (!network?.chainId) throw new Error('Cannot determine chainId: provider is missing'); + return network.chainId; + } + return await (signer as Signer).getChainId(); +}; +// const getSignerAddressSafe = async (signer: SignerV6 | Signer): Promise => { +// if (isV6EthersProvider(signer.provider)) { +// return await (signer as SignerV6).getAddress(); +// } +// return (signer as any).address; +// }; + +type ContractOptions = + | { + titleEscrowAddress: string; // Present — no restrictions on the rest + tokenId?: string | number; + tokenRegistryAddress?: string; + } + | { + titleEscrowAddress?: undefined; // Absent — must provide both below + tokenId: string | number; + tokenRegistryAddress: string; + }; + +const transferHolder = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: TransferHolderParams, + options: TransferOptions, +) => { + const { tokenRegistryAddress, tokenId } = contractOptions; + const { titleEscrowVersion } = options; + let { titleEscrowAddress } = contractOptions; + let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + { titleEscrowVersion }, + ); + } + + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { holderAddress, remarks } = params; + + // Connect V5 contract by default + let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V4, + provider: signer.provider, + }), + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }), + ]); + } + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + + // Switch to V4 if needed + if (isV4TT) { + titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + titleEscrowAddress, + signer as Signer, + ); + } + // check for current holder and signer + // const currentHolder = await titleEscrowContract.holder(); + + // if (currentHolder.toLowerCase() === holderAddress.toLowerCase()) { + // throw new Error('Cannot transfer to current holder'); + // } + // const signerAddress = await getSignerAddressSafe(signer); + // if (currentHolder.toLowerCase() !== signerAddress.toLowerCase()) { + // throw new Error('Only the current holder can transfer'); + // } + + // Check callStatic (dry run) + try { + if (isV5TT) { + await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.transferHolder( + holderAddress, + encryptedRemarks, + ); + } else if (isV4TT) { + await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.transferHolder( + holderAddress, + ); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for transferHolder failed'); + } + + // If gas values are missing, query gas station if available + if (!maxFeePerGas || !maxPriorityFeePerGas) { + chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); + const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; + + if (gasStation) { + const gasFees = await gasStation(); + maxFeePerGas = gasFees?.maxFeePerGas ?? 0; + maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; + } + } + const txOptions = + maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; + // Send the actual transaction + if (isV5TT) { + return await (titleEscrowContract as v5Contracts.TitleEscrow).transferHolder( + holderAddress, + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await titleEscrowContract.transferHolder(holderAddress, txOptions); + } +}; + +const transferBeneficiary = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: TransferBeneficiaryParams, + options: TransferOptions, +) => { + const { tokenId, tokenRegistryAddress } = contractOptions; + const { titleEscrowVersion } = options; + let { titleEscrowAddress } = contractOptions; + let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + { titleEscrowVersion }, + ); + } + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { newBeneficiaryAddress, remarks } = params; + + // Connect V5 contract by default + let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V4, + provider: signer.provider, + }), + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }), + ]); + } + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + + // Switch to V4 if needed + if (!isV5TT) { + titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + titleEscrowAddress, + signer as Signer, + ); + } + + // check for current beneficiary and signer + // const currentHolder = await titleEscrowContract.holder(); + // const currentBeneficiary = await titleEscrowContract.beneficiary(); + // if (currentBeneficiary.toLowerCase() === newBeneficiaryAddress.toLowerCase()) { + // throw new Error('Cannot transfer to current beneficiary'); + // } + // const signerAddress = await signer.getAddress(); + // if (currentHolder.toLowerCase() !== signerAddress.toLowerCase()) { + // throw new Error('Only the current holder can transfer'); + // } + + // Check callStatic (dry run) + try { + if (isV5TT) { + await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.transferBeneficiary( + newBeneficiaryAddress, + encryptedRemarks, + ); + } else if (isV4TT) { + await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.transferBeneficiary( + newBeneficiaryAddress, + ); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for transferBeneficiary failed'); + } + + // If gas values are missing, query gas station if available + if (!maxFeePerGas || !maxPriorityFeePerGas) { + chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); + const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; + + if (gasStation) { + const gasFees = await gasStation(); + maxFeePerGas = gasFees?.maxFeePerGas ?? 0; + maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; + } + } + + const txOptions = + maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; + // Send the actual transaction + if (isV5TT) { + const tx = await (titleEscrowContract as v5Contracts.TitleEscrow).transferBeneficiary( + newBeneficiaryAddress, + encryptedRemarks, + txOptions, + ); + return tx; + } else if (isV4TT) { + const tx = await (titleEscrowContract as v4Contracts.TitleEscrow).transferBeneficiary( + newBeneficiaryAddress, + txOptions, + ); + return tx; + } +}; +const transferOwners = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: TransferOwnersParams, + options: TransferOptions, +) => { + const { tokenId, tokenRegistryAddress } = contractOptions; + const { titleEscrowVersion } = options; + let { titleEscrowAddress } = contractOptions; + let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + { titleEscrowVersion }, + ); + } + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { newBeneficiaryAddress, newHolderAddress, remarks } = params; + + // Connect V5 contract by default + let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V4, + provider: signer.provider, + }), + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }), + ]); + } + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + + // Switch to V4 if needed + if (!isV5TT) { + titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + titleEscrowAddress, + signer as Signer, + ); + } + + // check for current beneficiary, holder and signer + // const currentHolder = await titleEscrowContract.holder(); + // const currentBeneficiary = await titleEscrowContract.beneficiary(); + // if (currentBeneficiary.toLowerCase() === newBeneficiaryAddress.toLowerCase()) { + // throw new Error('Cannot transfer to current beneficiary'); + // } + // if (currentHolder.toLowerCase() === newHolderAddress.toLowerCase()) { + // throw new Error('Cannot transfer to current holder'); + // } + // const signerAddress = await signer.getAddress(); + // if ( + // currentHolder.toLowerCase() !== signerAddress.toLowerCase() || + // currentBeneficiary.toLowerCase() !== signerAddress.toLowerCase() + // ) { + // throw new Error('Holder and Beneficiary must be current signer'); + // } + + // Check callStatic (dry run) + try { + if (isV5TT) { + await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.transferOwners( + newBeneficiaryAddress, + newHolderAddress, + encryptedRemarks, + ); + } else if (isV4TT) { + await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.transferOwners( + newBeneficiaryAddress, + newHolderAddress, + ); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for transferOwners failed'); + } + + // If gas values are missing, query gas station if available + if (!maxFeePerGas || !maxPriorityFeePerGas) { + chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); + const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; + + if (gasStation) { + const gasFees = await gasStation(); + maxFeePerGas = gasFees?.maxFeePerGas ?? 0; + maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; + } + } + + const txOptions = + maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; + // Send the actual transaction + + if (isV5TT) { + return await (titleEscrowContract as v5Contracts.TitleEscrow).transferOwners( + newBeneficiaryAddress, + newHolderAddress, + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await (titleEscrowContract as v4Contracts.TitleEscrow).transferOwners( + newBeneficiaryAddress, + newHolderAddress, + txOptions, + ); + } +}; + +const nominate = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: NominateParams, + options: TransferOptions, +) => { + const { tokenId, tokenRegistryAddress } = contractOptions; + const { titleEscrowVersion } = options; + let { titleEscrowAddress } = contractOptions; + let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + { titleEscrowVersion }, + ); + } + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { newBeneficiaryAddress, remarks } = params; + + // Connect V5 contract by default + let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V4, + provider: signer.provider, + }), + isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }), + ]); + } + + // Switch to V4 if needed + if (!isV5TT) { + titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + titleEscrowAddress, + signer as Signer, + ); + } + + // check for current beneficiary and signer + // const currentBeneficiary = await titleEscrowContract.beneficiary(); + // const signerAddress = await signer.getAddress(); + // if (currentBeneficiary.toLowerCase() !== signerAddress.toLowerCase()) { + // throw new Error('Beneficiary must be current signer'); + // } + // if (currentBeneficiary.toLowerCase() === newBeneficiaryAddress.toLowerCase()) { + // throw new Error('Cannot nominate to current beneficiary'); + // } + + // Check callStatic (dry run) + try { + if (isV5TT) { + await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.nominate( + newBeneficiaryAddress, + encryptedRemarks, + ); + } else if (isV4TT) { + await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.nominate( + newBeneficiaryAddress, + ); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for nominate failed'); + } + + // If gas values are missing, query gas station if available + if (!maxFeePerGas || !maxPriorityFeePerGas) { + chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); + const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; + + if (gasStation) { + const gasFees = await gasStation(); + maxFeePerGas = gasFees?.maxFeePerGas ?? 0; + maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; + } + } + + const txOptions = + maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; + // Send the actual transaction + + if (isV5TT) { + return await (titleEscrowContract as v5Contracts.TitleEscrow).nominate( + newBeneficiaryAddress, + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await (titleEscrowContract as v4Contracts.TitleEscrow).nominate( + newBeneficiaryAddress, + txOptions, + ); + } +}; + +export { transferHolder, transferBeneficiary, transferOwners, nominate }; From 73847b77f091198a9595071acc7e6c3a369422cf Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 30 Jun 2025 05:02:03 +0000 Subject: [PATCH 03/14] chore(release): 1.6.0-alpha.1 [skip ci] ## [1.6.0-alpha.1](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.6.0-alpha.1) (2025-06-30) ### Features * token registry functions ([#74](https://github.com/TrustVC/trustvc/issues/74)) ([5690fcd](https://github.com/TrustVC/trustvc/commit/5690fcda798192609b0060fab0a3f3f77dca8012)) ### Miscellaneous Chores * back merge ([#75](https://github.com/TrustVC/trustvc/issues/75)) ([7cc1891](https://github.com/TrustVC/trustvc/commit/7cc1891ffebceb4eebf1421d3bc348926efa3f10)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ef622b..ecfde22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [1.6.0-alpha.1](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.6.0-alpha.1) (2025-06-30) + + +### Features + +* token registry functions ([#74](https://github.com/TrustVC/trustvc/issues/74)) ([5690fcd](https://github.com/TrustVC/trustvc/commit/5690fcda798192609b0060fab0a3f3f77dca8012)) + + +### Miscellaneous Chores + +* back merge ([#75](https://github.com/TrustVC/trustvc/issues/75)) ([7cc1891](https://github.com/TrustVC/trustvc/commit/7cc1891ffebceb4eebf1421d3bc348926efa3f10)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) + ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) diff --git a/package-lock.json b/package-lock.json index dacc2c0..51f29bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@trustvc/trustvc", - "version": "1.5.5", + "version": "1.6.0-alpha.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.5.5", + "version": "1.6.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", diff --git a/package.json b/package.json index cc57a0d..f2c1570 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.5.5", + "version": "1.6.0-alpha.1", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From 2ea52ce2ed010ba2da095d6444f135f014dbb442 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Fri, 4 Jul 2025 08:41:51 +0530 Subject: [PATCH 04/14] feat: mint function (#78) * fix: add w3c credential status check (#72) * fix: add w3c credential status check * fix: update test * fix: update enum status codes * fix: remove console * chore(release): 1.5.4 [skip ci] ## [1.5.4](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.5.4) (2025-06-17) ### Bug Fixes * add w3c credential status check ([#72](https://github.com/TrustVC/trustvc/issues/72)) ([0111cb3](https://github.com/TrustVC/trustvc/commit/0111cb3e48ac86f0cea715ceb5277d199f139763)) * fix: upgrade package (#73) * chore(release): 1.5.5 [skip ci] ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) ### Bug Fixes * upgrade package ([#73](https://github.com/TrustVC/trustvc/issues/73)) ([3c6c9c7](https://github.com/TrustVC/trustvc/commit/3c6c9c73675ec43e0514d9afe5df4444f6e4400b)) * feat: add transfer holder function * feat: add transfer owners beneficiary * chore: tests cleanup * chore: tests cleanup * fix: remove console * fix: rever useendorement chain * fix: remove console * feat: add reject transfer functions * chore: trigger rebuild after rebase * chore(release): 1.5.4 [skip ci] * add w3c credential status check ([#72](https://github.com/TrustVC/trustvc/issues/72)) ([0111cb3](https://github.com/TrustVC/trustvc/commit/0111cb3e48ac86f0cea715ceb5277d199f139763)) * feat: add transfer holder function * feat: add transfer owners beneficiary * chore: tests cleanup * fix: remove console * fix: rever useendorement chain * feat: add reject transfer functions * chore: trigger rebuild after rebase * chore: trigger rebuild after rebase * feat: token registry return functions * feat: add mint function * fix: update fixes * fix: update tests * revert: revert changes --------- Co-authored-by: semantic-release-bot Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> --- .../token-registry-functions/fixtures.ts | 147 ++++++ .../token-registry-functions/mint.test.ts | 216 +++++++++ .../rejectTransfers.test.ts | 438 +++++++++++++++++ .../returnToken.test.ts | 452 ++++++++++++++++++ .../transfers.test.ts | 134 +----- .../endorsement-chain/useEndorsementChain.ts | 2 +- src/token-registry-functions/index.ts | 3 + src/token-registry-functions/mint.ts | 113 +++++ .../rejectTransfers.ts | 217 +++++++++ src/token-registry-functions/returnToken.ts | 306 ++++++++++++ src/token-registry-functions/transfer.ts | 225 ++++----- src/token-registry-functions/types.ts | 83 ++++ src/token-registry-functions/utils.ts | 44 ++ 13 files changed, 2135 insertions(+), 245 deletions(-) create mode 100644 src/__tests__/token-registry-functions/fixtures.ts create mode 100644 src/__tests__/token-registry-functions/mint.test.ts create mode 100644 src/__tests__/token-registry-functions/rejectTransfers.test.ts create mode 100644 src/__tests__/token-registry-functions/returnToken.test.ts create mode 100644 src/token-registry-functions/mint.ts create mode 100644 src/token-registry-functions/rejectTransfers.ts create mode 100644 src/token-registry-functions/returnToken.ts create mode 100644 src/token-registry-functions/types.ts create mode 100644 src/token-registry-functions/utils.ts diff --git a/src/__tests__/token-registry-functions/fixtures.ts b/src/__tests__/token-registry-functions/fixtures.ts new file mode 100644 index 0000000..767d804 --- /dev/null +++ b/src/__tests__/token-registry-functions/fixtures.ts @@ -0,0 +1,147 @@ +import { vi } from 'vitest'; +import { ethers as ethersV5 } from 'ethers'; +import { JsonRpcProvider as JsonRpcProviderV6 } from 'ethersV6'; +export const MOCK_V5_ADDRESS = '0xV5TokenRegistryContract'; +export const MOCK_V4_ADDRESS = '0xV4TokenRegistryContract'; + +vi.mock('src/core', () => ({ + encrypt: vi.fn(() => 'encrypted_remarks'), + getTitleEscrowAddress: vi.fn(), + isTitleEscrowVersion: vi.fn(() => Promise.resolve(true)), + checkSupportsInterface: vi.fn(), + + TitleEscrowInterface: { + V4: '0xTitleEscrowIdV4', + V5: '0xTitleEscrowIdV5', + }, +})); + +vi.mock('src/token-registry-v5', () => { + return { + v5Contracts: { + TitleEscrow__factory: { + connect: vi.fn(() => mockV5TitleEscrowContract), + }, + TradeTrustToken__factory: { + connect: vi.fn(() => mockV5TradeTrustTokenContract), + }, + TitleEscrowFactory__factory: { + connect: vi.fn(() => mockV5TitleEscrowFactoryContract), + }, + }, + v5SupportInterfaceIds: { + TitleEscrow: '0xTitleEscrowIdV5', + TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV5', + TradeTrustTokenRestorable: '0xTradeTrustTokenRestorableIdV5', + TradeTrustTokenBurnable: '0xTradeTrustTokenBurnableIdV5', + }, + }; +}); + +vi.mock('src/token-registry-v4', () => { + return { + v4Contracts: { + TitleEscrow__factory: { + connect: vi.fn(() => mockV4TitleEscrowContract), + }, + TradeTrustToken__factory: { + connect: vi.fn(() => mockV4TradeTrustTokenContract), + }, + TitleEscrowFactory__factory: { + connect: vi.fn(() => mockV4TitleEscrowFactoryContract), + }, + }, + v4SupportInterfaceIds: { + TitleEscrow: '0xTitleEscrowIdV4', + TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV4', + TradeTrustTokenRestorable: '0xTradeTrustTokenRestorableIdV4', + TradeTrustTokenBurnable: '0xTradeTrustTokenBurnableIdV4', + }, + }; +}); + +export const mockV5TitleEscrowFactoryContract = { + callStatic: { + getEscrowAddress: vi.fn(), + }, + getEscrowAddress: vi.fn(() => Promise.resolve('0xV5titleescrow')), +}; + +export const mockV5TradeTrustTokenContract = { + callStatic: { + burn: vi.fn(), + restore: vi.fn(), + mint: vi.fn(), + }, + supportsInterface: vi.fn(), + titleEscrowFactory: vi.fn(() => Promise.resolve('0xV5titleescrowfactory')), + burn: vi.fn(() => Promise.resolve('v5_burn_tx_hash')), + restore: vi.fn(() => Promise.resolve('v5_restore_tx_hash')), + mint: vi.fn(() => Promise.resolve('v5_mint_tx_hash')), +}; + +export const mockV5TitleEscrowContract = { + supportsInterface: vi.fn(), + callStatic: { + transferHolder: vi.fn(), + transferBeneficiary: vi.fn(), + transferOwners: vi.fn(), + nominate: vi.fn(), + rejectTransferHolder: vi.fn(), + rejectTransferBeneficiary: vi.fn(), + rejectTransferOwners: vi.fn(), + returnToIssuer: vi.fn(), + }, + transferHolder: vi.fn(() => Promise.resolve('v5_transfer_holder_tx_hash')), + transferBeneficiary: vi.fn(() => Promise.resolve('v5_transfer_beneficiary_tx_hash')), + transferOwners: vi.fn(() => Promise.resolve('v5_transfer_owners_tx_hash')), + nominate: vi.fn(() => Promise.resolve('v5_nominate_tx_hash')), + holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), + beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), + rejectTransferHolder: vi.fn(() => Promise.resolve('v5_reject_transfer_holder_tx_hash')), + rejectTransferBeneficiary: vi.fn(() => Promise.resolve('v5_reject_transfer_beneficiary_tx_hash')), + rejectTransferOwners: vi.fn(() => Promise.resolve('v5_reject_transfer_owners_tx_hash')), + returnToIssuer: vi.fn(() => Promise.resolve('v5_return_to_issuer_tx_hash')), +}; + +export const mockV4TitleEscrowContract = { + supportsInterface: vi.fn(), + callStatic: { + transferHolder: vi.fn(), + transferBeneficiary: vi.fn(), + transferOwners: vi.fn(), + nominate: vi.fn(), + surrender: vi.fn(), + }, + transferHolder: vi.fn(() => Promise.resolve('v4_transfer_holder_tx_hash')), + transferBeneficiary: vi.fn(() => Promise.resolve('v4_transfer_beneficiary_tx_hash')), + transferOwners: vi.fn(() => Promise.resolve('v4_transfer_owners_tx_hash')), + nominate: vi.fn(() => Promise.resolve('v4_nominate_tx_hash')), + holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), + beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), + surrender: vi.fn(() => Promise.resolve('v4_surrender_tx_hash')), +}; +export const mockV4TitleEscrowFactoryContract = { + callStatic: { + getEscrowAddress: vi.fn(), + }, + getEscrowAddress: vi.fn(() => Promise.resolve('0xV4titleescrow')), +}; + +export const mockV4TradeTrustTokenContract = { + callStatic: { + burn: vi.fn(), + restore: vi.fn(), + mint: vi.fn(), + }, + titleEscrowFactory: vi.fn(() => Promise.resolve('0xV4titleescrowfactory')), + supportsInterface: vi.fn(), + burn: vi.fn(() => Promise.resolve('v4_burn_tx_hash')), + restore: vi.fn(() => Promise.resolve('v4_restore_tx_hash')), + mint: vi.fn(() => Promise.resolve('v4_mint_tx_hash')), +}; + +export const PRIVATE_KEY = '0x59c6995e998f97a5a004497e5f1ebce0c16828d44b3f8d0bfa3a89d271d5b6b9'; // random local key + +export const providerV5 = new ethersV5.providers.JsonRpcProvider(); +export const providerV6 = new JsonRpcProviderV6(); diff --git a/src/__tests__/token-registry-functions/mint.test.ts b/src/__tests__/token-registry-functions/mint.test.ts new file mode 100644 index 0000000..b07e651 --- /dev/null +++ b/src/__tests__/token-registry-functions/mint.test.ts @@ -0,0 +1,216 @@ +import './fixtures.js'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; +import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; +import * as coreModule from 'src/core'; + +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { v5Contracts } from 'src/token-registry-v5'; +import { v4Contracts } from 'src/token-registry-v4'; +import { mint } from 'src/token-registry-functions/mint'; +import { + MOCK_V4_ADDRESS, + MOCK_V5_ADDRESS, + mockV4TradeTrustTokenContract, + mockV5TradeTrustTokenContract, + PRIVATE_KEY, + providerV5, + providerV6, +} from './fixtures.js'; +import { ProviderInfo } from 'src/token-registry-functions/types.js'; + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v4', + }, +]; +describe('Mint Token', () => { + const mockTokenId = '0xTokenId'; + const mockRemarks = 'Mint remarks'; + const mockChainId = CHAIN_ID.local; + describe.each(providers)( + 'Mint Token with TR version $titleEscrowVersion and ethers version $ethersVersion', + async ({ Provider, ethersVersion, titleEscrowVersion }) => { + const isV5TT = titleEscrowVersion === 'v5'; + // let mockContract = isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract; + const mockTxResponse = titleEscrowVersion === 'v5' ? 'v5_mint_tx_hash' : 'v4_mint_tx_hash'; + + let wallet: ethersV5.Wallet | ethersV6.Wallet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.local as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: CHAIN_ID.local, + } as unknown as Network); + } + const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; + const mockBeneficiaryAddress = '0xBeneficiaryAddress'; + const mockHolderAddress = '0xHolderAddress'; + // const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + beforeEach(() => { + vi.clearAllMocks(); + // vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2)); + vi.spyOn(coreModule, 'checkSupportsInterface').mockImplementation( + async (address, interfaceId) => { + return ( + interfaceId === + (isV5TT ? '0xTradeTrustTokenMintableIdV5' : '0xTradeTrustTokenMintableIdV4') + ); + }, + ); + mockV5TradeTrustTokenContract.callStatic.mint.mockResolvedValue(true); + mockV4TradeTrustTokenContract.callStatic.mint.mockResolvedValue(true); + }); + + it('should Mint token with remarks', async () => { + const result = await mint( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + remarks: mockRemarks, + }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual(mockTxResponse); + if (isV5TT) expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); + expect( + (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, + ).toHaveBeenCalled(); + }); + + it('should mint token without remarks', async () => { + const result = await mint( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + }, + { chainId: mockChainId, titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw when callStatic fails', async () => { + const mockError = new Error('callStatic error'); + if (isV5TT) { + mockV5TradeTrustTokenContract.callStatic.mint.mockRejectedValue(mockError); + } else { + mockV4TradeTrustTokenContract.callStatic.mint.mockRejectedValue(mockError); + } + await expect( + mint( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + remarks: mockRemarks, + }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for mint failed'); + if (isV5TT) { + mockV5TradeTrustTokenContract.callStatic.mint = vi.fn(); + } else { + mockV4TradeTrustTokenContract.callStatic.mint = vi.fn(); + } + }); + + it('should throw when token registry address is missing', async () => { + await expect( + mint( + { tokenRegistryAddress: '' }, + wallet, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + mint( + { tokenRegistryAddress: mockTokenRegistryAddress }, + signerWithoutProvider, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + remarks: mockRemarks, + }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw when version is unsupported', async () => { + vi.spyOn(coreModule, 'checkSupportsInterface').mockResolvedValue(false); + + await expect( + mint( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + remarks: mockRemarks, + }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Only Token Registry V4/V5 is supported'); + }); + + it('should work with explicit V5/V4 version', async () => { + const result = await mint( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { + beneficiaryAddress: mockBeneficiaryAddress, + holderAddress: mockHolderAddress, + tokenId: mockTokenId, + remarks: mockRemarks, + }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.checkSupportsInterface).not.toHaveBeenCalled(); + }); + }, + ); +}); diff --git a/src/__tests__/token-registry-functions/rejectTransfers.test.ts b/src/__tests__/token-registry-functions/rejectTransfers.test.ts new file mode 100644 index 0000000..86e3c16 --- /dev/null +++ b/src/__tests__/token-registry-functions/rejectTransfers.test.ts @@ -0,0 +1,438 @@ +import './fixtures.js'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; +import { ethers as ethersV6, Network, Wallet as WalletV6 } from 'ethersV6'; +import * as coreModule from 'src/core'; +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { + rejectTransferBeneficiary, + rejectTransferHolder, + rejectTransferOwners, +} from 'src/token-registry-functions/rejectTransfers'; +import { mockV5TitleEscrowContract, PRIVATE_KEY, providerV5, providerV6 } from './fixtures'; +import { ProviderInfo } from 'src/token-registry-functions/types.js'; + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, +]; + +describe.each(providers)( + 'Reject Transfers', + async ({ Provider, ethersVersion, titleEscrowVersion }) => { + const mockTokenRegistryAddress = '0xTokenRegistry'; + const mockTokenId = '0xTokenId'; + const mockTitleEscrowAddress = '0xTitleEscrow'; + const mockRemarks = 'Rejection remarks'; + const mockChainId = CHAIN_ID.local; + const mockEncryptedRemarks = '0xencryptedRemarks'; + + let wallet: ethersV5.Wallet | ethersV6.Wallet; + beforeEach(() => { + // Reset all mocks before each test + vi.clearAllMocks(); + + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + // wallet = { + // ...wallet, + // address: '0xcurrent_holder', + // getChainId: vi.fn().mockResolvedValue(CHAIN_ID.mainnet as unknown as number), + // } as any; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.mainnet as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: CHAIN_ID.mainnet, + } as unknown as Network); + // vi.spyOn(wallet, 'getAddress').mockResolvedValue('0xcurrent_holder'); + } + + // Mock core functions + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockResolvedValue(mockTitleEscrowAddress); + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockResolvedValue(true); + vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2)); + + // Mock contract calls + }); + describe(`Reject Transfers Holder with ethers version ${ethersVersion}`, () => { + it('should reject transfer holder with signer and all required parameters', async () => { + const result = await rejectTransferHolder( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual('v5_reject_transfer_holder_tx_hash'); + }); + + it('should reject transfer holder when titleEscrowAddress is provided', async () => { + const result = await rejectTransferHolder( + { + titleEscrowAddress: mockTitleEscrowAddress, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual('v5_reject_transfer_holder_tx_hash'); + expect(coreModule.getTitleEscrowAddress).not.toHaveBeenCalled(); + }); + + it('should reject transfer holder without remarks', async () => { + const result = await rejectTransferHolder( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + {}, + { chainId: mockChainId }, + ); + + expect(result).toEqual('v5_reject_transfer_holder_tx_hash'); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw error when tokenRegistryAddress is missing', async () => { + vi.mocked(coreModule.getTitleEscrowAddress).mockResolvedValue(undefined); + await expect( + rejectTransferHolder( + { + tokenId: mockTokenId, + } as any, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw error when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + rejectTransferHolder( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + signerWithoutProvider, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw error when title escrow is not V5', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockResolvedValue(false); + + await expect( + rejectTransferHolder( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Only Token Registry V5 is supported'); + }); + + it('should throw error when callStatic fails', async () => { + mockV5TitleEscrowContract.callStatic.rejectTransferHolder.mockRejectedValue( + new Error('Simulated failure'), + ); + + await expect( + rejectTransferHolder( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for rejectTransferHolder failed'); + mockV5TitleEscrowContract.callStatic.rejectTransferHolder = vi.fn(); + }); + + it('should use explicit titleEscrowVersion when provided', async () => { + await rejectTransferHolder( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(coreModule.isTitleEscrowVersion).not.toHaveBeenCalled(); + }); + }); + + describe(`Reject Transfers Beneficiary with ethers version ${ethersVersion}`, () => { + it('should reject transfer beneficiary with signer and all required parameters', async () => { + const result = await rejectTransferBeneficiary( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual('v5_reject_transfer_beneficiary_tx_hash'); + }); + + it('should reject transfer beneficiary when titleEscrowAddress is provided', async () => { + const result = await rejectTransferBeneficiary( + { + titleEscrowAddress: mockTitleEscrowAddress, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual('v5_reject_transfer_beneficiary_tx_hash'); + expect(coreModule.getTitleEscrowAddress).not.toHaveBeenCalled(); + }); + + it('should reject transfer beneficiary without remarks', async () => { + const result = await rejectTransferBeneficiary( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + {}, + { chainId: mockChainId }, + ); + + expect(result).toEqual('v5_reject_transfer_beneficiary_tx_hash'); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw error when tokenRegistryAddress is missing', async () => { + vi.mocked(coreModule.getTitleEscrowAddress).mockResolvedValue(undefined); + await expect( + rejectTransferBeneficiary( + { + tokenId: mockTokenId, + } as any, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw error when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + rejectTransferBeneficiary( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + signerWithoutProvider, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw error when title escrow is not V5', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockResolvedValue(false); + + await expect( + rejectTransferBeneficiary( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Only Token Registry V5 is supported'); + }); + + it('should throw error when callStatic fails', async () => { + mockV5TitleEscrowContract.callStatic.rejectTransferBeneficiary.mockRejectedValue( + new Error('Simulated failure'), + ); + + await expect( + rejectTransferBeneficiary( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for rejectTransferBeneficiary failed'); + mockV5TitleEscrowContract.callStatic.rejectTransferBeneficiary = vi.fn(); + }); + + it('should use explicit titleEscrowVersion when provided', async () => { + await rejectTransferBeneficiary( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(coreModule.isTitleEscrowVersion).not.toHaveBeenCalled(); + }); + }); + + describe(`Reject Transfers Owners with ethers version ${ethersVersion}`, () => { + it('should reject transfer beneficiary with signer and all required parameters', async () => { + const result = await rejectTransferOwners( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual('v5_reject_transfer_owners_tx_hash'); + }); + + it('should reject transfer beneficiary when titleEscrowAddress is provided', async () => { + const result = await rejectTransferOwners( + { + titleEscrowAddress: mockTitleEscrowAddress, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual('v5_reject_transfer_owners_tx_hash'); + expect(coreModule.getTitleEscrowAddress).not.toHaveBeenCalled(); + }); + + it('should reject transfer beneficiary without remarks', async () => { + const result = await rejectTransferOwners( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + {}, + { chainId: mockChainId }, + ); + + expect(result).toEqual('v5_reject_transfer_owners_tx_hash'); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw error when tokenRegistryAddress is missing', async () => { + vi.mocked(coreModule.getTitleEscrowAddress).mockResolvedValue(undefined); + await expect( + rejectTransferOwners( + { + tokenId: mockTokenId, + } as any, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw error when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + rejectTransferOwners( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + signerWithoutProvider, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw error when title escrow is not V5', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockResolvedValue(false); + + await expect( + rejectTransferOwners( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Only Token Registry V5 is supported'); + }); + + it('should throw error when callStatic fails', async () => { + mockV5TitleEscrowContract.callStatic.rejectTransferOwners.mockRejectedValue( + new Error('Simulated failure'), + ); + + await expect( + rejectTransferOwners( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for rejectTransferOwners failed'); + mockV5TitleEscrowContract.callStatic.rejectTransferOwners = vi.fn(); + }); + + it('should use explicit titleEscrowVersion when provided', async () => { + await rejectTransferOwners( + { + tokenRegistryAddress: mockTokenRegistryAddress, + tokenId: mockTokenId, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(coreModule.isTitleEscrowVersion).not.toHaveBeenCalled(); + }); + }); + }, +); diff --git a/src/__tests__/token-registry-functions/returnToken.test.ts b/src/__tests__/token-registry-functions/returnToken.test.ts new file mode 100644 index 0000000..9fd461c --- /dev/null +++ b/src/__tests__/token-registry-functions/returnToken.test.ts @@ -0,0 +1,452 @@ +import './fixtures.js'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; +import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; +import * as coreModule from 'src/core'; + +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { v5Contracts } from 'src/token-registry-v5'; +import { v4Contracts } from 'src/token-registry-v4'; +import { + acceptReturned, + rejectReturned, + returnToIssuer, +} from 'src/token-registry-functions/returnToken'; +import { + MOCK_V4_ADDRESS, + MOCK_V5_ADDRESS, + mockV4TitleEscrowContract, + mockV4TradeTrustTokenContract, + mockV5TitleEscrowContract, + mockV5TradeTrustTokenContract, + PRIVATE_KEY, + providerV5, + providerV6, +} from './fixtures.js'; +import { ProviderInfo } from 'src/token-registry-functions/types.js'; + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v4', + }, +]; +describe('Return Token', () => { + const mockTokenId = '0xTokenId'; + const mockRemarks = 'Return remarks'; + const mockChainId = CHAIN_ID.local; + const mockEncryptedRemarks = '0xencryptedRemarks'; + describe.each(providers)( + 'Return Token with TR version $titleEscrowVersion and ethers version $ethersVersion', + async ({ Provider, ethersVersion, titleEscrowVersion }) => { + const mockTokenRegistryAddress = '0xTokenRegistry'; + const mockTxResponse = + titleEscrowVersion === 'v5' ? 'v5_return_to_issuer_tx_hash' : 'v4_surrender_tx_hash'; + + let wallet: ethersV5.Wallet | ethersV6.Wallet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.local as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: CHAIN_ID.local, + } as unknown as Network); + } + const isV5TT = titleEscrowVersion === 'v5'; + const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + + beforeEach(() => { + vi.clearAllMocks(); + vi.spyOn(coreModule, 'getTitleEscrowAddress').mockResolvedValue(titleEscrowAddress); + vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2)); + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( + async ({ versionInterface }) => { + return versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'); + }, + ); + mockV5TitleEscrowContract.callStatic.returnToIssuer.mockResolvedValue(true); + mockV4TitleEscrowContract.callStatic.surrender.mockResolvedValue(true); + }); + + it('should return to issuer with signer and remarks', async () => { + const result = await returnToIssuer( + { + titleEscrowAddress, + }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); + expect( + (isV5TT ? v5Contracts : v4Contracts).TitleEscrow__factory.connect, + ).toHaveBeenCalled(); + }); + + it('should return to issuer without remarks', async () => { + const result = await returnToIssuer( + { titleEscrowAddress }, + wallet, + {}, + { chainId: mockChainId }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw when callStatic fails', async () => { + if (isV5TT) { + mockV5TitleEscrowContract.callStatic.returnToIssuer.mockRejectedValue( + new Error('Simulated failure'), + ); + } else { + mockV4TitleEscrowContract.callStatic.surrender.mockRejectedValue( + new Error('Simulated failure'), + ); + } + + await expect( + returnToIssuer( + { tokenRegistryAddress: mockTokenRegistryAddress, tokenId: mockTokenId }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for returnToIssuer failed'); + if (isV5TT) { + mockV5TitleEscrowContract.callStatic.returnToIssuer = vi.fn(); + } else { + mockV4TitleEscrowContract.callStatic.surrender = vi.fn(); + } + }); + it('should throw error when provider is missing', async () => { + const signerWithoutProvider = isV5TT + ? new WalletV5('0x'.padEnd(66, '1')) + : new WalletV6('0x'.padEnd(66, '1')); + + await expect( + returnToIssuer( + { tokenRegistryAddress: mockTokenRegistryAddress, tokenId: mockTokenId }, + signerWithoutProvider, + {}, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw when version is unsupported', async () => { + vi.spyOn(coreModule, 'isTitleEscrowVersion').mockResolvedValue(false); + + await expect( + returnToIssuer( + { tokenRegistryAddress: mockTokenRegistryAddress, tokenId: mockTokenId }, + wallet, + {}, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Only Token Registry V4/V5 is supported'); + }); + + it('should work with explicit version', async () => { + const result = await returnToIssuer( + { tokenRegistryAddress: mockTokenRegistryAddress, tokenId: mockTokenId }, + wallet, + { remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.isTitleEscrowVersion).not.toHaveBeenCalled(); + }); + }, + ); + + describe.each(providers)( + 'Reject Return Token with TR version $titleEscrowVersion and ethers version $ethersVersion', + async ({ Provider, ethersVersion, titleEscrowVersion }) => { + const isV5TT = titleEscrowVersion === 'v5'; + // let mockContract = isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract; + const mockTxResponse = + titleEscrowVersion === 'v5' ? 'v5_restore_tx_hash' : 'v4_restore_tx_hash'; + + let wallet: ethersV5.Wallet | ethersV6.Wallet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.local as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: CHAIN_ID.local, + } as unknown as Network); + } + const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; + // const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + beforeEach(() => { + vi.clearAllMocks(); + // vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2)); + vi.spyOn(coreModule, 'checkSupportsInterface').mockImplementation( + async (address, interfaceId) => { + return ( + interfaceId === + (isV5TT ? '0xTradeTrustTokenRestorableIdV5' : '0xTradeTrustTokenRestorableIdV4') + ); + }, + ); + mockV5TradeTrustTokenContract.callStatic.restore.mockResolvedValue(true); + mockV4TradeTrustTokenContract.callStatic.restore.mockResolvedValue(true); + }); + + it('should reject returned token with remarks', async () => { + const result = await rejectReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId, remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual(mockTxResponse); + if (isV5TT) expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); + expect( + (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, + ).toHaveBeenCalled(); + }); + + it('should reject returned token without remarks', async () => { + const result = await rejectReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId, titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw when callStatic fails', async () => { + const mockError = new Error('callStatic error'); + if (isV5TT) { + mockV5TradeTrustTokenContract.callStatic.restore.mockRejectedValue(mockError); + } else { + mockV4TradeTrustTokenContract.callStatic.restore.mockRejectedValue(mockError); + } + await expect( + rejectReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId, remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for rejectReturned failed'); + if (isV5TT) { + mockV5TradeTrustTokenContract.callStatic.restore = vi.fn(); + } else { + mockV4TradeTrustTokenContract.callStatic.restore = vi.fn(); + } + }); + + it('should throw when token registry address is missing', async () => { + await expect( + rejectReturned( + { tokenRegistryAddress: '' }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + rejectReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + signerWithoutProvider, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw when version is unsupported', async () => { + vi.spyOn(coreModule, 'checkSupportsInterface').mockResolvedValue(false); + + await expect( + rejectReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Only Token Registry V4/V5 is supported'); + }); + + it('should work with explicit V5/V4 version', async () => { + const result = await rejectReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId, remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.checkSupportsInterface).not.toHaveBeenCalled(); + }); + }, + ); + + describe.each(providers)( + 'Accept Return Token with TR version $titleEscrowVersion and ethers version $ethersVersion', + async ({ Provider, ethersVersion, titleEscrowVersion }) => { + const isV5TT = titleEscrowVersion === 'v5'; + // let mockContract = isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract; + const mockTxResponse = titleEscrowVersion === 'v5' ? 'v5_burn_tx_hash' : 'v4_burn_tx_hash'; + + let wallet: ethersV5.Wallet | ethersV6.Wallet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.local as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: CHAIN_ID.local, + } as unknown as Network); + } + const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; + // const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + beforeEach(() => { + vi.clearAllMocks(); + + vi.spyOn(coreModule, 'checkSupportsInterface').mockImplementation( + async (address, interfaceId) => { + return ( + interfaceId === + (isV5TT ? '0xTradeTrustTokenBurnableIdV5' : '0xTradeTrustTokenBurnableIdV4') + ); + }, + ); + mockV5TradeTrustTokenContract.callStatic.burn.mockResolvedValue(true); + mockV4TradeTrustTokenContract.callStatic.burn.mockResolvedValue(true); + }); + + it('should accept returned token with remarks', async () => { + const result = await acceptReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId, remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ); + + expect(result).toEqual(mockTxResponse); + if (isV5TT) expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); + expect( + (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, + ).toHaveBeenCalled(); + }); + + it('should accept returned token without remarks', async () => { + const result = await acceptReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId, titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.encrypt).not.toHaveBeenCalled(); + }); + + it('should throw when callStatic fails', async () => { + const mockError = new Error('callStatic error'); + if (isV5TT) { + mockV5TradeTrustTokenContract.callStatic.burn.mockRejectedValue(mockError); + } else { + mockV4TradeTrustTokenContract.callStatic.burn.mockRejectedValue(mockError); + } + await expect( + acceptReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId, remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id' }, + ), + ).rejects.toThrow('Pre-check (callStatic) for acceptReturned failed'); + if (isV5TT) { + mockV5TradeTrustTokenContract.callStatic.burn = vi.fn(); + } else { + mockV4TradeTrustTokenContract.callStatic.burn = vi.fn(); + } + }); + + it('should throw when token registry address is missing', async () => { + await expect( + acceptReturned( + { tokenRegistryAddress: '' }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + acceptReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + signerWithoutProvider, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw when version is unsupported', async () => { + vi.spyOn(coreModule, 'checkSupportsInterface').mockResolvedValue(false); + + await expect( + acceptReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Only Token Registry V4/V5 is supported'); + }); + + it('should work with explicit V5/V4 version', async () => { + const result = await acceptReturned( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId, remarks: mockRemarks }, + { chainId: mockChainId, id: 'encryption-id', titleEscrowVersion }, + ); + + expect(result).toEqual(mockTxResponse); + expect(coreModule.checkSupportsInterface).not.toHaveBeenCalled(); + }); + }, + ); +}); diff --git a/src/__tests__/token-registry-functions/transfers.test.ts b/src/__tests__/token-registry-functions/transfers.test.ts index c87447c..5f1d6f4 100644 --- a/src/__tests__/token-registry-functions/transfers.test.ts +++ b/src/__tests__/token-registry-functions/transfers.test.ts @@ -1,11 +1,7 @@ +import './fixtures.js'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; -import { - ethers as ethersV6, - JsonRpcProvider as JsonRpcProviderV6, - Network, - Wallet as WalletV6, -} from 'ethersV6'; +import { ethers as ethersV6, Network, Wallet as WalletV6 } from 'ethersV6'; import * as coreModule from 'src/core'; import { encrypt } from 'src/core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; @@ -15,122 +11,14 @@ import { transferOwners, nominate, } from 'src/token-registry-functions'; - -// Mocks - -vi.mock('src/core', () => ({ - encrypt: vi.fn(() => 'encrypted_remarks'), - getTitleEscrowAddress: vi.fn(() => Promise.resolve('0xv5contract')), - isTitleEscrowVersion: vi.fn(() => Promise.resolve(true)), - TitleEscrowInterface: { - V4: '0xTitleEscrowIdV4', - V5: '0xTitleEscrowIdV5', - }, -})); - -vi.mock('src/token-registry-v5', () => { - return { - v5Contracts: { - TitleEscrow__factory: { - connect: vi.fn(() => mockV5TitleEscrowContract), - }, - TradeTrustToken__factory: { - connect: vi.fn(() => mockV5TradeTrustTokenContract), - }, - TitleEscrowFactory__factory: { - connect: vi.fn(() => mockV5TitleEscrowFactoryContract), - }, - }, - v5SupportInterfaceIds: { - TitleEscrow: '0xTitleEscrowIdV5', - TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV5', - }, - }; -}); - -vi.mock('src/token-registry-v4', () => { - return { - v4Contracts: { - TitleEscrow__factory: { - connect: vi.fn(() => mockV4TitleEscrowContract), - }, - TradeTrustToken__factory: { - connect: vi.fn(() => mockV4TradeTrustTokenContract), - }, - TitleEscrowFactory__factory: { - connect: vi.fn(() => mockV4TitleEscrowFactoryContract), - }, - v4SupportInterfaceIds: { - TitleEscrow: '0xTitleEscrowIdV4', - TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV4', - }, - }, - }; -}); - -const mockV5TitleEscrowFactoryContract = { - callStatic: { - getEscrowAddress: vi.fn(), - }, - getEscrowAddress: vi.fn(() => Promise.resolve('0xV5titleescrow')), -}; - -const mockV5TradeTrustTokenContract = { - supportsInterface: vi.fn(), - titleEscrowFactory: vi.fn(() => Promise.resolve('0xV5titleescrowfactory')), -}; - -const mockV5TitleEscrowContract = { - supportsInterface: vi.fn(), - callStatic: { - transferHolder: vi.fn(), - transferBeneficiary: vi.fn(), - transferOwners: vi.fn(), - nominate: vi.fn(), - }, - transferHolder: vi.fn(() => Promise.resolve('v5_transfer_holder_tx_hash')), - transferBeneficiary: vi.fn(() => Promise.resolve('v5_transfer_beneficiary_tx_hash')), - transferOwners: vi.fn(() => Promise.resolve('v5_transfer_owners_tx_hash')), - nominate: vi.fn(() => Promise.resolve('v5_nominate_tx_hash')), - holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), - beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), -}; - -const mockV4TitleEscrowContract = { - callStatic: { - transferHolder: vi.fn(), - transferBeneficiary: vi.fn(), - transferOwners: vi.fn(), - nominate: vi.fn(), - }, - transferHolder: vi.fn(() => Promise.resolve('v4_transfer_holder_tx_hash')), - transferBeneficiary: vi.fn(() => Promise.resolve('v4_transfer_beneficiary_tx_hash')), - transferOwners: vi.fn(() => Promise.resolve('v4_transfer_owners_tx_hash')), - nominate: vi.fn(() => Promise.resolve('v4_nominate_tx_hash')), - holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), - beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), -}; -const mockV4TitleEscrowFactoryContract = { - callStatic: { - getEscrowAddress: vi.fn(), - }, - getAddress: vi.fn(() => Promise.resolve('0xV4titleescrow')), -}; - -const mockV4TradeTrustTokenContract = { - titleEscrowFactory: vi.fn(() => Promise.resolve('0xV4titleescrowfactory')), -}; - -const PRIVATE_KEY = '0x59c6995e998f97a5a004497e5f1ebce0c16828d44b3f8d0bfa3a89d271d5b6b9'; // random local key - -const providerV5 = new ethersV5.providers.JsonRpcProvider(); -const providerV6 = new JsonRpcProviderV6(); - -interface ProviderInfo { - Provider: typeof providerV5 | typeof providerV6; - ethersVersion: 'v5' | 'v6'; - titleEscrowVersion: 'v4' | 'v5'; -} +import { ProviderInfo } from 'src/token-registry-functions/types'; +import { + mockV4TitleEscrowContract, + mockV5TitleEscrowContract, + PRIVATE_KEY, + providerV5, + providerV6, +} from './fixtures'; const providers: ProviderInfo[] = [ { @@ -189,7 +77,6 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc holderAddress: '0xholder', tokenId: 1, }; - const txHash = isV5TT ? 'v5_transfer_holder_tx_hash' : 'v4_transfer_holder_tx_hash'; it('throws error if titleEscrowAddress is missing ', async () => { @@ -529,7 +416,6 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc remarks: '0xencrypted_remarks', } : { newBeneficiaryAddress: '0xbeneficiary', newHolderAddress: '0xholder' }; - const txHash = isV5TT ? 'v5_transfer_owners_tx_hash' : 'v4_transfer_owners_tx_hash'; it('throws error if titleEscrowAddress is missing ', async () => { diff --git a/src/core/endorsement-chain/useEndorsementChain.ts b/src/core/endorsement-chain/useEndorsementChain.ts index a6b949c..14104c7 100644 --- a/src/core/endorsement-chain/useEndorsementChain.ts +++ b/src/core/endorsement-chain/useEndorsementChain.ts @@ -145,7 +145,7 @@ export const getDocumentOwner = async ( }; // Check Title Escrow Interface Support -const checkSupportsInterface = async ( +export const checkSupportsInterface = async ( titleEscrowAddress: string, interfaceId: string, provider: Provider | ethersV6.Provider, diff --git a/src/token-registry-functions/index.ts b/src/token-registry-functions/index.ts index 6de95ff..fa484d0 100644 --- a/src/token-registry-functions/index.ts +++ b/src/token-registry-functions/index.ts @@ -1 +1,4 @@ export * from './transfer'; +export * from './rejectTransfers'; +export * from './returnToken'; +export * from './mint'; diff --git a/src/token-registry-functions/mint.ts b/src/token-registry-functions/mint.ts new file mode 100644 index 0000000..0594464 --- /dev/null +++ b/src/token-registry-functions/mint.ts @@ -0,0 +1,113 @@ +import { checkSupportsInterface, encrypt } from 'src/core'; +import { v5Contracts, v5SupportInterfaceIds } from 'src/token-registry-v5'; +import { v4Contracts, v4SupportInterfaceIds } from 'src/token-registry-v4'; +import { Signer as SignerV6 } from 'ethersV6'; +import { ContractTransaction, Signer } from 'ethers'; +import { getTxOptions } from './utils'; +import { MintTokenOptions, MintTokenParams, TransactionOptions } from './types'; + +/** + * Mints a new token into the TradeTrustToken registry with the specified beneficiary and holder. + * Supports both Token Registry V4 and V5 contracts. + * @param {MintTokenOptions} contractOptions - Contains the `tokenRegistryAddress` for the minting contract. + * @param {Signer | SignerV6} signer - Signer instance (Ethers v5 or v6) that authorizes the mint transaction. + * @param {MintTokenParams} params - Parameters for minting, including `beneficiaryAddress`, `holderAddress`, `tokenId`, and optional `remarks`. + * @param {TransactionOptions} options - Transaction metadata including gas values, version detection, chain ID, and optional encryption ID. + * @returns {Promise} A promise resolving to the transaction result from the mint call. + * @throws {Error} If the token registry address or signer provider is not provided. + * @throws {Error} If neither V4 nor V5 interfaces are supported. + * @throws {Error} If the `callStatic.mint` fails as a pre-check. + */ +const mint = async ( + contractOptions: MintTokenOptions, + signer: Signer | SignerV6, + params: MintTokenParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { beneficiaryAddress, holderAddress, tokenId, remarks } = params; + + // Detect version if not explicitly provided checkSupportsInterface + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + checkSupportsInterface( + tokenRegistryAddress, + v4SupportInterfaceIds.TradeTrustTokenMintable, + signer.provider, + ), + checkSupportsInterface( + tokenRegistryAddress, + v5SupportInterfaceIds.TradeTrustTokenMintable, + signer.provider, + ), + ]); + } + + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + // Connect V5 contract by default + let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + if (isV5TT) { + tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer, + ); + } else if (isV4TT) { + tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer as Signer, + ); + } + + const encryptedRemarks = remarks && isV5TT ? `0x${encrypt(remarks, options.id!)}` : '0x'; + // Check callStatic (dry run) + try { + if (isV5TT) { + await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).callStatic.mint( + beneficiaryAddress, + holderAddress, + tokenId, + encryptedRemarks, + ); + } else if (isV4TT) { + await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).callStatic.mint( + beneficiaryAddress, + holderAddress, + tokenId, + ); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for mint failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + + if (isV5TT) { + return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).mint( + beneficiaryAddress, + holderAddress, + tokenId, + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).mint( + beneficiaryAddress, + holderAddress, + tokenId, + txOptions, + ); + } +}; +export { mint }; diff --git a/src/token-registry-functions/rejectTransfers.ts b/src/token-registry-functions/rejectTransfers.ts new file mode 100644 index 0000000..207480d --- /dev/null +++ b/src/token-registry-functions/rejectTransfers.ts @@ -0,0 +1,217 @@ +import { + encrypt, + getTitleEscrowAddress, + isTitleEscrowVersion, + TitleEscrowInterface, +} from 'src/core'; +import { v5Contracts } from 'src/token-registry-v5'; +import { Signer as SignerV6 } from 'ethersV6'; +import { ContractTransaction, Signer } from 'ethers'; +import { getTxOptions } from './utils'; +import { ContractOptions, RejectTransferParams, TransactionOptions } from './types'; + +/** + * Rejects the transfer of holder for a title escrow contract. + * @param {ContractOptions} contractOptions - Contract-related options including the token registry address, and optionally, token ID and the title escrow address. + * @param {Signer | SignerV6} signer - Ethers signer (V5 or V6) used to sign and send the transaction. + * @param {RejectTransferParams} params - Contains the `remarks` field which is an optional string that will be encrypted and sent with the transaction. + * @param {TransactionOptions} options - Transfer options including optional `chainId`, `titleEscrowVersion`, `maxFeePerGas`, `maxPriorityFeePerGas`, and an `id` used for encryption. + * @throws error if the title escrow address or signer provider is missing. + * @throws if the version is not V5 compatible. + * @throws if the dry-run (`callStatic`) fails. + * @returns {Promise} The transaction response of the rejectTransferHolder call. + */ +const rejectTransferHolder = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: RejectTransferParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress, tokenId } = contractOptions; + let { titleEscrowAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + {}, + ); + } + + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { remarks } = params; + + // Connect V5 contract by default + const titleEscrowContract = v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + let isV5TT = titleEscrowVersion === 'v5'; + if (titleEscrowVersion === undefined) { + isV5TT = await isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }); + } + + if (!isV5TT) { + throw new Error('Only Token Registry V5 is supported'); + } + + // Check callStatic (dry run) + try { + await titleEscrowContract.callStatic.rejectTransferHolder(encryptedRemarks); + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for rejectTransferHolder failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + + return await titleEscrowContract.rejectTransferHolder(encryptedRemarks, txOptions); +}; + +/** + * Rejects the transfer of beneficiary for a title escrow contract. + * @param {ContractOptions} contractOptions - Contract-related options including the token registry address, and optionally, token ID and the title escrow address. + * @param {Signer | SignerV6} signer - Ethers signer (V5 or V6) used to sign and send the transaction. + * @param {RejectTransferParams} params - Contains the `remarks` field which is an optional string that will be encrypted and sent with the transaction. + * @param {TransactionOptions} options - Transfer options including optional `chainId`, `titleEscrowVersion`, `maxFeePerGas`, `maxPriorityFeePerGas`, and an `id` used for encryption. + * @throws error if the title escrow address or signer provider is missing. + * @throws error if the version is not V5 compatible. + * @throws error if the dry-run (`callStatic`) fails. + * @returns {Promise} The transaction response of the rejectTransferBeneficiary call. + */ +const rejectTransferBeneficiary = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: RejectTransferParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress, tokenId } = contractOptions; + let { titleEscrowAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + {}, + ); + } + + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { remarks } = params; + + // Connect V5 contract by default + const titleEscrowContract = v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + let isV5TT = titleEscrowVersion === 'v5'; + if (titleEscrowVersion === undefined) { + isV5TT = await isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }); + } + + if (!isV5TT) { + throw new Error('Only Token Registry V5 is supported'); + } + + // Check callStatic (dry run) + try { + await titleEscrowContract.callStatic.rejectTransferBeneficiary(encryptedRemarks); + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for rejectTransferBeneficiary failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + + return await titleEscrowContract.rejectTransferBeneficiary(encryptedRemarks, txOptions); +}; + +/** + * Rejects the transfer of ownership for a title escrow contract. + * @param {ContractOptions} contractOptions - Contract-related options including the token registry address, and optionally, token ID and the title escrow address. + * @param {Signer | SignerV6} signer - Ethers signer (V5 or V6) used to sign and send the transaction. + * @param {RejectTransferParams} params - Contains the `remarks` field which is an optional string that will be encrypted and sent with the transaction. + * @param {TransactionOptions} options - Transfer options including optional `chainId`, `titleEscrowVersion`, `maxFeePerGas`, `maxPriorityFeePerGas`, and an `id` used for encryption. + * @throws error if the title escrow address or signer provider is missing. + * @throws an error if the version is not V5 compatible. + * @throws an error if the dry-run (`callStatic`) fails. + * @returns {Promise} The transaction response of the rejectTransferOwners call. + */ +const rejectTransferOwners = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: RejectTransferParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress, tokenId } = contractOptions; + let { titleEscrowAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + {}, + ); + } + + if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { remarks } = params; + + // Connect V5 contract by default + const titleEscrowContract = v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Detect version if not explicitly provided + let isV5TT = titleEscrowVersion === 'v5'; + if (titleEscrowVersion === undefined) { + isV5TT = await isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }); + } + + if (!isV5TT) { + throw new Error('Only Token Registry V5 is supported'); + } + + // Check callStatic (dry run) + try { + await titleEscrowContract.callStatic.rejectTransferOwners(encryptedRemarks); + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for rejectTransferOwners failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + + return await titleEscrowContract.rejectTransferOwners(encryptedRemarks, txOptions); +}; + +export { rejectTransferHolder, rejectTransferBeneficiary, rejectTransferOwners }; diff --git a/src/token-registry-functions/returnToken.ts b/src/token-registry-functions/returnToken.ts new file mode 100644 index 0000000..a7b8d0e --- /dev/null +++ b/src/token-registry-functions/returnToken.ts @@ -0,0 +1,306 @@ +import { + checkSupportsInterface, + encrypt, + getTitleEscrowAddress, + isTitleEscrowVersion, + TitleEscrowInterface, +} from 'src/core'; +import { v5Contracts, v5SupportInterfaceIds } from 'src/token-registry-v5'; +import { v4Contracts, v4SupportInterfaceIds } from 'src/token-registry-v4'; +import { Signer as SignerV6 } from 'ethersV6'; +import { ContractTransaction, Signer } from 'ethers'; +import { getTxOptions } from './utils'; +import { + AcceptReturnedOptions, + AcceptReturnedParams, + ContractOptions, + RejectReturnedOptions, + RejectReturnedParams, + ReturnToIssuerParams, + TransactionOptions, +} from './types'; + +/** + * Returns the token to the original issuer from the Title Escrow contract. + * @param {ContractOptions} contractOptions - Options including token ID, registry address, and optionally title escrow address. + * @param {Signer | SignerV6} signer - Signer instance (Ethers v5 or v6) that will execute the transaction. + * @param {ReturnToIssuerParams} params - Contains optional remarks to be encrypted and attached to the transaction. + * @param {TransactionOptions} options - Transaction settings including gas fees, escrow version, chain ID, and optional encryption ID. + * @returns {Promise} Promise that resolves to the transaction response from the `returnToIssuer` function. + * @throws {Error} If title escrow address or provider is not provided or if version is unsupported. + * @throws {Error} If the `callStatic.returnToIssuer` fails as a pre-check. + */ +const returnToIssuer = async ( + contractOptions: ContractOptions, + signer: Signer | SignerV6, + params: ReturnToIssuerParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress, tokenId } = contractOptions; + let { titleEscrowAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!titleEscrowAddress) { + titleEscrowAddress = await getTitleEscrowAddress( + tokenRegistryAddress, + tokenId as string, + signer.provider, + {}, + ); + } + + if (!titleEscrowAddress) throw new Error('Title Escrow address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { remarks } = params; + + // Connect V5 contract by default + let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + + const encryptedRemarks = remarks && options.id ? `0x${encrypt(remarks, options.id)}` : '0x'; + + // Detect version if not explicitly provided + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + await isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V4, + provider: signer.provider, + }), + await isTitleEscrowVersion({ + titleEscrowAddress, + versionInterface: TitleEscrowInterface.V5, + provider: signer.provider, + }), + ]); + } + + if (!isV5TT && !isV4TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + + if (isV4TT) { + titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + titleEscrowAddress, + signer as Signer, + ); + } + + // Check callStatic (dry run) + try { + if (isV5TT) { + await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.returnToIssuer( + encryptedRemarks, + ); + } else if (isV4TT) { + await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.surrender(); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for returnToIssuer failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + if (isV5TT) { + return await (titleEscrowContract as v5Contracts.TitleEscrow).returnToIssuer( + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await (titleEscrowContract as v4Contracts.TitleEscrow).surrender(txOptions); + } +}; + +/** + * Rejects a previously returned token by restoring it back to the token registry. + * This is only supported on Token Registry V5 contracts with the `restore` functionality. + * @param {AcceptReturnedOptions} contractOptions - Contains the `tokenRegistryAddress` used to locate the TradeTrustToken contract. + * @param {Signer | SignerV6} signer - Signer instance (v5 or v6) used to authorize the transaction. + * @param {AcceptReturnedParams} params - Includes the `tokenId` to restore and optional `remarks` to encrypt. + * @param {TransactionOptions} options - Configuration for the transaction including version, gas fees, and optional `id` used for encryption. + * @returns {Promise} A promise that resolves to the transaction result of the `restore` call. + * @throws {Error} If the token registry address or provider is missing. + * @throws {Error} If the token registry version is unsupported. + * @throws {Error} If the callStatic pre-check fails. + */ +const rejectReturned = async ( + contractOptions: AcceptReturnedOptions, + signer: Signer | SignerV6, + params: RejectReturnedParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { tokenId, remarks } = params; + + // Detect version if not explicitly provided checkSupportsInterface + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + checkSupportsInterface( + tokenRegistryAddress, + v4SupportInterfaceIds.TradeTrustTokenRestorable, + signer.provider, + ), + checkSupportsInterface( + tokenRegistryAddress, + v5SupportInterfaceIds.TradeTrustTokenRestorable, + signer.provider, + ), + ]); + } + + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + // Connect V5 contract by default + let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + if (isV5TT) { + tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer, + ); + } else if (isV4TT) { + tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer as Signer, + ); + } + + const encryptedRemarks = remarks && isV5TT ? `0x${encrypt(remarks, options.id!)}` : '0x'; + // Check callStatic (dry run) + try { + if (isV5TT) { + await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).callStatic.restore( + tokenId, + encryptedRemarks, + ); + } else if (isV4TT) { + await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).callStatic.restore(tokenId); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for rejectReturned failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + + if (isV5TT) { + return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).restore( + tokenId, + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).restore( + tokenId, + txOptions, + ); + } +}; +/** + * Accepts the returned token by burning it from the TradeTrustToken contract. + * Only supported on Token Registry V5 contracts that implement the burnable interface. + * @param {RejectReturnedOptions} contractOptions - Contains the `tokenRegistryAddress` from which the token will be burned. + * @param {Signer | SignerV6} signer - Signer instance (v5 or v6) used to authorize and send the burn transaction. + * @param {AcceptReturnedParams} params - Includes the `tokenId` to burn and optional `remarks` for audit trail. + * @param {TransactionOptions} options - Transaction settings including chain ID, gas fee values, escrow version, and encryption ID for remarks. + * @returns {Promise} A promise resolving to the transaction result of the burn call. + * @throws {Error} If token registry address or signer provider is not provided. + * @throws {Error} If the contract does not support Token Registry V5. + * @throws {Error} If `callStatic.burn` fails as a pre-check. + */ +const acceptReturned = async ( + contractOptions: RejectReturnedOptions, + signer: Signer | SignerV6, + params: AcceptReturnedParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress } = contractOptions; + const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; + + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + const { tokenId, remarks } = params; + + // Detect version if not explicitly provided checkSupportsInterface + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + checkSupportsInterface( + tokenRegistryAddress, + v4SupportInterfaceIds.TradeTrustTokenBurnable, + signer.provider, + ), + checkSupportsInterface( + tokenRegistryAddress, + v5SupportInterfaceIds.TradeTrustTokenBurnable, + signer.provider, + ), + ]); + } + + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + // Connect V5 contract by default + let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + if (isV5TT) { + tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer, + ); + } else if (isV4TT) { + tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer as Signer, + ); + } + + const encryptedRemarks = remarks && isV5TT ? `0x${encrypt(remarks, options.id!)}` : '0x'; + + // Check callStatic (dry run) + try { + if (isV5TT) { + await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).callStatic.burn( + tokenId, + encryptedRemarks, + ); + } else if (isV4TT) { + await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).callStatic.burn(tokenId); + } + } catch (e) { + console.error('callStatic failed:', e); + throw new Error('Pre-check (callStatic) for acceptReturned failed'); + } + + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + + // Send the actual transaction + + if (isV5TT) { + return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).burn( + tokenId, + encryptedRemarks, + txOptions, + ); + } else if (isV4TT) { + return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).burn(tokenId, txOptions); + } +}; + +export { returnToIssuer, acceptReturned, rejectReturned }; diff --git a/src/token-registry-functions/transfer.ts b/src/token-registry-functions/transfer.ts index 5247762..a4fa004 100644 --- a/src/token-registry-functions/transfer.ts +++ b/src/token-registry-functions/transfer.ts @@ -1,4 +1,3 @@ -import { CHAIN_ID, SUPPORTED_CHAINS } from '@tradetrust-tt/tradetrust-utils'; import { encrypt, getTitleEscrowAddress, @@ -7,74 +6,44 @@ import { } from 'src/core'; import { v4Contracts } from 'src/token-registry-v4'; import { v5Contracts } from 'src/token-registry-v5'; -import { BigNumberish, Signer as SignerV6 } from 'ethersV6'; -import { BigNumber, Signer } from 'ethers'; -import { isV6EthersProvider } from 'src/utils/ethers'; - -interface TransferHolderParams { - holderAddress: string; - remarks?: string; -} -interface TransferBeneficiaryParams { - newBeneficiaryAddress: string; - remarks?: string; -} -interface NominateParams { - newBeneficiaryAddress: string; - remarks?: string; -} -interface TransferOwnersParams { - newHolderAddress: string; - newBeneficiaryAddress: string; - remarks?: string; -} - -interface TransferOptions { - chainId?: CHAIN_ID; - titleEscrowVersion?: 'v4' | 'v5'; - maxFeePerGas?: BigNumberish | string | number | BigNumber; - maxPriorityFeePerGas?: BigNumberish | string | number | BigNumber; - id?: string; -} - -// 🔍 Handles both Ethers v5 and v6 signer types -const getChainIdSafe = async (signer: SignerV6 | Signer): Promise => { - if (isV6EthersProvider(signer.provider)) { - const network = await (signer as Signer).provider?.getNetwork(); - if (!network?.chainId) throw new Error('Cannot determine chainId: provider is missing'); - return network.chainId; - } - return await (signer as Signer).getChainId(); -}; -// const getSignerAddressSafe = async (signer: SignerV6 | Signer): Promise => { -// if (isV6EthersProvider(signer.provider)) { -// return await (signer as SignerV6).getAddress(); -// } -// return (signer as any).address; -// }; - -type ContractOptions = - | { - titleEscrowAddress: string; // Present — no restrictions on the rest - tokenId?: string | number; - tokenRegistryAddress?: string; - } - | { - titleEscrowAddress?: undefined; // Absent — must provide both below - tokenId: string | number; - tokenRegistryAddress: string; - }; - +import { Signer as SignerV6 } from 'ethersV6'; +import { ContractTransaction, Signer } from 'ethers'; +import { + ContractOptions, + NominateParams, + TransactionOptions, + TransferBeneficiaryParams, + TransferHolderParams, + TransferOwnersParams, +} from './types'; +import { getTxOptions } from './utils'; + +/** + * Transfers holder role of a Title Escrow contract to a new address. + * The caller of this function must be the current holder. + * @param {ContractOptions} contractOptions - Contains `tokenRegistryAddress` and optionally `tokenId` and `titleEscrowAddress`. + * @param {Signer | SignerV6} signer - The signer (ethers v5 or v6) who initiates the transaction. + * @param {TransferHolderParams} params - Object containing `holderAddress` (address to transfer to) and optional `remarks`. + * @param {TransactionOptions} options - Transaction options including: + * - `titleEscrowVersion` (optional): Either "v4" or "v5" + * - `chainId` (optional): Used for gas station lookup + * - `maxFeePerGas` (optional), `maxPriorityFeePerGas` (optional): EIP-1559 gas fee configuration + * - `id` (optional): ID used for encrypting remarks + * @throws If required fields like `titleEscrowAddress` or `signer.provider` are missing. + * @throws If the version is unsupported (neither v4 nor v5). + * @throws If the dry-run via `callStatic` fails. + * @returns {Promise} The transaction response for `transferHolder`. + */ const transferHolder = async ( contractOptions: ContractOptions, signer: Signer | SignerV6, params: TransferHolderParams, - options: TransferOptions, -) => { + options: TransactionOptions, +): Promise => { const { tokenRegistryAddress, tokenId } = contractOptions; const { titleEscrowVersion } = options; let { titleEscrowAddress } = contractOptions; - let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + const { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; let isV5TT = titleEscrowVersion === 'v5'; let isV4TT = titleEscrowVersion === 'v4'; @@ -153,18 +122,8 @@ const transferHolder = async ( } // If gas values are missing, query gas station if available - if (!maxFeePerGas || !maxPriorityFeePerGas) { - chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); - const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; - - if (gasStation) { - const gasFees = await gasStation(); - maxFeePerGas = gasFees?.maxFeePerGas ?? 0; - maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; - } - } - const txOptions = - maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + // Send the actual transaction if (isV5TT) { return await (titleEscrowContract as v5Contracts.TitleEscrow).transferHolder( @@ -173,20 +132,41 @@ const transferHolder = async ( txOptions, ); } else if (isV4TT) { - return await titleEscrowContract.transferHolder(holderAddress, txOptions); + return await (titleEscrowContract as v4Contracts.TitleEscrow).transferHolder( + holderAddress, + txOptions, + ); } }; +/** + * Transfers the beneficiary role of a Title Escrow contract to a new beneficiary address. + * The caller of this function must be the current holder. + * @param {ContractOptions} contractOptions - Contains `tokenRegistryAddress` and optionally `tokenId` and `titleEscrowAddress`. + * @param {Signer | SignerV6} signer - The signer (ethers v5 or v6) who initiates and signs the transaction. + * @param {TransferBeneficiaryParams} params - Object containing: + * - `newBeneficiaryAddress`: Address to which the beneficiary role is being transferred. + * - `remarks` (optional): Optional encrypted message attached with the transaction. + * @param {TransactionOptions} options - Transaction configuration options: + * - `titleEscrowVersion` (optional): Token registry version, either `'v4'` or `'v5'`. + * - `chainId` (optional): Used to query gas station info if gas fee values are missing. + * - `maxFeePerGas`(optional), `maxPriorityFeePerGas`(optional): EIP-1559 gas fee parameters. + * - `id`(optional): Used for encryption of remarks. + * @throws If required values like `titleEscrowAddress` or `signer.provider` are missing. + * @throws If the version is unsupported (neither v4 nor v5). + * @throws If the dry-run `callStatic` fails for pre-checking the transaction. + * @returns {Promise} The transaction response for the `transferBeneficiary` call. + */ const transferBeneficiary = async ( contractOptions: ContractOptions, signer: Signer | SignerV6, params: TransferBeneficiaryParams, - options: TransferOptions, -) => { + options: TransactionOptions, +): Promise => { const { tokenId, tokenRegistryAddress } = contractOptions; const { titleEscrowVersion } = options; let { titleEscrowAddress } = contractOptions; - let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + const { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; let isV5TT = titleEscrowVersion === 'v5'; let isV4TT = titleEscrowVersion === 'v4'; @@ -265,19 +245,8 @@ const transferBeneficiary = async ( } // If gas values are missing, query gas station if available - if (!maxFeePerGas || !maxPriorityFeePerGas) { - chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); - const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; - - if (gasStation) { - const gasFees = await gasStation(); - maxFeePerGas = gasFees?.maxFeePerGas ?? 0; - maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; - } - } + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); - const txOptions = - maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; // Send the actual transaction if (isV5TT) { const tx = await (titleEscrowContract as v5Contracts.TitleEscrow).transferBeneficiary( @@ -294,16 +263,36 @@ const transferBeneficiary = async ( return tx; } }; + +/** + * Transfers both the holder and beneficiary roles of a Title Escrow contract to new addresses. + * The caller of this function must be the current holder and beneficiary both. + * @param {ContractOptions} contractOptions - Contains `tokenRegistryAddress` and optionally `tokenId` and `titleEscrowAddress`. + * @param {Signer | SignerV6} signer - The signer (ethers v5 or v6) who initiates and signs the transaction. + * @param {TransferOwnersParams} params - Object containing: + * - `newBeneficiaryAddress`: The new beneficiary address. + * - `newHolderAddress`: The new holder address. + * - `remarks` (optional): Optional remarks that will be encrypted and included with the transaction. + * @param {TransactionOptions} options - Transaction configuration options: + * - `titleEscrowVersion` (optional): Token registry version, either `'v4'` or `'v5'`. + * - `chainId` (optional): Used for gas station lookup if gas fee values are not provided. + * - `maxFeePerGas`(optional), `maxPriorityFeePerGas`(optional): EIP-1559 gas fee parameters. + * - `id`(optional): Used for encrypting remarks. + * @throws If required fields like `titleEscrowAddress` or `signer.provider` are missing. + * @throws If the title escrow version is unsupported. + * @throws If the pre-check `callStatic.transferOwners` fails. + * @returns {Promise} The transaction response from the `transferOwners` call. + */ const transferOwners = async ( contractOptions: ContractOptions, signer: Signer | SignerV6, params: TransferOwnersParams, - options: TransferOptions, -) => { + options: TransactionOptions, +): Promise => { const { tokenId, tokenRegistryAddress } = contractOptions; const { titleEscrowVersion } = options; let { titleEscrowAddress } = contractOptions; - let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + const { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; let isV5TT = titleEscrowVersion === 'v5'; let isV4TT = titleEscrowVersion === 'v4'; @@ -389,19 +378,8 @@ const transferOwners = async ( } // If gas values are missing, query gas station if available - if (!maxFeePerGas || !maxPriorityFeePerGas) { - chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); - const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; - - if (gasStation) { - const gasFees = await gasStation(); - maxFeePerGas = gasFees?.maxFeePerGas ?? 0; - maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; - } - } + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); - const txOptions = - maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; // Send the actual transaction if (isV5TT) { @@ -420,16 +398,34 @@ const transferOwners = async ( } }; +/** + * Nominates a new beneficiary on the Title Escrow contract. + * The caller of this function must be the current beneficiary. + * @param {ContractOptions} contractOptions - Contains `tokenRegistryAddress` and optionally `tokenId` and `titleEscrowAddress`. + * @param {Signer | SignerV6} signer - The signer (ethers v5 or v6) who will sign and send the transaction. + * @param {NominateParams} params - Nomination parameters: + * - `newBeneficiaryAddress`: The Ethereum address to nominate as the new beneficiary. + * - `remarks` (optional): Remarks to include with the transaction (will be encrypted). + * @param {TransactionOptions} options - Transaction-level configuration: + * - `titleEscrowVersion` (optional): Specifies token registry version, either `'v4'` or `'v5'`. + * - `chainId` (optional): Chain ID used for querying gas stations if fees are not set. + * - `maxFeePerGas`(optional), `maxPriorityFeePerGas`(optional): EIP-1559-compatible gas fee settings. + * - `id`(optional): Used for encrypting the remarks string. + * @throws If required inputs like `titleEscrowAddress` or `signer.provider` are missing. + * @throws If token registry version is unsupported. + * @throws If the dry-run `callStatic.nominate()` fails. + * @returns {Promise} The transaction response from the `nominate` method. + */ const nominate = async ( contractOptions: ContractOptions, signer: Signer | SignerV6, params: NominateParams, - options: TransferOptions, -) => { + options: TransactionOptions, +): Promise => { const { tokenId, tokenRegistryAddress } = contractOptions; const { titleEscrowVersion } = options; let { titleEscrowAddress } = contractOptions; - let { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; + const { chainId, maxFeePerGas, maxPriorityFeePerGas } = options; let isV5TT = titleEscrowVersion === 'v5'; let isV4TT = titleEscrowVersion === 'v4'; @@ -504,19 +500,8 @@ const nominate = async ( } // If gas values are missing, query gas station if available - if (!maxFeePerGas || !maxPriorityFeePerGas) { - chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); - const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; - - if (gasStation) { - const gasFees = await gasStation(); - maxFeePerGas = gasFees?.maxFeePerGas ?? 0; - maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; - } - } + const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); - const txOptions = - maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; // Send the actual transaction if (isV5TT) { diff --git a/src/token-registry-functions/types.ts b/src/token-registry-functions/types.ts new file mode 100644 index 0000000..82397f4 --- /dev/null +++ b/src/token-registry-functions/types.ts @@ -0,0 +1,83 @@ +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { BigNumber, providers as providersV5 } from 'ethers'; +import { BigNumberish, Provider as ProviderV6 } from 'ethersV6'; + +export type GasValue = BigNumber | BigNumberish | string | number; + +export interface RejectTransferParams { + remarks?: string; +} +export interface ReturnToIssuerParams { + remarks?: string; +} + +export interface AcceptReturnedParams { + tokenId: string | number; + remarks?: string; +} +export interface RejectReturnedParams { + tokenId: string | number; + remarks?: string; +} + +export interface MintTokenParams { + beneficiaryAddress: string; + holderAddress: string; + tokenId: string | number; + remarks?: string; +} + +export interface TransactionOptions { + chainId?: CHAIN_ID; + titleEscrowVersion?: 'v4' | 'v5'; + maxFeePerGas?: BigNumberish | string | number | BigNumber; + maxPriorityFeePerGas?: BigNumberish | string | number | BigNumber; + id?: string; +} + +export type ContractOptions = + | { + titleEscrowAddress: string; // Present — no restrictions on the rest + tokenId?: string | number; + tokenRegistryAddress?: string; + } + | { + titleEscrowAddress?: undefined; // Absent — must provide both below + tokenId: string | number; + tokenRegistryAddress: string; + }; + +export type AcceptReturnedOptions = { + tokenRegistryAddress: string; +}; +export type RejectReturnedOptions = { + tokenRegistryAddress: string; +}; + +export type MintTokenOptions = { + tokenRegistryAddress: string; +}; + +export interface TransferHolderParams { + holderAddress: string; + remarks?: string; +} +export interface TransferBeneficiaryParams { + newBeneficiaryAddress: string; + remarks?: string; +} +export interface NominateParams { + newBeneficiaryAddress: string; + remarks?: string; +} +export interface TransferOwnersParams { + newHolderAddress: string; + newBeneficiaryAddress: string; + remarks?: string; +} + +export interface ProviderInfo { + Provider: providersV5.Provider | ProviderV6; + ethersVersion: 'v5' | 'v6'; + titleEscrowVersion: 'v4' | 'v5'; +} diff --git a/src/token-registry-functions/utils.ts b/src/token-registry-functions/utils.ts new file mode 100644 index 0000000..df031e0 --- /dev/null +++ b/src/token-registry-functions/utils.ts @@ -0,0 +1,44 @@ +import { isV6EthersProvider } from 'src/utils/ethers'; +import { GasValue } from './types'; +import { CHAIN_ID, SUPPORTED_CHAINS } from '@tradetrust-tt/tradetrust-utils'; +import { Signer } from 'ethers'; +import { Signer as SignerV6 } from 'ethersV6'; + +const getTxOptions = async ( + signer: SignerV6 | Signer, + chainId: CHAIN_ID, + maxFeePerGas: GasValue, + maxPriorityFeePerGas: GasValue, +) => { + // If gas values are missing, query gas station if available + if (!maxFeePerGas || !maxPriorityFeePerGas) { + chainId = chainId ?? ((await getChainIdSafe(signer)) as unknown as CHAIN_ID); + const gasStation = SUPPORTED_CHAINS[chainId]?.gasStation; + + if (gasStation) { + const gasFees = await gasStation(); + maxFeePerGas = gasFees?.maxFeePerGas ?? 0; + maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; + } + } + return maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; +}; + +// 🔍 Handles both Ethers v5 and v6 signer types +const getChainIdSafe = async (signer: SignerV6 | Signer): Promise => { + if (isV6EthersProvider(signer.provider)) { + const network = await (signer as SignerV6).provider?.getNetwork(); + if (!network?.chainId) throw new Error('Cannot determine chainId: provider is missing'); + return network.chainId; + } + return await (signer as Signer).getChainId(); +}; + +const getSignerAddressSafe = async (signer: SignerV6 | Signer): Promise => { + if (isV6EthersProvider(signer.provider)) { + return await (signer as SignerV6).getAddress(); + } + return await (signer as unknown as Signer).getAddress(); +}; + +export { getChainIdSafe, getTxOptions, getSignerAddressSafe }; From 81d0e3633c1b011bd2b431dbb21854ade2082312 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:24:05 +0530 Subject: [PATCH 05/14] feat: owner of function (#79) * feat: add ownerOf function * feat: add test cases * fix: update test cases for ownerof function * fix: update imports * fix: update imports --- .../token-registry-functions/fixtures.ts | 11 +- .../token-registry-functions/mint.test.ts | 14 +- .../token-registry-functions/ownerOf.test.ts | 146 ++++++++++++++++++ .../rejectTransfers.test.ts | 6 +- .../returnToken.test.ts | 10 +- .../transfers.test.ts | 8 +- .../endorsement-chain/useEndorsementChain.ts | 10 +- src/token-registry-functions/index.ts | 1 + src/token-registry-functions/mint.ts | 6 +- src/token-registry-functions/ownerOf.ts | 68 ++++++++ .../rejectTransfers.ts | 4 +- src/token-registry-functions/returnToken.ts | 6 +- src/token-registry-functions/transfer.ts | 6 +- src/token-registry-functions/types.ts | 6 + src/token-registry-functions/utils.ts | 2 +- 15 files changed, 264 insertions(+), 40 deletions(-) create mode 100644 src/__tests__/token-registry-functions/ownerOf.test.ts create mode 100644 src/token-registry-functions/ownerOf.ts diff --git a/src/__tests__/token-registry-functions/fixtures.ts b/src/__tests__/token-registry-functions/fixtures.ts index 767d804..280d26b 100644 --- a/src/__tests__/token-registry-functions/fixtures.ts +++ b/src/__tests__/token-registry-functions/fixtures.ts @@ -3,8 +3,9 @@ import { ethers as ethersV5 } from 'ethers'; import { JsonRpcProvider as JsonRpcProviderV6 } from 'ethersV6'; export const MOCK_V5_ADDRESS = '0xV5TokenRegistryContract'; export const MOCK_V4_ADDRESS = '0xV4TokenRegistryContract'; +export const MOCK_OWNER_ADDRESS = '0xowner'; -vi.mock('src/core', () => ({ +vi.mock('../../core', () => ({ encrypt: vi.fn(() => 'encrypted_remarks'), getTitleEscrowAddress: vi.fn(), isTitleEscrowVersion: vi.fn(() => Promise.resolve(true)), @@ -16,7 +17,7 @@ vi.mock('src/core', () => ({ }, })); -vi.mock('src/token-registry-v5', () => { +vi.mock('../../token-registry-v5', () => { return { v5Contracts: { TitleEscrow__factory: { @@ -34,11 +35,12 @@ vi.mock('src/token-registry-v5', () => { TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV5', TradeTrustTokenRestorable: '0xTradeTrustTokenRestorableIdV5', TradeTrustTokenBurnable: '0xTradeTrustTokenBurnableIdV5', + SBT: '0xSBTIdV5', }, }; }); -vi.mock('src/token-registry-v4', () => { +vi.mock('../../token-registry-v4', () => { return { v4Contracts: { TitleEscrow__factory: { @@ -56,6 +58,7 @@ vi.mock('src/token-registry-v4', () => { TradeTrustTokenMintable: '0xTradeTrustTokenMintableIdV4', TradeTrustTokenRestorable: '0xTradeTrustTokenRestorableIdV4', TradeTrustTokenBurnable: '0xTradeTrustTokenBurnableIdV4', + SBT: '0xSBTIdV4', }, }; }); @@ -78,6 +81,7 @@ export const mockV5TradeTrustTokenContract = { burn: vi.fn(() => Promise.resolve('v5_burn_tx_hash')), restore: vi.fn(() => Promise.resolve('v5_restore_tx_hash')), mint: vi.fn(() => Promise.resolve('v5_mint_tx_hash')), + ownerOf: vi.fn(() => Promise.resolve(MOCK_OWNER_ADDRESS)), }; export const mockV5TitleEscrowContract = { @@ -139,6 +143,7 @@ export const mockV4TradeTrustTokenContract = { burn: vi.fn(() => Promise.resolve('v4_burn_tx_hash')), restore: vi.fn(() => Promise.resolve('v4_restore_tx_hash')), mint: vi.fn(() => Promise.resolve('v4_mint_tx_hash')), + ownerOf: vi.fn(() => Promise.resolve(MOCK_OWNER_ADDRESS)), }; export const PRIVATE_KEY = '0x59c6995e998f97a5a004497e5f1ebce0c16828d44b3f8d0bfa3a89d271d5b6b9'; // random local key diff --git a/src/__tests__/token-registry-functions/mint.test.ts b/src/__tests__/token-registry-functions/mint.test.ts index b07e651..bee8c48 100644 --- a/src/__tests__/token-registry-functions/mint.test.ts +++ b/src/__tests__/token-registry-functions/mint.test.ts @@ -2,12 +2,12 @@ import './fixtures.js'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; -import * as coreModule from 'src/core'; +import * as coreModule from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; -import { v5Contracts } from 'src/token-registry-v5'; -import { v4Contracts } from 'src/token-registry-v4'; -import { mint } from 'src/token-registry-functions/mint'; +import { v5Contracts } from '../../token-registry-v5'; +import { v4Contracts } from '../../token-registry-v4'; +import { mint } from '../../token-registry-functions'; import { MOCK_V4_ADDRESS, MOCK_V5_ADDRESS, @@ -17,7 +17,7 @@ import { providerV5, providerV6, } from './fixtures.js'; -import { ProviderInfo } from 'src/token-registry-functions/types.js'; +import { ProviderInfo } from '../../token-registry-functions/types'; const providers: ProviderInfo[] = [ { @@ -55,11 +55,11 @@ describe('Mint Token', () => { let wallet: ethersV5.Wallet | ethersV6.Wallet; if (ethersVersion === 'v5') { wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; - vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.local as unknown as number); + vi.spyOn(wallet, 'getChainId').mockResolvedValue(mockChainId as unknown as number); } else { wallet = new WalletV6(PRIVATE_KEY, Provider as any); vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ - chainId: CHAIN_ID.local, + chainId: mockChainId, } as unknown as Network); } const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; diff --git a/src/__tests__/token-registry-functions/ownerOf.test.ts b/src/__tests__/token-registry-functions/ownerOf.test.ts new file mode 100644 index 0000000..898b2ef --- /dev/null +++ b/src/__tests__/token-registry-functions/ownerOf.test.ts @@ -0,0 +1,146 @@ +import './fixtures.js'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; +import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; +import * as coreModule from '../../core'; +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { ownerOf } from '../../token-registry-functions'; +import { v5Contracts } from '../../token-registry-v5'; +import { v4Contracts } from '../../token-registry-v4'; +import { + MOCK_OWNER_ADDRESS, + MOCK_V4_ADDRESS, + MOCK_V5_ADDRESS, + PRIVATE_KEY, + providerV5, + providerV6, +} from './fixtures'; +import { ProviderInfo } from '../../token-registry-functions/types'; + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v4', + }, +]; + +describe.each(providers)( + 'ownerOf function for ethers version $ethersVersion and TR version $titleEscrowVersion', + ({ Provider, ethersVersion, titleEscrowVersion }) => { + const mockTokenId = '0xTokenId'; + const mockChainId = CHAIN_ID.local; + const isV5TT = titleEscrowVersion === 'v5'; + // let mockContract = isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract; + + let wallet: ethersV5.Wallet | ethersV6.Wallet; + if (ethersVersion === 'v5') { + wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; + vi.spyOn(wallet, 'getChainId').mockResolvedValue(mockChainId as unknown as number); + } else { + wallet = new WalletV6(PRIVATE_KEY, Provider as any); + vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ + chainId: mockChainId, + } as unknown as Network); + } + const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; + + beforeEach(() => { + vi.clearAllMocks(); + vi.spyOn(coreModule, 'checkSupportsInterface').mockImplementation( + async (address, interfaceId) => { + return interfaceId === (isV5TT ? '0xSBTIdV5' : '0xSBTIdV4'); + }, + ); + }); + + // afterEach(() => { + // vi.restoreAllMocks(); + // }); + + describe('Successful Calls', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + it('should return owner for V5/v4 contract (auto-detected)', async () => { + const result = await ownerOf( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + {}, + ); + + expect(result).toBe(MOCK_OWNER_ADDRESS); + expect( + (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, + ).toHaveBeenCalled(); + }); + + it('should return owner for V5/v4 contract (explicit version)', async () => { + const result = await ownerOf( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + { titleEscrowVersion }, + ); + + expect(result).toBe(MOCK_OWNER_ADDRESS); + expect(coreModule.checkSupportsInterface).not.toHaveBeenCalled(); + }); + }); + + describe('Error Handling', () => { + it('should throw when token registry address is missing', async () => { + await expect( + ownerOf( + { tokenRegistryAddress: '' }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Token registry address is required'); + }); + + it('should throw when provider is missing', async () => { + const signerWithoutProvider = new WalletV5('0x'.padEnd(66, '1')); + + await expect( + ownerOf( + { tokenRegistryAddress: mockTokenRegistryAddress }, + signerWithoutProvider, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Provider is required'); + }); + + it('should throw when version is unsupported', async () => { + vi.spyOn(coreModule, 'checkSupportsInterface').mockResolvedValue(false); + + await expect( + ownerOf( + { tokenRegistryAddress: mockTokenRegistryAddress }, + wallet, + { tokenId: mockTokenId }, + { chainId: mockChainId }, + ), + ).rejects.toThrow('Only Token Registry V4/V5 is supported'); + }); + }); + }, +); diff --git a/src/__tests__/token-registry-functions/rejectTransfers.test.ts b/src/__tests__/token-registry-functions/rejectTransfers.test.ts index 86e3c16..d4fde98 100644 --- a/src/__tests__/token-registry-functions/rejectTransfers.test.ts +++ b/src/__tests__/token-registry-functions/rejectTransfers.test.ts @@ -2,15 +2,15 @@ import './fixtures.js'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; import { ethers as ethersV6, Network, Wallet as WalletV6 } from 'ethersV6'; -import * as coreModule from 'src/core'; +import * as coreModule from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; import { rejectTransferBeneficiary, rejectTransferHolder, rejectTransferOwners, -} from 'src/token-registry-functions/rejectTransfers'; +} from '../../token-registry-functions/rejectTransfers'; import { mockV5TitleEscrowContract, PRIVATE_KEY, providerV5, providerV6 } from './fixtures'; -import { ProviderInfo } from 'src/token-registry-functions/types.js'; +import { ProviderInfo } from '../../token-registry-functions/types.js'; const providers: ProviderInfo[] = [ { diff --git a/src/__tests__/token-registry-functions/returnToken.test.ts b/src/__tests__/token-registry-functions/returnToken.test.ts index 9fd461c..56ca104 100644 --- a/src/__tests__/token-registry-functions/returnToken.test.ts +++ b/src/__tests__/token-registry-functions/returnToken.test.ts @@ -2,16 +2,16 @@ import './fixtures.js'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; -import * as coreModule from 'src/core'; +import * as coreModule from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; -import { v5Contracts } from 'src/token-registry-v5'; -import { v4Contracts } from 'src/token-registry-v4'; +import { v5Contracts } from '../../token-registry-v5'; +import { v4Contracts } from '../../token-registry-v4'; import { acceptReturned, rejectReturned, returnToIssuer, -} from 'src/token-registry-functions/returnToken'; +} from '../../token-registry-functions/returnToken'; import { MOCK_V4_ADDRESS, MOCK_V5_ADDRESS, @@ -23,7 +23,7 @@ import { providerV5, providerV6, } from './fixtures.js'; -import { ProviderInfo } from 'src/token-registry-functions/types.js'; +import { ProviderInfo } from '../../token-registry-functions/types.js'; const providers: ProviderInfo[] = [ { diff --git a/src/__tests__/token-registry-functions/transfers.test.ts b/src/__tests__/token-registry-functions/transfers.test.ts index 5f1d6f4..65c8b82 100644 --- a/src/__tests__/token-registry-functions/transfers.test.ts +++ b/src/__tests__/token-registry-functions/transfers.test.ts @@ -2,16 +2,16 @@ import './fixtures.js'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; import { ethers as ethersV6, Network, Wallet as WalletV6 } from 'ethersV6'; -import * as coreModule from 'src/core'; -import { encrypt } from 'src/core'; +import * as coreModule from '../../core'; +import { encrypt } from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; import { transferBeneficiary, transferHolder, transferOwners, nominate, -} from 'src/token-registry-functions'; -import { ProviderInfo } from 'src/token-registry-functions/types'; +} from '../../token-registry-functions'; +import { ProviderInfo } from '../../token-registry-functions/types'; import { mockV4TitleEscrowContract, mockV5TitleEscrowContract, diff --git a/src/core/endorsement-chain/useEndorsementChain.ts b/src/core/endorsement-chain/useEndorsementChain.ts index 14104c7..d5f389c 100644 --- a/src/core/endorsement-chain/useEndorsementChain.ts +++ b/src/core/endorsement-chain/useEndorsementChain.ts @@ -146,18 +146,16 @@ export const getDocumentOwner = async ( // Check Title Escrow Interface Support export const checkSupportsInterface = async ( - titleEscrowAddress: string, + contractAddress: string, interfaceId: string, provider: Provider | ethersV6.Provider, ): Promise => { try { const Contract = getEthersContractFromProvider(provider); - const titleEscrowAbi = [ - 'function supportsInterface(bytes4 interfaceId) external view returns (bool)', - ]; + const abi = ['function supportsInterface(bytes4 interfaceId) external view returns (bool)']; // eslint-disable-next-line @typescript-eslint/no-explicit-any - const titleEscrowContract = new Contract(titleEscrowAddress, titleEscrowAbi, provider as any); - return await titleEscrowContract.supportsInterface(interfaceId); + const contract = new Contract(contractAddress, abi, provider as any); + return await contract.supportsInterface(interfaceId); } catch { return false; } diff --git a/src/token-registry-functions/index.ts b/src/token-registry-functions/index.ts index fa484d0..607e167 100644 --- a/src/token-registry-functions/index.ts +++ b/src/token-registry-functions/index.ts @@ -2,3 +2,4 @@ export * from './transfer'; export * from './rejectTransfers'; export * from './returnToken'; export * from './mint'; +export * from './ownerOf'; diff --git a/src/token-registry-functions/mint.ts b/src/token-registry-functions/mint.ts index 0594464..00fea5f 100644 --- a/src/token-registry-functions/mint.ts +++ b/src/token-registry-functions/mint.ts @@ -1,6 +1,6 @@ -import { checkSupportsInterface, encrypt } from 'src/core'; -import { v5Contracts, v5SupportInterfaceIds } from 'src/token-registry-v5'; -import { v4Contracts, v4SupportInterfaceIds } from 'src/token-registry-v4'; +import { checkSupportsInterface, encrypt } from '../core'; +import { v5Contracts, v5SupportInterfaceIds } from '../token-registry-v5'; +import { v4Contracts, v4SupportInterfaceIds } from '../token-registry-v4'; import { Signer as SignerV6 } from 'ethersV6'; import { ContractTransaction, Signer } from 'ethers'; import { getTxOptions } from './utils'; diff --git a/src/token-registry-functions/ownerOf.ts b/src/token-registry-functions/ownerOf.ts new file mode 100644 index 0000000..9cd2c32 --- /dev/null +++ b/src/token-registry-functions/ownerOf.ts @@ -0,0 +1,68 @@ +import { checkSupportsInterface } from '../core'; +import { v5Contracts, v5SupportInterfaceIds } from '../token-registry-v5'; +import { v4Contracts, v4SupportInterfaceIds } from '../token-registry-v4'; +import { Signer as SignerV6 } from 'ethersV6'; +import { Signer } from 'ethers'; +import { OwnerOfTokenOptions, OwnerOfTokenParams, TransactionOptions } from './types'; + +/** + * Retrieves the owner of a given token from the TradeTrustToken contract. + * Supports both Token Registry V4 and V5 implementations. + * @param {OwnerOfTokenOptions} contractOptions - Options containing the token registry address. + * @param {Signer | SignerV6} signer - Signer instance (v5 or v6) used to query the blockchain. + * @param {OwnerOfTokenParams} params - Contains the `tokenId` of the token to query ownership for. + * @param {TransactionOptions} options - Includes the `titleEscrowVersion` and other optional metadata for interface detection. + * @returns {Promise} A promise that resolves to the owner address of the specified token. + * @throws {Error} If token registry address or signer provider is not provided. + * @throws {Error} If the token registry does not support V4 or V5 interfaces. + */ +const ownerOf = async ( + contractOptions: OwnerOfTokenOptions, + signer: Signer | SignerV6, + params: OwnerOfTokenParams, + options: TransactionOptions, +): Promise => { + const { tokenRegistryAddress } = contractOptions; + const { titleEscrowVersion } = options; + const { tokenId } = params; + + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!signer.provider) throw new Error('Provider is required'); + + // Detect version if not explicitly provided checkSupportsInterface + let isV5TT = titleEscrowVersion === 'v5'; + let isV4TT = titleEscrowVersion === 'v4'; + + if (titleEscrowVersion === undefined) { + [isV4TT, isV5TT] = await Promise.all([ + checkSupportsInterface(tokenRegistryAddress, v4SupportInterfaceIds.SBT, signer.provider), + checkSupportsInterface(tokenRegistryAddress, v5SupportInterfaceIds.SBT, signer.provider), + ]); + } + + if (!isV4TT && !isV5TT) { + throw new Error('Only Token Registry V4/V5 is supported'); + } + // Connect V5 contract by default + let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + if (isV5TT) { + tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer, + ); + } else if (isV4TT) { + tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tokenRegistryAddress, + signer as Signer, + ); + } + + // Send the actual transaction + + if (isV5TT) { + return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).ownerOf(tokenId); + } else if (isV4TT) { + return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).ownerOf(tokenId); + } +}; +export { ownerOf }; diff --git a/src/token-registry-functions/rejectTransfers.ts b/src/token-registry-functions/rejectTransfers.ts index 207480d..85023e8 100644 --- a/src/token-registry-functions/rejectTransfers.ts +++ b/src/token-registry-functions/rejectTransfers.ts @@ -3,8 +3,8 @@ import { getTitleEscrowAddress, isTitleEscrowVersion, TitleEscrowInterface, -} from 'src/core'; -import { v5Contracts } from 'src/token-registry-v5'; +} from '../core'; +import { v5Contracts } from '../token-registry-v5'; import { Signer as SignerV6 } from 'ethersV6'; import { ContractTransaction, Signer } from 'ethers'; import { getTxOptions } from './utils'; diff --git a/src/token-registry-functions/returnToken.ts b/src/token-registry-functions/returnToken.ts index a7b8d0e..3754437 100644 --- a/src/token-registry-functions/returnToken.ts +++ b/src/token-registry-functions/returnToken.ts @@ -4,9 +4,9 @@ import { getTitleEscrowAddress, isTitleEscrowVersion, TitleEscrowInterface, -} from 'src/core'; -import { v5Contracts, v5SupportInterfaceIds } from 'src/token-registry-v5'; -import { v4Contracts, v4SupportInterfaceIds } from 'src/token-registry-v4'; +} from '../core'; +import { v5Contracts, v5SupportInterfaceIds } from '../token-registry-v5'; +import { v4Contracts, v4SupportInterfaceIds } from '../token-registry-v4'; import { Signer as SignerV6 } from 'ethersV6'; import { ContractTransaction, Signer } from 'ethers'; import { getTxOptions } from './utils'; diff --git a/src/token-registry-functions/transfer.ts b/src/token-registry-functions/transfer.ts index a4fa004..4629d8f 100644 --- a/src/token-registry-functions/transfer.ts +++ b/src/token-registry-functions/transfer.ts @@ -3,9 +3,9 @@ import { getTitleEscrowAddress, isTitleEscrowVersion, TitleEscrowInterface, -} from 'src/core'; -import { v4Contracts } from 'src/token-registry-v4'; -import { v5Contracts } from 'src/token-registry-v5'; +} from '../core'; +import { v4Contracts } from '../token-registry-v4'; +import { v5Contracts } from '../token-registry-v5'; import { Signer as SignerV6 } from 'ethersV6'; import { ContractTransaction, Signer } from 'ethers'; import { diff --git a/src/token-registry-functions/types.ts b/src/token-registry-functions/types.ts index 82397f4..3af157f 100644 --- a/src/token-registry-functions/types.ts +++ b/src/token-registry-functions/types.ts @@ -26,6 +26,9 @@ export interface MintTokenParams { tokenId: string | number; remarks?: string; } +export interface OwnerOfTokenParams { + tokenId: string | number; +} export interface TransactionOptions { chainId?: CHAIN_ID; @@ -57,6 +60,9 @@ export type RejectReturnedOptions = { export type MintTokenOptions = { tokenRegistryAddress: string; }; +export type OwnerOfTokenOptions = { + tokenRegistryAddress: string; +}; export interface TransferHolderParams { holderAddress: string; diff --git a/src/token-registry-functions/utils.ts b/src/token-registry-functions/utils.ts index df031e0..63065ac 100644 --- a/src/token-registry-functions/utils.ts +++ b/src/token-registry-functions/utils.ts @@ -1,4 +1,4 @@ -import { isV6EthersProvider } from 'src/utils/ethers'; +import { isV6EthersProvider } from '../utils/ethers'; import { GasValue } from './types'; import { CHAIN_ID, SUPPORTED_CHAINS } from '@tradetrust-tt/tradetrust-utils'; import { Signer } from 'ethers'; From e0d1a775a9937a361811989897088e476f586574 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 15 Jul 2025 09:55:45 +0000 Subject: [PATCH 06/14] chore(release): 1.6.0-alpha.2 [skip ci] ## [1.6.0-alpha.2](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15) ### Features * mint function ([#78](https://github.com/TrustVC/trustvc/issues/78)) ([2ea52ce](https://github.com/TrustVC/trustvc/commit/2ea52ce2ed010ba2da095d6444f135f014dbb442)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) [#72](https://github.com/TrustVC/trustvc/issues/72) * owner of function ([#79](https://github.com/TrustVC/trustvc/issues/79)) ([81d0e36](https://github.com/TrustVC/trustvc/commit/81d0e3633c1b011bd2b431dbb21854ade2082312)) --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecfde22..ddb1913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [1.6.0-alpha.2](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15) + + +### Features + +* mint function ([#78](https://github.com/TrustVC/trustvc/issues/78)) ([2ea52ce](https://github.com/TrustVC/trustvc/commit/2ea52ce2ed010ba2da095d6444f135f014dbb442)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) [#72](https://github.com/TrustVC/trustvc/issues/72) +* owner of function ([#79](https://github.com/TrustVC/trustvc/issues/79)) ([81d0e36](https://github.com/TrustVC/trustvc/commit/81d0e3633c1b011bd2b431dbb21854ade2082312)) + ## [1.6.0-alpha.1](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.6.0-alpha.1) (2025-06-30) diff --git a/package-lock.json b/package-lock.json index 51f29bc..ca0a82f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.1", + "version": "1.6.0-alpha.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.1", + "version": "1.6.0-alpha.2", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", diff --git a/package.json b/package.json index f2c1570..c9fca25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.1", + "version": "1.6.0-alpha.2", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From 145e7630a53cac9ed26fd335aee89c2b3677ae95 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:31:57 +0530 Subject: [PATCH 07/14] chore: e2e transfers tests (#82) * feat: add ownerOf function * feat: add test cases * fix: update test cases for ownerof function * chore: add e2e test for transfer functions * chore: add e2e test for transfer functions * feat: add ownerOf function * feat: add test cases * fix: update test cases for ownerof function * chore: add e2e test for transfer functions * chore: add e2e test for transfer functions * fix: update mock tests * fix: update mock test fixtures * fix: update mock tests for mint and return * fix: update test script * fix: update imports * fix: update gitignore * fix: delete cache * fix: update imports --- .gitignore | 1 + hardhat.config.ts | 34 + package-lock.json | 2237 +++++++++++++++-- package.json | 14 +- src/__tests__/core/verify.test.ts | 2 +- src/__tests__/e2e/fixtures.ts | 123 + .../transfer.e2e.test.ts | 858 +++++++ src/__tests__/e2e/utils.ts | 56 + .../token-registry-functions/fixtures.ts | 180 +- .../token-registry-functions/mint.test.ts | 29 +- .../returnToken.test.ts | 15 + .../transfers.test.ts | 128 +- src/token-registry-functions/mint.ts | 55 +- src/token-registry-functions/transfer.ts | 204 +- src/token-registry-functions/utils.ts | 2 +- tsconfig.json | 5 +- vitest.config.ts | 8 +- 17 files changed, 3605 insertions(+), 346 deletions(-) create mode 100644 hardhat.config.ts create mode 100644 src/__tests__/e2e/fixtures.ts create mode 100644 src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts create mode 100644 src/__tests__/e2e/utils.ts diff --git a/.gitignore b/.gitignore index c3e82cc..e562349 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ dist tmp /out-tsc .coverage +cache/ # dependencies node_modules diff --git a/hardhat.config.ts b/hardhat.config.ts new file mode 100644 index 0000000..d8cb89f --- /dev/null +++ b/hardhat.config.ts @@ -0,0 +1,34 @@ +import 'tsconfig-paths/register'; +import { HardhatUserConfig } from 'hardhat/config'; +import '@nomiclabs/hardhat-ethers'; +import '@nomicfoundation/hardhat-chai-matchers'; + +const config: HardhatUserConfig = { + solidity: { + version: '0.8.20', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + networks: { + hardhat: { + chainId: 1337, + accounts: { + count: 20, + accountsBalance: '1000000000000000000000', // 1000 ETH + }, + }, + localhost: { + url: 'http://127.0.0.1:8545', + chainId: 1337, + }, + }, + mocha: { + timeout: 60000, + }, +}; + +export default config; diff --git a/package-lock.json b/package-lock.json index ca0a82f..0cfd4b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,13 +30,18 @@ "@commitlint/config-conventional": "^19.8.0", "@commitlint/config-nx-scopes": "^19.8.0", "@commitlint/prompt": "^19.8.0", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", + "@nomiclabs/hardhat-ethers": "^2.2.3", + "@openzeppelin/contracts": "^5.3.0", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/npm": "^9.0.2", "@types/conventional-commits-parser": "^5.0.1", "@types/lodash": "^4.17.16", + "@types/mocha": "^10.0.10", "@types/node": "^18.19.86", "@vitest/coverage-v8": "^1.6.1", + "concurrently": "^9.2.0", "cpy": "^11.1.0", "dotenv": "^16.5.0", "eslint": "^9.25.1", @@ -48,17 +53,20 @@ "eslint-plugin-promise": "^7.2.1", "eth-testing": "^1.14.0", "execa": "^9.5.2", + "hardhat": "^2.25.0", "husky": "^9.1.7", "lint-staged": "^15.5.1", "prettier": "^3.5.3", "rimraf": "^5.0.10", "semantic-release": "^20.1.3", "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "tsup": "^8.4.0", "typescript": "^5.8.3", "typescript-eslint": "^8.31.0", "vite-plugin-dts": "^3.9.1", - "vitest": "^1.6.1" + "vitest": "^1.6.1", + "wait-on": "^8.0.3" }, "engines": { "node": ">=18.17.0" @@ -1736,6 +1744,103 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@ethereumjs/rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz", + "integrity": "sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==", + "dev": true, + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ethereumjs/util": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-9.1.0.tgz", + "integrity": "sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==", + "dev": true, + "dependencies": { + "@ethereumjs/rlp": "^5.0.2", + "ethereum-cryptography": "^2.2.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, "node_modules/@ethersproject/abi": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", @@ -2442,6 +2547,21 @@ "node-fetch": "^2.7.0" } }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -2983,6 +3103,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3018,6 +3150,204 @@ "node": ">= 8" } }, + "node_modules/@nomicfoundation/edr": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.3.tgz", + "integrity": "sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g==", + "dev": true, + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.11.3", + "@nomicfoundation/edr-darwin-x64": "0.11.3", + "@nomicfoundation/edr-linux-arm64-gnu": "0.11.3", + "@nomicfoundation/edr-linux-arm64-musl": "0.11.3", + "@nomicfoundation/edr-linux-x64-gnu": "0.11.3", + "@nomicfoundation/edr-linux-x64-musl": "0.11.3", + "@nomicfoundation/edr-win32-x64-msvc": "0.11.3" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz", + "integrity": "sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz", + "integrity": "sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz", + "integrity": "sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz", + "integrity": "sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz", + "integrity": "sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz", + "integrity": "sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz", + "integrity": "sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz", + "integrity": "sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomiclabs/hardhat-ethers": "^2.0.0", + "chai": "^4.2.0", + "ethers": "^5.0.0", + "hardhat": "^2.9.4" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomiclabs/hardhat-ethers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz", + "integrity": "sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==", + "dev": true, + "peerDependencies": { + "ethers": "^5.0.0", + "hardhat": "^2.0.0" + } + }, "node_modules/@octokit/auth-token": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", @@ -3173,6 +3503,12 @@ "@octokit/openapi-types": "^18.0.0" } }, + "node_modules/@openzeppelin/contracts": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.3.0.tgz", + "integrity": "sha512-zj/KGoW7zxWUE8qOI++rUM18v+VeLTTzKs/DJFkSzHpQFPD/jKKF0TrMxBfGLl3kpdELCNccvB3zmofSzm4nlA==", + "dev": true + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -3662,6 +3998,15 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -4546,56 +4891,215 @@ "node": ">=10" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/core/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", "dev": true, - "engines": { - "node": ">=18" + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6" } }, - "node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "license": "Apache-2.0", + "node_modules/@sentry/hub/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" }, "engines": { - "node": ">=18.0.0" + "node": ">=6" } }, - "node_modules/@smithy/config-resolver": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.4.tgz", - "integrity": "sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==", - "license": "Apache-2.0", + "node_modules/@sentry/minimal/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, "dependencies": { - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "tslib": "^2.6.2" + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" }, "engines": { - "node": ">=18.0.0" + "node": ">=6" } }, - "node_modules/@smithy/core": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.5.3.tgz", + "node_modules/@sentry/node/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", + "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.4.tgz", + "integrity": "sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.5.3.tgz", "integrity": "sha512-xa5byV9fEguZNofCclv6v9ra0FYh5FATQW/da7FQUVTic94DfrN/NvmKZjrMyzbpqfot9ZjBaO8U1UeTbmSLuA==", "license": "Apache-2.0", "dependencies": { @@ -5438,6 +5942,30 @@ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true }, + "node_modules/@types/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, "node_modules/@types/conventional-commits-parser": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", @@ -5465,12 +5993,24 @@ "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", "dev": true }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true + }, "node_modules/@types/node": { "version": "18.19.112", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.112.tgz", @@ -5983,6 +6523,15 @@ "node": ">=0.4.0" } }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, "node_modules/aes-js": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", @@ -5992,7 +6541,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, + "devOptional": true, "dependencies": { "debug": "4" }, @@ -6044,6 +6593,24 @@ } } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -6092,6 +6659,19 @@ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "dev": true }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -6379,6 +6959,18 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bip39": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", @@ -6415,6 +7007,100 @@ "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", "license": "MIT" }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6441,6 +7127,12 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "node_modules/bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", @@ -6473,6 +7165,12 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "node_modules/builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", @@ -6494,6 +7192,15 @@ "esbuild": ">=0.18" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -6623,6 +7330,18 @@ "node": ">=4" } }, + "node_modules/chai-as-promised": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "dev": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, "node_modules/chalk": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", @@ -6677,6 +7396,12 @@ "node": ">=10" } }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -6686,6 +7411,18 @@ "node": ">=6" } }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -6899,6 +7636,12 @@ "node": ">= 0.8" } }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, "node_modules/command-line-args": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", @@ -7067,9 +7810,92 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "node_modules/concurrently": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz", + "integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", "dev": true }, @@ -7363,6 +8189,15 @@ "node": ">=16" } }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/copy-file": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-file/-/copy-file-11.0.0.tgz", @@ -7861,6 +8696,15 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "optional": true }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", @@ -8032,6 +8876,19 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "devOptional": true }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -9386,6 +10243,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -9494,6 +10360,12 @@ "node": ">=12.20.0" } }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -10094,102 +10966,412 @@ "node": ">=6" } }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "engines": { - "node": ">= 0.4" + "node_modules/hardhat": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.25.0.tgz", + "integrity": "sha512-yBiA74Yj3VnTRj7lhnn8GalvBdvsMOqTKRrRATSy/2v0VIR2hR0Jcnmfn4aQBLtGAnr3Q2c8CxL0g3LYegUp+g==", + "dev": true, + "dependencies": { + "@ethereumjs/util": "^9.1.0", + "@ethersproject/abi": "^5.1.2", + "@nomicfoundation/edr": "^0.11.1", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", + "chokidar": "^4.0.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "find-up": "^5.0.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "json-stream-stringify": "^3.1.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "micro-eth-signer": "^0.14.0", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "picocolors": "^1.1.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.8.26", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.6", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/hardhat/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" } }, - "node_modules/has-proto": { + "node_modules/hardhat/node_modules/ethereum-cryptography": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/hardhat/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/hardhat/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, "dependencies": { - "has-symbols": "^1.0.3" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6 <7 || >=8" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true + "node_modules/hardhat/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "node_modules/hardhat/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/hardhat/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "dependencies": { - "function-bind": "^1.1.2" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/he": { + "node_modules/hardhat/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hardhat/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hardhat/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/hardhat/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/hardhat/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/hardhat/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/hardhat/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", @@ -10232,6 +11414,22 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -10272,7 +11470,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, + "devOptional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -10346,6 +11544,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -10505,6 +11709,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -10559,6 +11772,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -11107,6 +12332,19 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", @@ -11192,11 +12430,32 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stream-stringify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "dev": true, + "engines": { + "node": ">=7.10.1" + } + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -11325,6 +12584,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -12053,6 +13327,12 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -12184,6 +13464,15 @@ "node": ">= 0.4" } }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/meow": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", @@ -12211,6 +13500,56 @@ "node": ">= 8" } }, + "node_modules/micro-eth-signer": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "dev": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "dev": true, + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -12344,63 +13683,372 @@ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", + "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==", + "dev": true + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "optional": true, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, "dependencies": { - "yallist": "^4.0.0" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, "engines": { "node": ">=10" } }, - "node_modules/mlly": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", - "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "node_modules/mocha/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "dependencies": { - "acorn": "^8.14.0", - "pathe": "^2.0.1", - "pkg-types": "^1.3.0", - "ufo": "^1.5.4" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", - "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==", - "dev": true - }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -12714,6 +14362,12 @@ "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", "dev": true }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", @@ -12784,7 +14438,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "optional": true, + "devOptional": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -12827,6 +14481,15 @@ "semver": "bin/semver" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -15535,6 +17198,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "dev": true + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -15687,6 +17356,12 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -16383,6 +18058,30 @@ "node": ">=8" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -16893,9 +18592,9 @@ "integrity": "sha512-3TLdfFX8YHNFOhwHrSJza6uxVBmBrEjnNQlNXvXCdItS0Pdskfg5vVXUTWIN+Y23QR09jWpSl99UHkA83m4uWA==" }, "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, "dependencies": { "tslib": "^2.1.0" @@ -17354,6 +19053,15 @@ "node": ">=8" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -17408,6 +19116,12 @@ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -17429,6 +19143,18 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -17656,6 +19382,51 @@ "node-gyp-build": "^4.3.0" } }, + "node_modules/solc": { + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", + "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/solc/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/solc/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -17674,6 +19445,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", @@ -17769,6 +19550,36 @@ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/std-env": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", @@ -18484,6 +20295,15 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", @@ -18663,11 +20483,31 @@ "integrity": "sha512-Tdu3BWzaer7R5RvBIJcg9r8HrTZgpJmsX+1meXMJzYypbkj8NK2oJN0yvm4Dp/Iv6tzFa/L5jKRmEVTga6K3nA==", "optional": true }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, "node_modules/tsup": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.4.0.tgz", @@ -19107,6 +20947,15 @@ "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -19913,6 +21762,36 @@ "typescript": "*" } }, + "node_modules/wait-on": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.3.tgz", + "integrity": "sha512-nQFqAFzZDeRxsu7S3C7LbuxslHhk+gnJZHyethuGKAn2IVleIbTB9I3vJSQiSR+DifUqmdzfPMoMPJfLqMF2vw==", + "dev": true, + "dependencies": { + "axios": "^1.8.2", + "joi": "^17.13.3", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.2" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/wait-on/node_modules/axios": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -20074,6 +21953,18 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -20109,6 +22000,12 @@ "node": ">=8" } }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -20258,6 +22155,54 @@ "node": ">=12" } }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index c9fca25..4b121a8 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,10 @@ ], "scripts": { "test": "npx vitest --run --test-timeout=15000", + "test:e2e": "concurrently -k \"npm run e2e:node\" \"npm run wait-and-test\"", + "e2e:node": "npx hardhat node", + "wait-and-test": "wait-on tcp:8545 && npm run e2e:test", + "e2e:test": "npx hardhat test src/__tests__/e2e/**/*.test.ts --network hardhat", "type-check": "tsc --noEmit", "lint": "npx eslint . --color --format=table --max-warnings=0", "lint:fix": "npx eslint . --fix", @@ -131,13 +135,18 @@ "@commitlint/config-conventional": "^19.8.0", "@commitlint/config-nx-scopes": "^19.8.0", "@commitlint/prompt": "^19.8.0", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", + "@nomiclabs/hardhat-ethers": "^2.2.3", + "@openzeppelin/contracts": "^5.3.0", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/npm": "^9.0.2", "@types/conventional-commits-parser": "^5.0.1", "@types/lodash": "^4.17.16", + "@types/mocha": "^10.0.10", "@types/node": "^18.19.86", "@vitest/coverage-v8": "^1.6.1", + "concurrently": "^9.2.0", "cpy": "^11.1.0", "dotenv": "^16.5.0", "eslint": "^9.25.1", @@ -149,17 +158,20 @@ "eslint-plugin-promise": "^7.2.1", "eth-testing": "^1.14.0", "execa": "^9.5.2", + "hardhat": "^2.25.0", "husky": "^9.1.7", "lint-staged": "^15.5.1", "prettier": "^3.5.3", "rimraf": "^5.0.10", "semantic-release": "^20.1.3", "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "tsup": "^8.4.0", "typescript": "^5.8.3", "typescript-eslint": "^8.31.0", "vite-plugin-dts": "^3.9.1", - "vitest": "^1.6.1" + "vitest": "^1.6.1", + "wait-on": "^8.0.3" }, "overrides": { "ethers": "^5.8.0" diff --git a/src/__tests__/core/verify.test.ts b/src/__tests__/core/verify.test.ts index 6fb349b..cf540cf 100644 --- a/src/__tests__/core/verify.test.ts +++ b/src/__tests__/core/verify.test.ts @@ -8,7 +8,7 @@ import { WRAPPED_DOCUMENT_DID_TOKEN_REGISTRY_V3, WRAPPED_DOCUMENT_DNS_TXT_V2, } from '../fixtures/fixtures'; -import { W3CCredentialStatusCode } from 'src/verify/fragments/document-status/w3cCredentialStatus'; +import { W3CCredentialStatusCode } from '../../verify/fragments/document-status/w3cCredentialStatus'; const providerUrl = 'https://rpc-amoy.polygon.technology'; diff --git a/src/__tests__/e2e/fixtures.ts b/src/__tests__/e2e/fixtures.ts new file mode 100644 index 0000000..fb7d327 --- /dev/null +++ b/src/__tests__/e2e/fixtures.ts @@ -0,0 +1,123 @@ +import { ethers as ethersV5 } from 'ethers'; +import { JsonRpcProvider as JsonRpcProviderV6 } from 'ethersV6'; +import { Wallet as WalletV6 } from 'ethersV6'; +// Hardhat local node URL +export const HARDHAT_RPC_URL = 'http://127.0.0.1:8545'; + +// Create ethers v5 provider for Hardhat +export const providerV5 = new ethersV5.providers.JsonRpcProvider(HARDHAT_RPC_URL); + +// Create ethers v6 provider for Hardhat +export const providerV6 = new JsonRpcProviderV6(HARDHAT_RPC_URL); + +// Utility function to create a signer with v5 provider +export const createSignerV5 = (privateKey: string) => { + return new ethersV5.Wallet(privateKey, providerV5); +}; + +// Utility function to create a signer with v6 provider +export const createSignerV6 = (privateKey: string) => { + return new WalletV6(privateKey, providerV6); +}; + +// Provider detection utilities for testing +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const getProviderVersion = (provider: any): 'v5' | 'v6' => { + // Check for v6-specific properties + if (provider._getConnection || provider.getNetwork?.length === 0) { + return 'v6'; + } + // Check for v5-specific properties + if (provider.getNetwork?.length === 1 || provider.connection) { + return 'v5'; + } + return 'v5'; // default fallback +}; + +// Mock hardhat ethers provider for testing +export const createMockHardhatProvider = (version: 'v5' | 'v6' = 'v5') => { + if (version === 'v6') { + return providerV6; + } + return providerV5; +}; + +// Generate test private keys (similar to Hardhat's approach) +const generateTestV5PrivateKeys = (count: number): string[] => { + const keys: string[] = []; + // Start with some well-known test keys (same as Hardhat) + const baseKeys = [ + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', + '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', + '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', + '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', + '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a', + '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba', + '0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e', + '0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356', + '0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97', + '0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6', + ]; + + for (let i = 0; i < count; i++) { + if (i < baseKeys.length) { + keys.push(baseKeys[i]); + } else { + // Generate additional keys if needed + const randomKey = ethersV5.Wallet.createRandom().privateKey; + keys.push(randomKey); + } + } + + return keys; +}; +const generateTestV6PrivateKeys = (count: number): string[] => { + const keys: string[] = []; + // Start with some well-known test keys (same as Hardhat) + const baseKeys = [ + '0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897', + '0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82', + '0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1', + '0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd', + '0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa', + '0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61', + '0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0', + '0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd', + '0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0', + '0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e', + ]; + + for (let i = 0; i < count; i++) { + if (i < baseKeys.length) { + keys.push(baseKeys[i]); + } else { + // Generate additional keys if needed + const randomKey = WalletV6.createRandom().privateKey; + keys.push(randomKey); + } + } + + return keys; +}; + +// Get multiple signers for ethers v5 (similar to hardhat getSigners) +export const getSignersV5 = async (count: number = 10): Promise => { + const privateKeys = generateTestV5PrivateKeys(count); + const wallets = privateKeys.map((key) => new ethersV5.Wallet(key, providerV5)); + + // Fund the wallets from Hardhat's pre-funded account + // await fundWalletsV5(wallets); + + return wallets; +}; + +// Get multiple signers for ethers v6 (similar to hardhat getSigners) +export const getSignersV6 = async (count: number = 10): Promise => { + const privateKeys = generateTestV6PrivateKeys(count); + const wallets = privateKeys.map((key) => new WalletV6(key, providerV6)); + + // Fund the wallets from Hardhat's pre-funded account + // await fundWalletsV6Simple(wallets); + + return wallets; +}; diff --git a/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts b/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts new file mode 100644 index 0000000..b8d7951 --- /dev/null +++ b/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts @@ -0,0 +1,858 @@ +import { expect } from 'chai'; +import { network } from 'hardhat'; +import { ethers as ethersV6 } from 'ethersV6'; +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; + +// Import the functions we want to test +import { + transferHolder, + transferBeneficiary, + transferOwners, + nominate, +} from '../../../token-registry-functions/transfer'; +import { mint } from '../../../token-registry-functions/mint'; +import type { + MintTokenOptions, + MintTokenParams, + TransactionOptions, + ProviderInfo, +} from '../../../token-registry-functions/types'; +import { v5Contracts } from '../../../token-registry-v5'; +import { ethers, Signer } from 'ethers'; + +// Import our new signer utilities +import { getSignersV5, getSignersV6, providerV5, providerV6 } from '../fixtures'; +import { + createContract, + getV4TitleEscrowContractFromTitleEscrowFactory, + getVersionedContractFactory, +} from '../utils'; + +interface ContractAddresses { + tokenAddress: string; + titleEscrow0: string; + titleEscrow1: string; + holder1: string; + beneficiary1: string; + holder2: string; + beneficiary2: string; +} + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v4', + }, +]; + +providers.forEach(({ Provider, ethersVersion, titleEscrowVersion }) => { + describe(`Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, async function () { + let TradeTrustTokenContract: any; + let TitleEscrowFactoryContract: any; + let titleEscrowFactoryAddress: any; + let titleEscrow0: any; + let titleEscrow1: any; + let owner: ethers.Wallet | ethersV6.Wallet; + let holder1: ethers.Wallet | ethersV6.Wallet; + let beneficiary1: ethers.Wallet | ethersV6.Wallet; + let holder2: ethers.Wallet | ethersV6.Wallet; + let beneficiary2: ethers.Wallet | ethersV6.Wallet; + let newHolder: ethers.Wallet | ethersV6.Wallet; + let newBeneficiary: ethers.Wallet | ethersV6.Wallet; + let addresses: ContractAddresses; + let tradeTrustTokenAddress: string; + + before(async function () { + await network.provider.send('evm_setAutomine', [true]); // Ensure auto-mining + await network.provider.send('hardhat_reset'); // Reset network between tests + // Reset nonce tracker for clean state (especially important for v6) + // resetNonceTracker(); + + // Get signers using our custom utility (returns ethers.Wallet[]) + // For v6, use unique private keys based on provider index to avoid nonce conflicts + const signers = ethersVersion === 'v5' ? await getSignersV5(8) : await getSignersV6(8); // Larger offset for v6 + // const signers = await hardhatEthers.getSigners(); + [owner, holder1, beneficiary1, holder2, beneficiary2, newHolder, newBeneficiary] = signers; + + // Deploy TitleEscrowFactory first + console.log('Deploying TitleEscrowFactory...'); + + const titleEscrowFactory = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + titleEscrowVersion, + owner, + ); + + TitleEscrowFactoryContract = await titleEscrowFactory.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContract.waitForDeployment(); + } else { + await TitleEscrowFactoryContract.deployTransaction.wait(); + } + + titleEscrowFactoryAddress = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContract as ethers.Contract).address + : (TitleEscrowFactoryContract as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + console.log('Deploying TradeTrustToken...'); + const tradeTrustTokenFactory = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + titleEscrowVersion, + owner, + ); + + // add a time delay here + await new Promise((resolve) => setTimeout(resolve, 1000)); + + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(owner.address, 'pending'); + TradeTrustTokenContract = await tradeTrustTokenFactory.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddress, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContract = await tradeTrustTokenFactory.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddress, + ); + // await TradeTrustTokenContract.wait(); + } + + tradeTrustTokenAddress = + ethersVersion === 'v5' + ? (TradeTrustTokenContract as ethers.Contract).address + : await (TradeTrustTokenContract as ethersV6.Contract).getAddress(); + console.log('TradeTrustToken deployed to:', tradeTrustTokenAddress); + + console.log('All mock contracts deployed and initialized for E2E testing'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + }); + + describe('Token Minting', function () { + beforeEach(async function () { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }); + it('should mint token 0 with beneficiary1 and holder1', async function () { + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary1.address, + holderAddress: holder1.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion, + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const tx1 = await mint(contractOptions, owner as unknown as Signer, params, options); + await tx1.wait(); + + // Verify token ownership + const ownerOfToken0 = await TradeTrustTokenContract.ownerOf('0'); + expect(ownerOfToken0).to.not.equal('0x0000000000000000000000000000000000000000'); + }); + + it('should mint token 1 with beneficiary2 and holder2', async function () { + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary2.address, + holderAddress: holder2.address, + tokenId: '1', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: titleEscrowVersion, + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const tx2 = await mint(contractOptions, owner as unknown as Signer, params, options); + await tx2.wait(); + + // Verify token ownership + const ownerOfToken1 = await TradeTrustTokenContract.ownerOf('1'); + expect(ownerOfToken1).to.not.equal('0x0000000000000000000000000000000000000000'); + }); + + it('should fail when trying to mint duplicate token ID', async function () { + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary1.address, + holderAddress: holder1.address, + tokenId: '0', // Same as first token - should fail + remarks: 'Duplicate mint attempt', + }; + + const options: TransactionOptions = { + titleEscrowVersion: titleEscrowVersion, + chainId: CHAIN_ID.local, + }; + + // Should revert due to duplicate token ID + try { + await mint(contractOptions, owner as unknown as Signer, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Pre-check (callStatic) for mint failed'); + } + }); + + it('should fail when minting with invalid beneficiary address', async function () { + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: '0x0000000000000000000000000000000000000000', // Invalid zero address + holderAddress: holder1.address, + tokenId: '999', + remarks: 'Invalid address test', + }; + + const options: TransactionOptions = { + titleEscrowVersion: titleEscrowVersion, + chainId: CHAIN_ID.local, + }; + + // Should revert due to invalid beneficiary address + try { + await mint(contractOptions, owner as unknown as Signer, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Pre-check (callStatic) for mint failed'); + } + }); + + it('should fail when non-owner tries to mint', async function () { + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary1.address, + holderAddress: holder1.address, + tokenId: '998', + remarks: 'Unauthorized mint attempt', + }; + + const options: TransactionOptions = { + titleEscrowVersion: titleEscrowVersion, + chainId: CHAIN_ID.local, + }; + + // Use holder1 (non-owner) as signer - should fail + try { + await mint(contractOptions, holder1 as unknown as Signer, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Pre-check (callStatic) for mint failed'); + } + }); + + it('should mint token with encrypted remarks (V5 only)', async function () { + // Skip this test for V4 as it doesn't support encrypted remarks + if (titleEscrowVersion === 'v4') { + console.log('Skipping encrypted remarks test for V4'); + this.skip(); + } + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary1.address, + holderAddress: holder1.address, + tokenId: '997', + remarks: 'This should be encrypted in V5 contracts', + }; + + const options: TransactionOptions = { + titleEscrowVersion: titleEscrowVersion, + chainId: CHAIN_ID.local, + id: 'test-encryption-key', // Enable encryption for V5 + }; + + const tx = await mint(contractOptions, owner as unknown as Signer, params, options); + await tx.wait(); + + // Verify token was created successfully + const ownerOfToken = await TradeTrustTokenContract.ownerOf('997'); + expect(ownerOfToken).to.not.equal('0x0000000000000000000000000000000000000000'); + }); + + it('should mint token without remarks', async function () { + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary2.address, + holderAddress: holder2.address, + tokenId: '996', + // No remarks property - should work fine + }; + + const options: TransactionOptions = { + titleEscrowVersion: titleEscrowVersion, + chainId: CHAIN_ID.local, + }; + + const tx = await mint(contractOptions, owner as unknown as Signer, params, options); + await tx.wait(); + + // Verify token was created successfully + const ownerOfToken = await TradeTrustTokenContract.ownerOf('996'); + expect(ownerOfToken).to.not.equal('0x0000000000000000000000000000000000000000'); + }); + + it('should set up title escrow addresses and contract instances', async function () { + // Get title escrow addresses using the factory + + const titleEscrow0Address = + titleEscrowVersion === 'v5' + ? await (TitleEscrowFactoryContract as v5Contracts.TitleEscrowFactory).getEscrowAddress( + tradeTrustTokenAddress, + '0', + ) + : await getV4TitleEscrowContractFromTitleEscrowFactory( + Provider, + TitleEscrowFactoryContract, + tradeTrustTokenAddress, + '0', + ); + + const titleEscrow1Address = + titleEscrowVersion === 'v5' + ? await (TitleEscrowFactoryContract as v5Contracts.TitleEscrowFactory).getEscrowAddress( + tradeTrustTokenAddress, + '1', + ) + : await getV4TitleEscrowContractFromTitleEscrowFactory( + Provider, + TitleEscrowFactoryContract, + tradeTrustTokenAddress, + '1', + ); + + // Get contract instances + titleEscrow0 = createContract( + titleEscrow0Address, + 'TitleEscrow', + ethersVersion, + titleEscrowVersion, + owner, + ); + + titleEscrow1 = createContract( + titleEscrow1Address, + 'TitleEscrow', + ethersVersion, + titleEscrowVersion, + owner, + ); + + // Set up addresses object for use in transfer tests + addresses = { + tokenAddress: tradeTrustTokenAddress, + titleEscrow0: titleEscrow0Address, + titleEscrow1: titleEscrow1Address, + holder1: holder1.address, + beneficiary1: beneficiary1.address, + holder2: holder2.address, + beneficiary2: beneficiary2.address, + }; + + // Verify that escrow contracts are properly connected + expect(titleEscrow0Address).to.not.equal('0x0000000000000000000000000000000000000000'); + expect(titleEscrow1Address).to.not.equal('0x0000000000000000000000000000000000000000'); + expect(addresses.tokenAddress).to.equal(tradeTrustTokenAddress); + }); + + it('should verify token registry state after minting', async function () { + // Verify specific token ownership + const token0Owner = await TradeTrustTokenContract.ownerOf('0'); + const token1Owner = await TradeTrustTokenContract.ownerOf('1'); + + expect(token0Owner).to.equal(addresses.titleEscrow0); + expect(token1Owner).to.equal(addresses.titleEscrow1); + }); + }); + + describe('Transfer Holder', function () { + it('should have correct initial state', async function () { + const initialHolder = await titleEscrow0.holder(); + const initialBeneficiary = await titleEscrow0.beneficiary(); + + expect(initialHolder).to.equal(holder1.address); + expect(initialBeneficiary).to.equal(beneficiary1.address); + }); + + it('should successfully transfer holder role from holder1 to newHolder', async function () { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + holderAddress: newHolder.address, + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Check initial state + const initialHolder = await titleEscrow0.holder(); + + expect(initialHolder).to.equal(holder1.address); + + // Execute transfer using type assertion to bypass type issues + const tx = await transferHolder(contractOptions, holder1, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow0.holder(); + expect(newHolderAddress).to.equal(newHolder.address); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should fail when non-holder tries to transfer holder role', async function () { + const tokenId = '1'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow1, + }; + + const params = { + holderAddress: newHolder.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + // Try to transfer from non-holder (should fail) + try { + await transferHolder(contractOptions, beneficiary2 as any, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Pre-check (callStatic) for transferHolder failed'); + } + }); + + it('should handle transfer without remarks', async function () { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '1', + titleEscrowAddress: addresses.titleEscrow1, + }; + + const params = { + holderAddress: newHolder.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + const tx = await transferHolder(contractOptions, holder2 as any, params, options); + await tx.wait(); + + const holderAddress = await titleEscrow1.holder(); + expect(holderAddress).to.equal(newHolder.address); + }); + }); + + describe('Nominate', function () { + it('should successfully nominate a new beneficiary', async function () { + const tokenId = '0'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + newBeneficiaryAddress: newBeneficiary.address, + remarks: 'Nominate new beneficiary', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Current beneficiary is beneficiary1, nominate from them + const tx = await nominate(contractOptions, beneficiary1 as any, params, options); + await tx.wait(); + + // Verify nominee has been set + const nominee = await titleEscrow0.nominee(); + expect(nominee).to.equal(newBeneficiary.address); + }); + + it('should fail when non-beneficiary tries to nominate', async function () { + const tokenId = '1'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow1, + }; + + const params = { + newBeneficiaryAddress: newBeneficiary.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + // Try to nominate from non-beneficiary (should fail) + // Since we don't know the exact revert reason, catch any error + try { + await nominate(contractOptions, holder2 as any, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + // Both are acceptable for this test case + expect(error.message).to.satisfy((msg: string) => { + return ( + msg.includes('Pre-check (callStatic) for nominate failed') || + msg.includes('CallerNotBeneficiary') || + msg.includes('revert') || + msg.includes('reverted') + ); + }); + } + }); + + it('should handle nomination without remarks', async function () { + const tokenId = '1'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow1, + }; + + const params = { + newBeneficiaryAddress: holder1.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + const tx = await nominate(contractOptions, beneficiary2 as any, params, options); + await tx.wait(); + + const nominee = await titleEscrow1.nominee(); + expect(nominee).to.equal(holder1.address); + }); + }); + + describe('Transfer Beneficiary', function () { + beforeEach(async function () { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }); + it('should successfully transfer beneficiary role', async function () { + const tokenId = '0'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + newBeneficiaryAddress: newBeneficiary.address, + remarks: 'Transfer beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Check initial state + const initialBeneficiary = await titleEscrow0.beneficiary(); + expect(initialBeneficiary).to.equal(beneficiary1.address); + + // Transfer beneficiary using newHolder (current holder after transferHolder test) + const tx = await transferBeneficiary(contractOptions, newHolder as any, params, options); + + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow0.beneficiary(); + expect(newBeneficiaryAddress).to.equal(newBeneficiary.address); + }); + + it('should fail when non-holder tries to transfer beneficiary', async function () { + const tokenId = '0'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + newBeneficiaryAddress: newBeneficiary.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + // Try to transfer from non-holder (should fail) + try { + await transferBeneficiary(contractOptions, beneficiary2 as any, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Pre-check (callStatic) for transferBeneficiary failed'); + } + }); + }); + + describe('transfer Owners', function () { + beforeEach(async function () { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }); + it('should successfully transfer both holder and beneficiary roles', async function () { + // Make current holder (newHolder) also the beneficiary for token 0 + const prevContractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow0, + }; + const prevParams = { + newBeneficiaryAddress: newHolder.address, + remarks: 'Nominate and endorse new beneficiary', + }; + const prevOptions = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const nominateTxn = await nominate( + prevContractOptions, + newBeneficiary as any, + prevParams, + prevOptions, + ); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await nominateTxn.wait(); + const beneficiaryTransferTxn = await transferBeneficiary( + prevContractOptions, + newHolder as any, + prevParams, + prevOptions, + ); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await beneficiaryTransferTxn.wait(); + const tokenId = '0'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + newBeneficiaryAddress: beneficiary2.address, + newHolderAddress: holder2.address, + remarks: 'Transfer both roles', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptions, newHolder as any, params, options); + await tx.wait(); + + // Verify both roles have changed + const holderAddress = await titleEscrow0.holder(); + const beneficiaryAddress = await titleEscrow0.beneficiary(); + + expect(holderAddress).to.equal(holder2.address); + expect(beneficiaryAddress).to.equal(beneficiary2.address); + }); + + it('should fail when caller is not both holder and beneficiary', async function () { + const tokenId = '1'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow1, + }; + + const params = { + newBeneficiaryAddress: newBeneficiary.address, + newHolderAddress: newHolder.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + // holder2 is holder but beneficiary2 is beneficiary (different addresses) + // Since we don't know the exact revert reason, catch any error + try { + await transferOwners(contractOptions, holder2 as any, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + // Both are acceptable for this test case + expect(error.message).to.satisfy((msg: string) => { + return ( + msg.includes('Pre-check (callStatic) for transferOwners failed') || + msg.includes('CallerNotBeneficiary') || + msg.includes('revert') || + msg.includes('reverted') + ); + }); + } + }); + }); + + describe('Error handling', function () { + it('should throw error when tokenRegistryAddress and titleEscrowAddress is missing', async function () { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + // titleEscrowAddress is intentionally missing + }; + + const params = { + holderAddress: newHolder.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + try { + await transferHolder(contractOptions, holder2 as any, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should throw error when provider is missing', async function () { + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + holderAddress: newHolder.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + }; + + try { + await transferHolder(contractOptions, signerWithoutProvider as any, params, options); + expect.fail('Expected function to throw an error'); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + }); + + describe('Gas estimation and transaction options', function () { + it('should handle custom gas options', async function () { + const tokenId = '0'; + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId, + titleEscrowAddress: addresses.titleEscrow0, + }; + + const params = { + holderAddress: holder1.address, + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + maxFeePerGas: ethers.utils.parseUnits('20', 'gwei').toHexString(), + maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei').toHexString(), + }; + + // Transfer back to holder1 from newHolder + const tx = await transferHolder(contractOptions, holder2 as any, params, options); + await tx.wait(); + + const holderAddress = await titleEscrow0.holder(); + expect(holderAddress).to.equal(holder1.address); + }); + }); + }); +}); diff --git a/src/__tests__/e2e/utils.ts b/src/__tests__/e2e/utils.ts new file mode 100644 index 0000000..4c3e8a1 --- /dev/null +++ b/src/__tests__/e2e/utils.ts @@ -0,0 +1,56 @@ +import { ethers as ethersV6, ContractRunner } from 'ethersV6'; +import { v5Contracts } from '../../token-registry-v5'; +import { v4Contracts } from '../../token-registry-v4'; +import { ethers, Signer } from 'ethers'; + +export function getVersionedContractFactory( + contractName: 'TradeTrustToken' | 'TitleEscrowFactory', + ethersVersion: 'v5' | 'v6', + titleEscrowVersion: 'v4' | 'v5', + owner: Signer | ContractRunner, +) { + const contracts = titleEscrowVersion === 'v5' ? v5Contracts : v4Contracts; + const Factory = ethersVersion === 'v5' ? ethers.ContractFactory : ethersV6.ContractFactory; + const signer = ethersVersion === 'v5' ? (owner as Signer) : (owner as ContractRunner); + + return new Factory( + contracts[`${contractName}__factory`].abi, + contracts[`${contractName}__factory`].bytecode, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); +} + +export const createContract = ( + address: string, + contractName: 'TitleEscrow' | 'TradeTrustToken', + ethersVersion: 'v5' | 'v6', + contractVersion: 'v4' | 'v5', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer: any, +) => { + const contracts = contractVersion === 'v5' ? v5Contracts : v4Contracts; + const abi = contracts[`${contractName}__factory`].abi; + + return ethersVersion === 'v5' + ? new ethers.Contract(address, abi, signer as Signer) + : new ethersV6.Contract(address, abi, signer as ContractRunner); +}; + +export const getV4TitleEscrowContractFromTitleEscrowFactory = async ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + provider: any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + titleEscrowFactory: any, + tradeTrustTokenAddress: string, + tokenId: string, +) => { + const iface = titleEscrowFactory.interface; + const encodedData = iface.encodeFunctionData('getAddress', [tradeTrustTokenAddress, tokenId]); + const result = await provider.call({ + to: titleEscrowFactory.target ?? titleEscrowFactory.address, + data: encodedData, + }); + const decodedAddress = iface.decodeFunctionResult('getAddress', result)[0]; + return decodedAddress; +}; diff --git a/src/__tests__/token-registry-functions/fixtures.ts b/src/__tests__/token-registry-functions/fixtures.ts index 280d26b..fa2bfc2 100644 --- a/src/__tests__/token-registry-functions/fixtures.ts +++ b/src/__tests__/token-registry-functions/fixtures.ts @@ -1,16 +1,26 @@ import { vi } from 'vitest'; import { ethers as ethersV5 } from 'ethers'; import { JsonRpcProvider as JsonRpcProviderV6 } from 'ethersV6'; +import * as originalModule from '../../utils/ethers'; + export const MOCK_V5_ADDRESS = '0xV5TokenRegistryContract'; export const MOCK_V4_ADDRESS = '0xV4TokenRegistryContract'; export const MOCK_OWNER_ADDRESS = '0xowner'; +vi.mock('../../utils/ethers', async (importOriginal) => { + const original = (await importOriginal()) as typeof originalModule; + + return { + ...original, // Keep all original exports + getEthersContractFromProvider: vi.fn(() => vi.fn()), // Only mock this function + }; +}); + vi.mock('../../core', () => ({ encrypt: vi.fn(() => 'encrypted_remarks'), getTitleEscrowAddress: vi.fn(), isTitleEscrowVersion: vi.fn(() => Promise.resolve(true)), checkSupportsInterface: vi.fn(), - TitleEscrowInterface: { V4: '0xTitleEscrowIdV4', V5: '0xTitleEscrowIdV5', @@ -22,12 +32,15 @@ vi.mock('../../token-registry-v5', () => { v5Contracts: { TitleEscrow__factory: { connect: vi.fn(() => mockV5TitleEscrowContract), + abi: 'TitleEscrow', }, TradeTrustToken__factory: { connect: vi.fn(() => mockV5TradeTrustTokenContract), + abi: 'TradeTrustToken', }, TitleEscrowFactory__factory: { connect: vi.fn(() => mockV5TitleEscrowFactoryContract), + abi: 'TitleEscrowFactory', }, }, v5SupportInterfaceIds: { @@ -45,12 +58,15 @@ vi.mock('../../token-registry-v4', () => { v4Contracts: { TitleEscrow__factory: { connect: vi.fn(() => mockV4TitleEscrowContract), + abi: 'TitleEscrow', }, TradeTrustToken__factory: { connect: vi.fn(() => mockV4TradeTrustTokenContract), + abi: 'TradeTrustToken', }, TitleEscrowFactory__factory: { connect: vi.fn(() => mockV4TitleEscrowFactoryContract), + abi: 'TitleEscrowFactory', }, }, v4SupportInterfaceIds: { @@ -78,9 +94,30 @@ export const mockV5TradeTrustTokenContract = { }, supportsInterface: vi.fn(), titleEscrowFactory: vi.fn(() => Promise.resolve('0xV5titleescrowfactory')), - burn: vi.fn(() => Promise.resolve('v5_burn_tx_hash')), - restore: vi.fn(() => Promise.resolve('v5_restore_tx_hash')), - mint: vi.fn(() => Promise.resolve('v5_mint_tx_hash')), + burn: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_burn_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + restore: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_restore_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + mint: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_mint_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), ownerOf: vi.fn(() => Promise.resolve(MOCK_OWNER_ADDRESS)), }; @@ -96,16 +133,72 @@ export const mockV5TitleEscrowContract = { rejectTransferOwners: vi.fn(), returnToIssuer: vi.fn(), }, - transferHolder: vi.fn(() => Promise.resolve('v5_transfer_holder_tx_hash')), - transferBeneficiary: vi.fn(() => Promise.resolve('v5_transfer_beneficiary_tx_hash')), - transferOwners: vi.fn(() => Promise.resolve('v5_transfer_owners_tx_hash')), - nominate: vi.fn(() => Promise.resolve('v5_nominate_tx_hash')), + transferHolder: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_transfer_holder_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + transferBeneficiary: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_transfer_beneficiary_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + transferOwners: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_transfer_owners_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + nominate: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_nominate_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), - rejectTransferHolder: vi.fn(() => Promise.resolve('v5_reject_transfer_holder_tx_hash')), - rejectTransferBeneficiary: vi.fn(() => Promise.resolve('v5_reject_transfer_beneficiary_tx_hash')), - rejectTransferOwners: vi.fn(() => Promise.resolve('v5_reject_transfer_owners_tx_hash')), - returnToIssuer: vi.fn(() => Promise.resolve('v5_return_to_issuer_tx_hash')), + rejectTransferHolder: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_reject_transfer_holder_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + rejectTransferBeneficiary: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_reject_transfer_beneficiary_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + rejectTransferOwners: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_reject_transfer_owners_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + returnToIssuer: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v5_return_to_issuer_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), }; export const mockV4TitleEscrowContract = { @@ -117,10 +210,38 @@ export const mockV4TitleEscrowContract = { nominate: vi.fn(), surrender: vi.fn(), }, - transferHolder: vi.fn(() => Promise.resolve('v4_transfer_holder_tx_hash')), - transferBeneficiary: vi.fn(() => Promise.resolve('v4_transfer_beneficiary_tx_hash')), - transferOwners: vi.fn(() => Promise.resolve('v4_transfer_owners_tx_hash')), - nominate: vi.fn(() => Promise.resolve('v4_nominate_tx_hash')), + transferHolder: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_transfer_holder_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + transferBeneficiary: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_transfer_beneficiary_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + transferOwners: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_transfer_owners_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + nominate: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_nominate_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), surrender: vi.fn(() => Promise.resolve('v4_surrender_tx_hash')), @@ -140,9 +261,30 @@ export const mockV4TradeTrustTokenContract = { }, titleEscrowFactory: vi.fn(() => Promise.resolve('0xV4titleescrowfactory')), supportsInterface: vi.fn(), - burn: vi.fn(() => Promise.resolve('v4_burn_tx_hash')), - restore: vi.fn(() => Promise.resolve('v4_restore_tx_hash')), - mint: vi.fn(() => Promise.resolve('v4_mint_tx_hash')), + burn: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_burn_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + restore: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_restore_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), + mint: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_mint_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), ownerOf: vi.fn(() => Promise.resolve(MOCK_OWNER_ADDRESS)), }; diff --git a/src/__tests__/token-registry-functions/mint.test.ts b/src/__tests__/token-registry-functions/mint.test.ts index bee8c48..ebac886 100644 --- a/src/__tests__/token-registry-functions/mint.test.ts +++ b/src/__tests__/token-registry-functions/mint.test.ts @@ -5,8 +5,6 @@ import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; import * as coreModule from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; -import { v5Contracts } from '../../token-registry-v5'; -import { v4Contracts } from '../../token-registry-v4'; import { mint } from '../../token-registry-functions'; import { MOCK_V4_ADDRESS, @@ -18,6 +16,7 @@ import { providerV6, } from './fixtures.js'; import { ProviderInfo } from '../../token-registry-functions/types'; +import { getEthersContractFromProvider } from '../../utils/ethers/index.js'; const providers: ProviderInfo[] = [ { @@ -66,6 +65,18 @@ describe('Mint Token', () => { const mockBeneficiaryAddress = '0xBeneficiaryAddress'; const mockHolderAddress = '0xHolderAddress'; // const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + const mockTradeTrustTokenContract = isV5TT + ? mockV5TradeTrustTokenContract + : mockV4TradeTrustTokenContract; + beforeAll(() => { + // Clear any existing mocks first + vi.clearAllMocks(); + const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); + // Only set up the mock if it hasn't been set up yet + vi.mocked(getEthersContractFromProvider).mockReturnValue( + mockContractConstructor(mockTradeTrustTokenContract), + ); + }); beforeEach(() => { vi.clearAllMocks(); // vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2)); @@ -77,8 +88,8 @@ describe('Mint Token', () => { ); }, ); - mockV5TradeTrustTokenContract.callStatic.mint.mockResolvedValue(true); - mockV4TradeTrustTokenContract.callStatic.mint.mockResolvedValue(true); + mockTradeTrustTokenContract.callStatic.mint.mockResolvedValue(true); + mockTradeTrustTokenContract.mint.staticCall.mockResolvedValue(true); }); it('should Mint token with remarks', async () => { @@ -96,9 +107,6 @@ describe('Mint Token', () => { expect(result).toEqual(mockTxResponse); if (isV5TT) expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); - expect( - (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, - ).toHaveBeenCalled(); }); it('should mint token without remarks', async () => { @@ -119,11 +127,8 @@ describe('Mint Token', () => { it('should throw when callStatic fails', async () => { const mockError = new Error('callStatic error'); - if (isV5TT) { - mockV5TradeTrustTokenContract.callStatic.mint.mockRejectedValue(mockError); - } else { - mockV4TradeTrustTokenContract.callStatic.mint.mockRejectedValue(mockError); - } + mockTradeTrustTokenContract.callStatic.mint.mockRejectedValue(mockError); + mockTradeTrustTokenContract.mint.staticCall.mockRejectedValue(mockError); await expect( mint( { tokenRegistryAddress: mockTokenRegistryAddress }, diff --git a/src/__tests__/token-registry-functions/returnToken.test.ts b/src/__tests__/token-registry-functions/returnToken.test.ts index 56ca104..7ed81b2 100644 --- a/src/__tests__/token-registry-functions/returnToken.test.ts +++ b/src/__tests__/token-registry-functions/returnToken.test.ts @@ -24,6 +24,7 @@ import { providerV6, } from './fixtures.js'; import { ProviderInfo } from '../../token-registry-functions/types.js'; +import { getEthersContractFromProvider } from '../../utils/ethers/index.js'; const providers: ProviderInfo[] = [ { @@ -70,8 +71,22 @@ describe('Return Token', () => { } as unknown as Network); } const isV5TT = titleEscrowVersion === 'v5'; + const mockTitleEscrowContract = isV5TT + ? mockV5TitleEscrowContract + : mockV4TitleEscrowContract; const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + // Handle both v5 and v6 contract constructors + beforeAll(() => { + // Clear any existing mocks first + vi.clearAllMocks(); + const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); + // Only set up the mock if it hasn't been set up yet + vi.mocked(getEthersContractFromProvider).mockReturnValue( + mockContractConstructor(mockTitleEscrowContract), + ); + }); + beforeEach(() => { vi.clearAllMocks(); vi.spyOn(coreModule, 'getTitleEscrowAddress').mockResolvedValue(titleEscrowAddress); diff --git a/src/__tests__/token-registry-functions/transfers.test.ts b/src/__tests__/token-registry-functions/transfers.test.ts index 65c8b82..86d9faa 100644 --- a/src/__tests__/token-registry-functions/transfers.test.ts +++ b/src/__tests__/token-registry-functions/transfers.test.ts @@ -1,41 +1,59 @@ import './fixtures.js'; -import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { vi, describe, beforeAll, it, expect } from 'vitest'; import { ethers as ethersV5, Wallet as WalletV5 } from 'ethers'; import { ethers as ethersV6, Network, Wallet as WalletV6 } from 'ethersV6'; import * as coreModule from '../../core'; import { encrypt } from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; import { + nominate, transferBeneficiary, transferHolder, transferOwners, - nominate, } from '../../token-registry-functions'; -import { ProviderInfo } from '../../token-registry-functions/types'; + import { mockV4TitleEscrowContract, mockV5TitleEscrowContract, PRIVATE_KEY, providerV5, providerV6, -} from './fixtures'; - -const providers: ProviderInfo[] = [ +} from './fixtures.js'; +import { getEthersContractFromProvider } from '../../utils/ethers/index.js'; + +// Mock core module +vi.mock('../../core', () => ({ + __esModule: true, + ...vi.importActual('../../core'), + encrypt: vi.fn(() => 'encrypted_remarks'), +})); + +// Mock gas station +vi.mock('../../core/gas-station', () => ({ + getGasStation: vi.fn(), +})); + +// Mock gas station options +vi.mock('../../core/gas-station/mock', () => ({ + getGasOptions: vi.fn(), +})); + +const providers: any[] = [ { Provider: providerV5, ethersVersion: 'v5', titleEscrowVersion: 'v5', }, - { - Provider: providerV5, - ethersVersion: 'v5', - titleEscrowVersion: 'v4', - }, { Provider: providerV6, ethersVersion: 'v6', titleEscrowVersion: 'v5', }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, { Provider: providerV6, ethersVersion: 'v6', @@ -43,30 +61,31 @@ const providers: ProviderInfo[] = [ }, ]; describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEscrowVersion }) => { - beforeEach(() => { - vi.clearAllMocks(); - }); let wallet: ethersV5.Wallet | ethersV6.Wallet; if (ethersVersion === 'v5') { wallet = new WalletV5(PRIVATE_KEY, Provider as any) as ethersV5.Wallet; - // wallet = { - // ...wallet, - // address: '0xcurrent_holder', - // getChainId: vi.fn().mockResolvedValue(CHAIN_ID.mainnet as unknown as number), - // } as any; vi.spyOn(wallet, 'getChainId').mockResolvedValue(CHAIN_ID.mainnet as unknown as number); } else { wallet = new WalletV6(PRIVATE_KEY, Provider as any); vi.spyOn(Provider, 'getNetwork').mockResolvedValue({ chainId: CHAIN_ID.mainnet, } as unknown as Network); - // vi.spyOn(wallet, 'getAddress').mockResolvedValue('0xcurrent_holder'); } const isV5TT = titleEscrowVersion === 'v5'; const mockTitleEscrowContract = isV5TT ? mockV5TitleEscrowContract : mockV4TitleEscrowContract; const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; - describe(`transfer holder with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + // Handle both v5 and v6 contract constructors + beforeAll(() => { + // Clear any existing mocks first + vi.clearAllMocks(); + const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); + // Only set up the mock if it hasn't been set up yet + vi.mocked(getEthersContractFromProvider).mockReturnValue( + mockContractConstructor(mockTitleEscrowContract), + ); + }); + describe(`transfer holder with TR Version ${titleEscrowVersion} and ethers version ${ethersVersion}`, () => { const params = isV5TT ? { holderAddress: '0xholder', @@ -111,9 +130,7 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc ); if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); - const resultOptions = isV5TT - ? ['0xholder', '0xencrypted_remarks', undefined] - : ['0xholder', undefined]; + const resultOptions = isV5TT ? ['0xholder', '0xencrypted_remarks', {}] : ['0xholder', {}]; expect(mockTitleEscrowContract.transferHolder).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); @@ -193,6 +210,9 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc mockTitleEscrowContract.callStatic.transferHolder.mockRejectedValue( new Error('Simulated failure'), ); + mockTitleEscrowContract.transferHolder.staticCall.mockRejectedValue( + new Error('Simulated failure'), + ); await expect( transferHolder( @@ -204,9 +224,10 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc { id: 'doc-id', titleEscrowVersion }, ), ).rejects.toThrow('Pre-check (callStatic) for transferHolder failed'); + mockTitleEscrowContract.transferHolder.staticCall.mockResolvedValue(true); }); - it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { + it('handles both v5 and v4 contracts when tokenId and tokenRegistry is provided', async () => { vi.spyOn(coreModule, 'isTitleEscrowVersion').mockImplementation( async ({ versionInterface }) => versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), @@ -228,15 +249,28 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xholder', '0xencrypted_remarks', undefined] - : ['0xholder', undefined]; + ? [ + '0xholder', + '0xencrypted_remarks', + { + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }, + ] + : [ + '0xholder', + { + maxFeePerGas: 100, + maxPriorityFeePerGas: 50, + }, + ]; expect(mockTitleEscrowContract.transferHolder).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); }); }); - describe(`transfer beneficiary with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + describe(`transfer beneficiary with TR Version ${titleEscrowVersion} and ethers version ${ethersVersion}`, () => { const params = isV5TT ? { newBeneficiaryAddress: '0xbeneficiary', remarks: '0xencrypted_remarks', tokenId: 1 } : { newBeneficiaryAddress: '0xbeneficiary', tokenId: 1 }; @@ -276,8 +310,8 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xbeneficiary', '0xencrypted_remarks', undefined] - : ['0xbeneficiary', undefined]; + ? ['0xbeneficiary', '0xencrypted_remarks', {}] + : ['0xbeneficiary', {}]; expect(mockTitleEscrowContract.transferBeneficiary).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); @@ -365,6 +399,9 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc mockTitleEscrowContract.callStatic.transferBeneficiary.mockRejectedValue( new Error('Simulated failure'), ); + mockTitleEscrowContract.transferBeneficiary.staticCall.mockRejectedValue( + new Error('Simulated failure'), + ); await expect( transferBeneficiary( @@ -376,6 +413,7 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc { id: 'doc-id', titleEscrowVersion }, ), ).rejects.toThrow('Pre-check (callStatic) for transferBeneficiary failed'); + mockTitleEscrowContract.transferBeneficiary.staticCall.mockResolvedValue(true); }); it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { @@ -400,15 +438,15 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xbeneficiary', '0xencrypted_remarks', undefined] - : ['0xbeneficiary', undefined]; + ? ['0xbeneficiary', '0xencrypted_remarks', {}] + : ['0xbeneficiary', {}]; expect(mockTitleEscrowContract.transferBeneficiary).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); }); }); - describe(`transfer owners with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + describe(`transfer owners with TR Version ${titleEscrowVersion} and ethers version ${ethersVersion}`, () => { const params = isV5TT ? { newBeneficiaryAddress: '0xbeneficiary', @@ -454,8 +492,8 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks', undefined] - : ['0xbeneficiary', '0xholder', undefined]; + ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks', {}] + : ['0xbeneficiary', '0xholder', {}]; expect(mockTitleEscrowContract.transferOwners).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); @@ -545,6 +583,9 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc mockTitleEscrowContract.callStatic.transferOwners.mockRejectedValue( new Error('Simulated failure'), ); + mockTitleEscrowContract.transferOwners.staticCall.mockRejectedValue( + new Error('Simulated failure'), + ); await expect( transferOwners( @@ -556,6 +597,7 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc { id: 'doc-id', titleEscrowVersion }, ), ).rejects.toThrow('Pre-check (callStatic) for transferOwners failed'); + mockTitleEscrowContract.transferOwners.staticCall.mockResolvedValue(true); }); it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { @@ -580,15 +622,15 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks', undefined] - : ['0xbeneficiary', '0xholder', undefined]; + ? ['0xbeneficiary', '0xholder', '0xencrypted_remarks', {}] + : ['0xbeneficiary', '0xholder', {}]; expect(mockTitleEscrowContract.transferOwners).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); }); }); - describe(`nominate with TR Version $titleEscrowVersion and ethers version $ethersVersion`, () => { + describe(`nominate with TR Version ${titleEscrowVersion} and ethers version ${ethersVersion}`, () => { const params = isV5TT ? { newBeneficiaryAddress: '0xbeneficiary', remarks: '0xencrypted_remarks', tokenId: 1 } : { newBeneficiaryAddress: '0xbeneficiary', tokenId: 1 }; @@ -628,8 +670,8 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xbeneficiary', '0xencrypted_remarks', undefined] - : ['0xbeneficiary', undefined]; + ? ['0xbeneficiary', '0xencrypted_remarks', {}] + : ['0xbeneficiary', {}]; expect(mockTitleEscrowContract.nominate).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); @@ -715,6 +757,7 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc versionInterface === (isV5TT ? '0xTitleEscrowIdV5' : '0xTitleEscrowIdV4'), ); mockTitleEscrowContract.callStatic.nominate.mockRejectedValue(new Error('Simulated failure')); + mockTitleEscrowContract.nominate.staticCall.mockRejectedValue(new Error('Simulated failure')); await expect( nominate( @@ -726,6 +769,7 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc { id: 'doc-id', titleEscrowVersion }, ), ).rejects.toThrow('Pre-check (callStatic) for nominate failed'); + mockTitleEscrowContract.nominate.staticCall.mockResolvedValue(true); }); it('handles both v5 and v4 contracts when tokenId and tokenregistry is provided', async () => { @@ -750,8 +794,8 @@ describe.each(providers)('Transfers', async ({ Provider, ethersVersion, titleEsc if (isV5TT) expect(encrypt).toHaveBeenCalledWith('0xencrypted_remarks', 'doc-id'); const resultOptions = isV5TT - ? ['0xbeneficiary', '0xencrypted_remarks', undefined] - : ['0xbeneficiary', undefined]; + ? ['0xbeneficiary', '0xencrypted_remarks', {}] + : ['0xbeneficiary', {}]; expect(mockTitleEscrowContract.nominate).toHaveBeenCalledWith(...resultOptions); expect(tx).toBe(txHash); diff --git a/src/token-registry-functions/mint.ts b/src/token-registry-functions/mint.ts index 00fea5f..78a7b91 100644 --- a/src/token-registry-functions/mint.ts +++ b/src/token-registry-functions/mint.ts @@ -1,10 +1,11 @@ import { checkSupportsInterface, encrypt } from '../core'; import { v5Contracts, v5SupportInterfaceIds } from '../token-registry-v5'; import { v4Contracts, v4SupportInterfaceIds } from '../token-registry-v4'; -import { Signer as SignerV6 } from 'ethersV6'; -import { ContractTransaction, Signer } from 'ethers'; +import { Signer as SignerV6, Contract as ContractV6 } from 'ethersV6'; +import { Contract as ContractV5, ContractTransaction, Signer } from 'ethers'; import { getTxOptions } from './utils'; import { MintTokenOptions, MintTokenParams, TransactionOptions } from './types'; +import { getEthersContractFromProvider, isV6EthersProvider } from '../utils/ethers'; /** * Mints a new token into the TradeTrustToken registry with the specified beneficiary and holder. @@ -53,48 +54,54 @@ const mint = async ( if (!isV4TT && !isV5TT) { throw new Error('Only Token Registry V4/V5 is supported'); } + const Contract = getEthersContractFromProvider(signer.provider); // Connect V5 contract by default - let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + let tradeTrustTokenContract: ContractV5 | ContractV6; if (isV5TT) { - tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tradeTrustTokenContract = new Contract( tokenRegistryAddress, - signer, + v5Contracts.TradeTrustToken__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } else if (isV4TT) { - tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tradeTrustTokenContract = new Contract( tokenRegistryAddress, - signer as Signer, + v4Contracts.TradeTrustToken__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } - const encryptedRemarks = remarks && isV5TT ? `0x${encrypt(remarks, options.id!)}` : '0x'; + const encryptedRemarks = remarks && isV5TT ? `0x${encrypt(remarks, options.id ?? '')}` : '0x'; // Check callStatic (dry run) try { - if (isV5TT) { - await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).callStatic.mint( - beneficiaryAddress, - holderAddress, - tokenId, - encryptedRemarks, - ); - } else if (isV4TT) { - await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).callStatic.mint( - beneficiaryAddress, - holderAddress, - tokenId, - ); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT + ? [beneficiaryAddress, holderAddress, tokenId, encryptedRemarks] + : [beneficiaryAddress, holderAddress, tokenId]; + + if (isV6) { + await (tradeTrustTokenContract as ContractV6).mint.staticCall(...args); + } else { + await (tradeTrustTokenContract as ContractV5).callStatic.mint(...args); } } catch (e) { console.error('callStatic failed:', e); throw new Error('Pre-check (callStatic) for mint failed'); } - const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); + const txOptions: TransactionOptions = await getTxOptions( + signer, + chainId, + maxFeePerGas, + maxPriorityFeePerGas, + ); // Send the actual transaction if (isV5TT) { - return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).mint( + return await tradeTrustTokenContract.mint( beneficiaryAddress, holderAddress, tokenId, @@ -102,7 +109,7 @@ const mint = async ( txOptions, ); } else if (isV4TT) { - return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).mint( + return await tradeTrustTokenContract.mint( beneficiaryAddress, holderAddress, tokenId, diff --git a/src/token-registry-functions/transfer.ts b/src/token-registry-functions/transfer.ts index 4629d8f..c0dc9a9 100644 --- a/src/token-registry-functions/transfer.ts +++ b/src/token-registry-functions/transfer.ts @@ -6,8 +6,8 @@ import { } from '../core'; import { v4Contracts } from '../token-registry-v4'; import { v5Contracts } from '../token-registry-v5'; -import { Signer as SignerV6 } from 'ethersV6'; -import { ContractTransaction, Signer } from 'ethers'; +import { Signer as SignerV6, Contract as ContractV6 } from 'ethersV6'; +import { Contract as ContractV5, ContractTransaction, Signer } from 'ethers'; import { ContractOptions, NominateParams, @@ -17,6 +17,7 @@ import { TransferOwnersParams, } from './types'; import { getTxOptions } from './utils'; +import { getEthersContractFromProvider, isV6EthersProvider } from '../utils/ethers'; /** * Transfers holder role of a Title Escrow contract to a new address. @@ -49,6 +50,8 @@ const transferHolder = async ( let isV4TT = titleEscrowVersion === 'v4'; if (!titleEscrowAddress) { + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!tokenId) throw new Error('Token ID is required'); titleEscrowAddress = await getTitleEscrowAddress( tokenRegistryAddress, tokenId as string, @@ -62,8 +65,8 @@ const transferHolder = async ( const { holderAddress, remarks } = params; // Connect V5 contract by default - let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = - v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + // let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + // v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; @@ -86,11 +89,22 @@ const transferHolder = async ( throw new Error('Only Token Registry V4/V5 is supported'); } - // Switch to V4 if needed - if (isV4TT) { - titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + const Contract = getEthersContractFromProvider(signer.provider); + // Connect V5 contract by default + let titleEscrowContract: ContractV5 | ContractV6; + if (isV5TT) { + titleEscrowContract = new Contract( + titleEscrowAddress, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); + } else if (isV4TT) { + titleEscrowContract = new Contract( titleEscrowAddress, - signer as Signer, + v4Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } // check for current holder and signer @@ -106,15 +120,13 @@ const transferHolder = async ( // Check callStatic (dry run) try { - if (isV5TT) { - await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.transferHolder( - holderAddress, - encryptedRemarks, - ); - } else if (isV4TT) { - await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.transferHolder( - holderAddress, - ); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [holderAddress, encryptedRemarks] : [holderAddress]; + + if (isV6) { + await (titleEscrowContract as ContractV6).transferHolder.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.transferHolder(...args); } } catch (e) { console.error('callStatic failed:', e); @@ -123,19 +135,11 @@ const transferHolder = async ( // If gas values are missing, query gas station if available const txOptions = await getTxOptions(signer, chainId, maxFeePerGas, maxPriorityFeePerGas); - // Send the actual transaction if (isV5TT) { - return await (titleEscrowContract as v5Contracts.TitleEscrow).transferHolder( - holderAddress, - encryptedRemarks, - txOptions, - ); + return await titleEscrowContract.transferHolder(holderAddress, encryptedRemarks, txOptions); } else if (isV4TT) { - return await (titleEscrowContract as v4Contracts.TitleEscrow).transferHolder( - holderAddress, - txOptions, - ); + return await titleEscrowContract.transferHolder(holderAddress, txOptions); } }; @@ -183,10 +187,6 @@ const transferBeneficiary = async ( if (!signer.provider) throw new Error('Provider is required'); const { newBeneficiaryAddress, remarks } = params; - // Connect V5 contract by default - let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = - v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); - const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; // Detect version if not explicitly provided @@ -208,11 +208,22 @@ const transferBeneficiary = async ( throw new Error('Only Token Registry V4/V5 is supported'); } - // Switch to V4 if needed - if (!isV5TT) { - titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + const Contract = getEthersContractFromProvider(signer.provider); + // Connect V5 contract by default + let titleEscrowContract: ContractV5 | ContractV6; + if (isV5TT) { + titleEscrowContract = new Contract( titleEscrowAddress, - signer as Signer, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); + } else if (isV4TT) { + titleEscrowContract = new Contract( + titleEscrowAddress, + v4Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } @@ -229,15 +240,13 @@ const transferBeneficiary = async ( // Check callStatic (dry run) try { - if (isV5TT) { - await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.transferBeneficiary( - newBeneficiaryAddress, - encryptedRemarks, - ); - } else if (isV4TT) { - await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.transferBeneficiary( - newBeneficiaryAddress, - ); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [newBeneficiaryAddress, encryptedRemarks] : [newBeneficiaryAddress]; + + if (isV6) { + await (titleEscrowContract as ContractV6).transferBeneficiary.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.transferBeneficiary(...args); } } catch (e) { console.error('callStatic failed:', e); @@ -249,18 +258,13 @@ const transferBeneficiary = async ( // Send the actual transaction if (isV5TT) { - const tx = await (titleEscrowContract as v5Contracts.TitleEscrow).transferBeneficiary( + return await titleEscrowContract.transferBeneficiary( newBeneficiaryAddress, encryptedRemarks, txOptions, ); - return tx; } else if (isV4TT) { - const tx = await (titleEscrowContract as v4Contracts.TitleEscrow).transferBeneficiary( - newBeneficiaryAddress, - txOptions, - ); - return tx; + return await titleEscrowContract.transferBeneficiary(newBeneficiaryAddress, txOptions); } }; @@ -308,10 +312,6 @@ const transferOwners = async ( if (!signer.provider) throw new Error('Provider is required'); const { newBeneficiaryAddress, newHolderAddress, remarks } = params; - // Connect V5 contract by default - let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = - v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); - const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; // Detect version if not explicitly provided @@ -333,11 +333,22 @@ const transferOwners = async ( throw new Error('Only Token Registry V4/V5 is supported'); } - // Switch to V4 if needed - if (!isV5TT) { - titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + const Contract = getEthersContractFromProvider(signer.provider); + // Connect V5 contract by default + let titleEscrowContract: ContractV5 | ContractV6; + if (isV5TT) { + titleEscrowContract = new Contract( + titleEscrowAddress, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); + } else if (isV4TT) { + titleEscrowContract = new Contract( titleEscrowAddress, - signer as Signer, + v4Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } @@ -360,17 +371,15 @@ const transferOwners = async ( // Check callStatic (dry run) try { - if (isV5TT) { - await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.transferOwners( - newBeneficiaryAddress, - newHolderAddress, - encryptedRemarks, - ); - } else if (isV4TT) { - await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.transferOwners( - newBeneficiaryAddress, - newHolderAddress, - ); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT + ? [newBeneficiaryAddress, newHolderAddress, encryptedRemarks] + : [newBeneficiaryAddress, newHolderAddress]; + + if (isV6) { + await (titleEscrowContract as ContractV6).transferOwners.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.transferOwners(...args); } } catch (e) { console.error('callStatic failed:', e); @@ -383,14 +392,14 @@ const transferOwners = async ( // Send the actual transaction if (isV5TT) { - return await (titleEscrowContract as v5Contracts.TitleEscrow).transferOwners( + return await titleEscrowContract.transferOwners( newBeneficiaryAddress, newHolderAddress, encryptedRemarks, txOptions, ); } else if (isV4TT) { - return await (titleEscrowContract as v4Contracts.TitleEscrow).transferOwners( + return await titleEscrowContract.transferOwners( newBeneficiaryAddress, newHolderAddress, txOptions, @@ -442,10 +451,6 @@ const nominate = async ( if (!signer.provider) throw new Error('Provider is required'); const { newBeneficiaryAddress, remarks } = params; - // Connect V5 contract by default - let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = - v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); - const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; // Detect version if not explicitly provided @@ -464,11 +469,22 @@ const nominate = async ( ]); } - // Switch to V4 if needed - if (!isV5TT) { - titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + const Contract = getEthersContractFromProvider(signer.provider); + // Connect V5 contract by default + let titleEscrowContract: ContractV5 | ContractV6; + if (isV5TT) { + titleEscrowContract = new Contract( titleEscrowAddress, - signer as Signer, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); + } else if (isV4TT) { + titleEscrowContract = new Contract( + titleEscrowAddress, + v4Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } @@ -482,17 +498,16 @@ const nominate = async ( // throw new Error('Cannot nominate to current beneficiary'); // } + // Check callStatic (dry run) // Check callStatic (dry run) try { - if (isV5TT) { - await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.nominate( - newBeneficiaryAddress, - encryptedRemarks, - ); - } else if (isV4TT) { - await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.nominate( - newBeneficiaryAddress, - ); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [newBeneficiaryAddress, encryptedRemarks] : [newBeneficiaryAddress]; + + if (isV6) { + await (titleEscrowContract as ContractV6).nominate.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.nominate(...args); } } catch (e) { console.error('callStatic failed:', e); @@ -505,16 +520,9 @@ const nominate = async ( // Send the actual transaction if (isV5TT) { - return await (titleEscrowContract as v5Contracts.TitleEscrow).nominate( - newBeneficiaryAddress, - encryptedRemarks, - txOptions, - ); + return await titleEscrowContract.nominate(newBeneficiaryAddress, encryptedRemarks, txOptions); } else if (isV4TT) { - return await (titleEscrowContract as v4Contracts.TitleEscrow).nominate( - newBeneficiaryAddress, - txOptions, - ); + return await titleEscrowContract.nominate(newBeneficiaryAddress, txOptions); } }; diff --git a/src/token-registry-functions/utils.ts b/src/token-registry-functions/utils.ts index 63065ac..bbfc666 100644 --- a/src/token-registry-functions/utils.ts +++ b/src/token-registry-functions/utils.ts @@ -21,7 +21,7 @@ const getTxOptions = async ( maxPriorityFeePerGas = gasFees?.maxPriorityFeePerGas ?? 0; } } - return maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : undefined; + return maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : {}; }; // 🔍 Handles both Ethers v5 and v6 signer types diff --git a/tsconfig.json b/tsconfig.json index 06eebbb..41deed1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,9 +5,12 @@ "moduleResolution": "nodenext", "experimentalDecorators": true, "emitDecoratorMetadata": true, + "types": ["vitest/globals", "mocha"], "baseUrl": ".", "rootDir": ".", - "paths": {}, + "paths": { + "src/*": ["./src/*"] + }, "resolveJsonModule": true, "allowJs": true, "checkJs": true, diff --git a/vitest.config.ts b/vitest.config.ts index 7867a67..7a76875 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -4,6 +4,11 @@ import { config } from 'dotenv'; config({ path: '.env' }); export default defineConfig({ + resolve: { + alias: { + 'src/': new URL('./src/', import.meta.url).pathname, + }, + }, define: { 'import.meta.vitest': 'undefined', }, @@ -15,6 +20,7 @@ export default defineConfig({ ], cacheDir: 'node_modules/.vitest', test: { + globals: true, include: ['**/*.test.{ts,js}'], retry: process.env.CI ? 3 : 0, // setupFiles: ['dotenv/config'], //this line @@ -25,7 +31,7 @@ export default defineConfig({ inline: ['@govtechsg/oa-verify', '@tradetrust-tt/tt-verify'], // Inline oa-verify package directly }, }, - exclude: ['dist', 'node_modules', '*/type{s}.{ts,js}'], + exclude: ['dist', 'node_modules', '*/type{s}.{ts,js}', 'src/__tests__/e2e/**'], coverage: { enabled: true, provider: 'v8', From 58a8da209e68cc7aa1928cd507cdee66a3031203 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Thu, 17 Jul 2025 15:35:44 +0530 Subject: [PATCH 08/14] chore: e2e tests reject transfer (#83) * chore: e2e tests for reject functions * fix: reject function ethers v6 compatible * fix: update imports * fix: mock test cases * fix: import fixed --- .../rejectTransfer.e2e.test.ts | 1572 +++++++++++++++++ .../transfer.e2e.test.ts | 48 +- src/__tests__/e2e/utils.ts | 18 - .../rejectTransfers.test.ts | 24 +- .../rejectTransfers.ts | 69 +- 5 files changed, 1667 insertions(+), 64 deletions(-) create mode 100644 src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts diff --git a/src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts b/src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts new file mode 100644 index 0000000..f832219 --- /dev/null +++ b/src/__tests__/e2e/token-registry-functions/rejectTransfer.e2e.test.ts @@ -0,0 +1,1572 @@ +import { expect } from 'chai'; +import { network } from 'hardhat'; +import { ethers as ethersV6, ZeroAddress } from 'ethersV6'; +import '@nomiclabs/hardhat-ethers'; +import '@nomicfoundation/hardhat-chai-matchers'; +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import type { + MintTokenOptions, + MintTokenParams, + TransactionOptions, + ProviderInfo, +} from '../../../token-registry-functions/types'; +import { ethers, Signer } from 'ethers'; + +// Import our new signer utilities +import { getSignersV5, getSignersV6, providerV5, providerV6 } from '../fixtures'; +import { createContract, getVersionedContractFactory } from '../utils'; +import { + mint, + transferHolder, + transferBeneficiary, + transferOwners, + nominate, + rejectTransferBeneficiary, + rejectTransferHolder, + rejectTransferOwners, +} from '../../../token-registry-functions'; + +interface ContractAddresses { + tokenAddress: string; + titleEscrow: string; + holder: string; + beneficiary: string; + newHolder: string; + newBeneficiary: string; + owner: string; + newOwner: string; +} + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, +]; + +providers.forEach(({ ethersVersion, titleEscrowVersion }) => { + describe(`Reject Transfer Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, async function () { + let TradeTrustTokenContract: any; + let TitleEscrowFactoryContract: any; + let titleEscrowFactoryAddress: any; + let titleEscrow: any; + let deployer: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let owner: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let newOwner: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let holder: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let beneficiary: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let newHolder: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let newBeneficiary: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let addresses: ContractAddresses; + let tradeTrustTokenAddress: string; + + before(async function () { + await network.provider.send('evm_setAutomine', [true]); // Ensure auto-mining + await network.provider.send('hardhat_reset'); // Reset network between tests + // Reset nonce tracker for clean state (especially important for v6) + + // Get signers using our custom utility (returns ethers.Wallet[]) + // For v6, use unique private keys based on provider index to avoid nonce conflicts + const signers = ethersVersion === 'v5' ? await getSignersV5(11) : await getSignersV6(11); // Larger offset for v6 + // const signers = await hardhatEthers.getSigners(); + [deployer, owner, newOwner, holder, beneficiary, newHolder, newBeneficiary] = signers; + + // Deploy TitleEscrowFactory first + console.log('Deploying TitleEscrowFactory...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const titleEscrowFactory = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + titleEscrowVersion, + deployer, + ); + + TitleEscrowFactoryContract = await titleEscrowFactory.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContract.waitForDeployment(); + } else { + await TitleEscrowFactoryContract.deployTransaction.wait(); + } + + titleEscrowFactoryAddress = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContract as ethers.Contract).address + : (TitleEscrowFactoryContract as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + console.log('Deploying TradeTrustToken...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactory = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + titleEscrowVersion, + deployer, + ); + + // add a time delay here + + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContract = await tradeTrustTokenFactory.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddress, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContract = await tradeTrustTokenFactory.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddress, + ); + // await TradeTrustTokenContract.wait(); + } + + tradeTrustTokenAddress = + ethersVersion === 'v5' + ? (TradeTrustTokenContract as ethers.Contract).address + : await (TradeTrustTokenContract as ethersV6.Contract).getAddress(); + console.log('TradeTrustToken deployed to:', tradeTrustTokenAddress); + + console.log('All mock contracts deployed and initialized for E2E testing'); + console.log('Minting token...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: beneficiary.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion, + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const tx0 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await tx0.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + titleEscrow = createContract( + await TradeTrustTokenContract.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + titleEscrowVersion, + deployer, + ); + + addresses = { + tokenAddress: tradeTrustTokenAddress, + titleEscrow: titleEscrow.address || titleEscrow.target, + holder: holder.address, + beneficiary: beneficiary.address, + newHolder: newHolder.address, + newBeneficiary: newBeneficiary.address, + owner: owner.address, + newOwner: newOwner.address, + }; + }); + describe('rejectTransferHolder', () => { + describe('Successful Rejection of Holder', () => { + beforeEach(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + holderAddress: addresses.newHolder, + remarks: 'Transfer Holder', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const prevHolder = await titleEscrow.prevHolder(); + // Execute transfer using current holder (newHolder) + if (prevHolder == ZeroAddress) { + const tx0 = await transferHolder(contractOptions, holder as any, params, options); + await tx0.wait(); + } + }); + it('should have correct initial state', async function () { + const currentHolder = await titleEscrow.holder(); + const currentBeneficiary = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(currentHolder).to.equal(newHolder.address); + expect(currentBeneficiary).to.equal(beneficiary.address); + expect(prevHolder).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + }); + it('should reject holder transfer successfully with remarks provided', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferHolder(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow.holder(); + expect(newHolderAddress).to.equal(holder.address); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevHolder = await titleEscrow.prevHolder(); + expect(prevHolder).to.equal(ZeroAddress); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should reject holder transfer successfully without remarks', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: '', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferHolder(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow.holder(); + expect(newHolderAddress).to.equal(holder.address); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should detect version v5 automatically when titleEscrowVersion is not passed', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferHolder(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow.holder(); + expect(newHolderAddress).to.equal(holder.address); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + }); + + it('should handle undefined/empty options object without crashing (safeguards)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = {}; + + const options = { + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + + const tx = await rejectTransferHolder(contractOptions, newHolder, params, options); + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow.holder(); + expect(newHolderAddress).to.equal(holder.address); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + }); + }); + describe('Error Handling', () => { + it('should fail if titleEscrowAddress is not derivable from tokenRegistryAddress and tokenId', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '2', //invalid token ID + }; + + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + try { + await rejectTransferHolder(contractOptions, holder as any, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + // Both are acceptable for this test case + expect(error.message).to.include('ERC721: owner query for nonexistent token'); + } + }); + + it('should throw error if signer has no provider', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + try { + await rejectTransferHolder( + contractOptions, + signerWithoutProvider as any, + params, + options, + ); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + + it('should throw error if titleEscrow contract is not version v5', async () => { + const titleEscrowFactoryV4 = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + 'v4', + deployer, + ); + + const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContractV4.waitForDeployment(); + } + + const titleEscrowFactoryAddressV4 = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContractV4 as ethers.Contract).address + : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactoryV4 = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + 'v4', + deployer, + ); + + // add a time delay here + let TradeTrustTokenContractV4: any; + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + ); + // await TradeTrustTokenContract.wait(); + } + + const tradeTrustTokenAddressV4 = + ethersVersion === 'v5' + ? (TradeTrustTokenContractV4 as ethers.Contract).address + : await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddressV4, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: 'v4', + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await txV4.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const titleEscrowv4 = createContract( + await TradeTrustTokenContractV4.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + 'v4', + deployer, + ); + const contractOptionsV4 = { + titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string, + }; + + const paramsV4 = { + newBeneficiaryAddress: addresses.newBeneficiary, + newHolderAddress: addresses.newHolder, + remarks: 'Transfer both roles', + }; + + const optionsV4 = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4); + await tx.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptionsV4Reject = { + titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target, + }; + + const paramsV4Reject = { + remarks: 'Reject transfer holder to new address', + }; + + const optionsV4Reject = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder( + contractOptionsV4Reject, + newHolder, + paramsV4Reject, + optionsV4Reject, + ); + } catch (error: any) { + expect(error.message).to.equal('Only Token Registry V5 is supported'); + } + }); + + it('should throw error when callStatic rejectTransferHolder fails', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); //reject is invalid + } catch (error: any) { + expect(error.message).to.equal( + 'Pre-check (callStatic) for rejectTransferHolder failed', + ); + } + }); + + it('should fail if tokenRegistryAddress is not provided when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should fail if tokenId is missing when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '', + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token ID is required'); + } + }); + + it('should throw error if `encrypt` function throws (invalid remarks or id)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal( + `Cannot read properties of undefined (reading 'length')`, + ); + } + }); + // it('should allow retrying the transaction if it fails due to nonce issues'); + }); + }); + describe('rejectTransferBeneficiary', () => { + describe('Successful Rejection of Beneficiary', () => { + beforeEach(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + newBeneficiaryAddress: addresses.newBeneficiary, + remarks: 'Transfer Beneficiary', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + // Execute transfer using current holder (newHolder) + if (prevBeneficiary == ZeroAddress) { + const tx0 = await nominate(contractOptions, beneficiary, params, options); + await tx0.wait(); + const tx1 = await transferBeneficiary(contractOptions, holder, params, options); + await tx1.wait(); + } + }); + it('should have correct initial state', async function () { + const currentHolder = await titleEscrow.holder(); + const currentBeneficiary = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(currentHolder).to.equal(holder.address); + expect(currentBeneficiary).to.equal(newBeneficiary.address); + expect(prevHolder).to.equal(ZeroAddress); + expect(prevBeneficiary).to.equal(beneficiary.address); + }); + it('should reject beneficiary transfer successfully with remarks provided', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow.holder(); + expect(newHolderAddress).to.equal(holder.address); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevHolder = await titleEscrow.prevHolder(); + expect(prevHolder).to.equal(ZeroAddress); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should reject holder transfer successfully without remarks', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: '', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should detect version v5 automatically when titleEscrowVersion is not passed', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + }); + + it('should handle undefined/empty options object without crashing (safeguards)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = {}; + + const options = { + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + }); + }); + describe('Error Handling', () => { + it('should fail if titleEscrowAddress is not derivable from tokenRegistryAddress and tokenId', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '2', //invalid token ID + }; + + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + try { + await rejectTransferBeneficiary(contractOptions, newBeneficiary, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + // Both are acceptable for this test case + expect(error.message).to.include('ERC721: owner query for nonexistent token'); + } + }); + + it('should throw error if signer has no provider', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + try { + await rejectTransferBeneficiary( + contractOptions, + signerWithoutProvider as any, + params, + options, + ); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + + it('should throw error if titleEscrow contract is not version v5', async () => { + const titleEscrowFactoryV4 = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + 'v4', + deployer, + ); + + const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContractV4.waitForDeployment(); + } + + const titleEscrowFactoryAddressV4 = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContractV4 as ethers.Contract).address + : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactoryV4 = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + 'v4', + deployer, + ); + + // add a time delay here + let TradeTrustTokenContractV4: any; + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + ); + // await TradeTrustTokenContract.wait(); + } + + const tradeTrustTokenAddressV4 = + ethersVersion === 'v5' + ? (TradeTrustTokenContractV4 as ethers.Contract).address + : await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress(); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddressV4, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: 'v4', + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await txV4.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const titleEscrowv4 = createContract( + await TradeTrustTokenContractV4.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + 'v4', + deployer, + ); + const contractOptionsV4 = { + titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string, + }; + + const paramsV4 = { + newBeneficiaryAddress: addresses.newBeneficiary, + newHolderAddress: addresses.newHolder, + remarks: 'Transfer both roles', + }; + + const optionsV4 = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4); + await tx.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptionsV4Reject = { + titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target, + }; + + const paramsV4Reject = { + remarks: 'Reject transfer beneficiary to new address', + }; + + const optionsV4Reject = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary( + contractOptionsV4Reject, + newHolder, + paramsV4Reject, + optionsV4Reject, + ); + } catch (error: any) { + expect(error.message).to.equal('Only Token Registry V5 is supported'); + } + }); + + it('should throw error when callStatic rejectTransferHolder fails', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); //reject is invalid + } catch (error: any) { + expect(error.message).to.equal( + 'Pre-check (callStatic) for rejectTransferBeneficiary failed', + ); + } + }); + + it('should fail if tokenRegistryAddress is not provided when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should fail if tokenId is missing when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token ID is required'); + } + }); + + it('should throw error if `encrypt` function throws (invalid remarks or id)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal( + `Cannot read properties of undefined (reading 'length')`, + ); + } + }); + // it('should allow retrying the transaction if it fails due to nonce issues'); + }); + }); + describe('rejectTransferOwners', () => { + before(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + newBeneficiaryAddress: addresses.holder, + remarks: 'Transfer Beneficiary', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + // Execute transfer using current holder (newHolder) + const tx0 = await nominate(contractOptions, beneficiary, params, options); + await tx0.wait(); + const tx1 = await transferBeneficiary(contractOptions, holder, params, options); + await tx1.wait(); + }); + describe('Successful Rejection of Owners', () => { + beforeEach(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + newBeneficiaryAddress: addresses.newHolder, //keeping both beneficiary and holder same + newHolderAddress: addresses.newHolder, + remarks: 'Transfer Owners', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + + // Execute transfer using current holder (newHolder) + if (prevBeneficiary == ZeroAddress || prevHolder == ZeroAddress) { + const tx1 = await transferOwners(contractOptions, holder, params, options); + await tx1.wait(); + } + }); + it('should have correct initial state', async function () { + const currentHolder = await titleEscrow.holder(); + const currentBeneficiary = await titleEscrow.beneficiary(); + + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(currentHolder).to.equal(newHolder.address); + expect(currentBeneficiary).to.equal(newHolder.address); + + expect(prevHolder).to.equal(holder.address); + expect(prevBeneficiary).to.equal(holder.address); + }); + it('should reject Owners transfer successfully with remarks provided', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Reject transfer owners', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should reject holder transfer successfully without remarks', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: '', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should detect version v5 automatically when titleEscrowVersion is not passed', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Reject Transfer Owners to Previous address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should handle undefined/empty options object without crashing (safeguards)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = {}; + + const options = { + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + }); + describe('Error Handling', () => { + it('should fail if titleEscrowAddress is not derivable from tokenRegistryAddress and tokenId', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '2', //invalid token ID + }; + + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + expect(error.message).to.include('ERC721: owner query for nonexistent token'); + } + }); + + it('should throw error if signer has no provider', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + try { + await rejectTransferOwners( + contractOptions, + signerWithoutProvider as any, + params, + options, + ); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + + it('should throw error if titleEscrow contract is not version v5', async () => { + const titleEscrowFactoryV4 = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + 'v4', + deployer, + ); + + const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContractV4.waitForDeployment(); + } + + const titleEscrowFactoryAddressV4 = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContractV4 as ethers.Contract).address + : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactoryV4 = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + 'v4', + deployer, + ); + + // add a time delay here + let TradeTrustTokenContractV4: any; + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + ); + // await TradeTrustTokenContract.wait(); + } + + const tradeTrustTokenAddressV4 = + ethersVersion === 'v5' + ? (TradeTrustTokenContractV4 as ethers.Contract).address + : await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddressV4, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: 'v4', + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await txV4.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const titleEscrowv4 = createContract( + await TradeTrustTokenContractV4.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + 'v4', + deployer, + ); + const contractOptionsV4 = { + titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string, + }; + + const paramsV4 = { + newBeneficiaryAddress: addresses.newBeneficiary, + newHolderAddress: addresses.newHolder, + remarks: 'Transfer both roles', + }; + + const optionsV4 = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4); + await tx.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptionsV4Reject = { + titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target, + }; + + const paramsV4Reject = { + remarks: 'Reject transfer beneficiary to new address', + }; + + const optionsV4Reject = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners( + contractOptionsV4Reject, + newHolder, + paramsV4Reject, + optionsV4Reject, + ); + } catch (error: any) { + expect(error.message).to.equal('Only Token Registry V5 is supported'); + } + }); + + it('should throw error when callStatic rejectTransferHolder fails', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); //reject is invalid + } catch (error: any) { + expect(error.message).to.equal( + 'Pre-check (callStatic) for rejectTransferOwners failed', + ); + } + }); + + it('should fail if tokenRegistryAddress is not provided when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should fail if tokenId is missing when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token ID is required'); + } + }); + + it('should throw error if `encrypt` function throws (invalid remarks or id)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal( + `Cannot read properties of undefined (reading 'length')`, + ); + } + }); + // it('should allow retrying the transaction if it fails due to nonce issues'); + }); + }); + }); +}); diff --git a/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts b/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts index b8d7951..e44c5cd 100644 --- a/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts +++ b/src/__tests__/e2e/token-registry-functions/transfer.e2e.test.ts @@ -5,28 +5,24 @@ import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; // Import the functions we want to test import { + mint, transferHolder, transferBeneficiary, transferOwners, nominate, -} from '../../../token-registry-functions/transfer'; -import { mint } from '../../../token-registry-functions/mint'; +} from '../../../token-registry-functions'; import type { MintTokenOptions, MintTokenParams, TransactionOptions, ProviderInfo, } from '../../../token-registry-functions/types'; -import { v5Contracts } from '../../../token-registry-v5'; import { ethers, Signer } from 'ethers'; // Import our new signer utilities import { getSignersV5, getSignersV6, providerV5, providerV6 } from '../fixtures'; -import { - createContract, - getV4TitleEscrowContractFromTitleEscrowFactory, - getVersionedContractFactory, -} from '../utils'; +import { createContract, getVersionedContractFactory } from '../utils'; +import { getTitleEscrowAddress } from '../../../core'; interface ContractAddresses { tokenAddress: string; @@ -347,31 +343,17 @@ providers.forEach(({ Provider, ethersVersion, titleEscrowVersion }) => { it('should set up title escrow addresses and contract instances', async function () { // Get title escrow addresses using the factory - const titleEscrow0Address = - titleEscrowVersion === 'v5' - ? await (TitleEscrowFactoryContract as v5Contracts.TitleEscrowFactory).getEscrowAddress( - tradeTrustTokenAddress, - '0', - ) - : await getV4TitleEscrowContractFromTitleEscrowFactory( - Provider, - TitleEscrowFactoryContract, - tradeTrustTokenAddress, - '0', - ); - - const titleEscrow1Address = - titleEscrowVersion === 'v5' - ? await (TitleEscrowFactoryContract as v5Contracts.TitleEscrowFactory).getEscrowAddress( - tradeTrustTokenAddress, - '1', - ) - : await getV4TitleEscrowContractFromTitleEscrowFactory( - Provider, - TitleEscrowFactoryContract, - tradeTrustTokenAddress, - '1', - ); + const titleEscrow0Address = await getTitleEscrowAddress( + tradeTrustTokenAddress, + '0', + Provider, + ); + + const titleEscrow1Address = await getTitleEscrowAddress( + tradeTrustTokenAddress, + '1', + Provider, + ); // Get contract instances titleEscrow0 = createContract( diff --git a/src/__tests__/e2e/utils.ts b/src/__tests__/e2e/utils.ts index 4c3e8a1..060d04c 100644 --- a/src/__tests__/e2e/utils.ts +++ b/src/__tests__/e2e/utils.ts @@ -36,21 +36,3 @@ export const createContract = ( ? new ethers.Contract(address, abi, signer as Signer) : new ethersV6.Contract(address, abi, signer as ContractRunner); }; - -export const getV4TitleEscrowContractFromTitleEscrowFactory = async ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - provider: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - titleEscrowFactory: any, - tradeTrustTokenAddress: string, - tokenId: string, -) => { - const iface = titleEscrowFactory.interface; - const encodedData = iface.encodeFunctionData('getAddress', [tradeTrustTokenAddress, tokenId]); - const result = await provider.call({ - to: titleEscrowFactory.target ?? titleEscrowFactory.address, - data: encodedData, - }); - const decodedAddress = iface.decodeFunctionResult('getAddress', result)[0]; - return decodedAddress; -}; diff --git a/src/__tests__/token-registry-functions/rejectTransfers.test.ts b/src/__tests__/token-registry-functions/rejectTransfers.test.ts index d4fde98..879da71 100644 --- a/src/__tests__/token-registry-functions/rejectTransfers.test.ts +++ b/src/__tests__/token-registry-functions/rejectTransfers.test.ts @@ -11,6 +11,7 @@ import { } from '../../token-registry-functions/rejectTransfers'; import { mockV5TitleEscrowContract, PRIVATE_KEY, providerV5, providerV6 } from './fixtures'; import { ProviderInfo } from '../../token-registry-functions/types.js'; +import { getEthersContractFromProvider } from '../../utils/ethers'; const providers: ProviderInfo[] = [ { @@ -36,6 +37,16 @@ describe.each(providers)( const mockEncryptedRemarks = '0xencryptedRemarks'; let wallet: ethersV5.Wallet | ethersV6.Wallet; + // Handle both v5 and v6 contract constructors + beforeAll(() => { + // Clear any existing mocks first + vi.clearAllMocks(); + const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); + // Only set up the mock if it hasn't been set up yet + vi.mocked(getEthersContractFromProvider).mockReturnValue( + mockContractConstructor(mockV5TitleEscrowContract), + ); + }); beforeEach(() => { // Reset all mocks before each test vi.clearAllMocks(); @@ -157,6 +168,9 @@ describe.each(providers)( mockV5TitleEscrowContract.callStatic.rejectTransferHolder.mockRejectedValue( new Error('Simulated failure'), ); + mockV5TitleEscrowContract.rejectTransferHolder.staticCall.mockRejectedValue( + new Error('Simulated failure'), + ); await expect( rejectTransferHolder( @@ -170,6 +184,7 @@ describe.each(providers)( ), ).rejects.toThrow('Pre-check (callStatic) for rejectTransferHolder failed'); mockV5TitleEscrowContract.callStatic.rejectTransferHolder = vi.fn(); + mockV5TitleEscrowContract.rejectTransferHolder.staticCall = vi.fn(); }); it('should use explicit titleEscrowVersion when provided', async () => { @@ -281,7 +296,9 @@ describe.each(providers)( mockV5TitleEscrowContract.callStatic.rejectTransferBeneficiary.mockRejectedValue( new Error('Simulated failure'), ); - + mockV5TitleEscrowContract.rejectTransferBeneficiary.staticCall.mockRejectedValue( + new Error('Simulated failure'), + ); await expect( rejectTransferBeneficiary( { @@ -294,6 +311,7 @@ describe.each(providers)( ), ).rejects.toThrow('Pre-check (callStatic) for rejectTransferBeneficiary failed'); mockV5TitleEscrowContract.callStatic.rejectTransferBeneficiary = vi.fn(); + mockV5TitleEscrowContract.rejectTransferBeneficiary.staticCall = vi.fn(); }); it('should use explicit titleEscrowVersion when provided', async () => { @@ -405,6 +423,9 @@ describe.each(providers)( mockV5TitleEscrowContract.callStatic.rejectTransferOwners.mockRejectedValue( new Error('Simulated failure'), ); + mockV5TitleEscrowContract.rejectTransferOwners.staticCall.mockRejectedValue( + new Error('Simulated failure'), + ); await expect( rejectTransferOwners( @@ -418,6 +439,7 @@ describe.each(providers)( ), ).rejects.toThrow('Pre-check (callStatic) for rejectTransferOwners failed'); mockV5TitleEscrowContract.callStatic.rejectTransferOwners = vi.fn(); + mockV5TitleEscrowContract.rejectTransferOwners.staticCall = vi.fn(); }); it('should use explicit titleEscrowVersion when provided', async () => { diff --git a/src/token-registry-functions/rejectTransfers.ts b/src/token-registry-functions/rejectTransfers.ts index 85023e8..268dc0d 100644 --- a/src/token-registry-functions/rejectTransfers.ts +++ b/src/token-registry-functions/rejectTransfers.ts @@ -3,12 +3,13 @@ import { getTitleEscrowAddress, isTitleEscrowVersion, TitleEscrowInterface, -} from '../core'; -import { v5Contracts } from '../token-registry-v5'; -import { Signer as SignerV6 } from 'ethersV6'; -import { ContractTransaction, Signer } from 'ethers'; +} from './../core'; +import { v5Contracts } from './../token-registry-v5'; +import { Signer as SignerV6, Contract as ContractV6 } from 'ethersV6'; +import { Contract as ContractV5, ContractTransaction, Signer } from 'ethers'; import { getTxOptions } from './utils'; import { ContractOptions, RejectTransferParams, TransactionOptions } from './types'; +import { getEthersContractFromProvider, isV6EthersProvider } from '../utils/ethers'; /** * Rejects the transfer of holder for a title escrow contract. @@ -32,6 +33,8 @@ const rejectTransferHolder = async ( const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; if (!titleEscrowAddress) { + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!tokenId) throw new Error('Token ID is required'); titleEscrowAddress = await getTitleEscrowAddress( tokenRegistryAddress, tokenId as string, @@ -40,13 +43,18 @@ const rejectTransferHolder = async ( ); } - if (!titleEscrowAddress) throw new Error('Token registry address is required'); + if (!titleEscrowAddress) throw new Error('Title escrow address is required'); if (!signer.provider) throw new Error('Provider is required'); const { remarks } = params; // Connect V5 contract by default - const titleEscrowContract = v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); - + const Contract = getEthersContractFromProvider(signer.provider); + const titleEscrowContract: ContractV5 | ContractV6 = new Contract( + titleEscrowAddress, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; // Detect version if not explicitly provided @@ -65,7 +73,14 @@ const rejectTransferHolder = async ( // Check callStatic (dry run) try { - await titleEscrowContract.callStatic.rejectTransferHolder(encryptedRemarks); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [encryptedRemarks] : []; + + if (isV6) { + await (titleEscrowContract as ContractV6).rejectTransferHolder.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.rejectTransferHolder(...args); + } } catch (e) { console.error('callStatic failed:', e); throw new Error('Pre-check (callStatic) for rejectTransferHolder failed'); @@ -100,6 +115,8 @@ const rejectTransferBeneficiary = async ( const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; if (!titleEscrowAddress) { + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!tokenId) throw new Error('Token ID is required'); titleEscrowAddress = await getTitleEscrowAddress( tokenRegistryAddress, tokenId as string, @@ -113,7 +130,13 @@ const rejectTransferBeneficiary = async ( const { remarks } = params; // Connect V5 contract by default - const titleEscrowContract = v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + const Contract = getEthersContractFromProvider(signer.provider); + const titleEscrowContract: ContractV5 | ContractV6 = new Contract( + titleEscrowAddress, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; @@ -133,7 +156,14 @@ const rejectTransferBeneficiary = async ( // Check callStatic (dry run) try { - await titleEscrowContract.callStatic.rejectTransferBeneficiary(encryptedRemarks); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [encryptedRemarks] : []; + + if (isV6) { + await (titleEscrowContract as ContractV6).rejectTransferBeneficiary.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.rejectTransferBeneficiary(...args); + } } catch (e) { console.error('callStatic failed:', e); throw new Error('Pre-check (callStatic) for rejectTransferBeneficiary failed'); @@ -168,6 +198,8 @@ const rejectTransferOwners = async ( const { chainId, maxFeePerGas, maxPriorityFeePerGas, titleEscrowVersion } = options; if (!titleEscrowAddress) { + if (!tokenRegistryAddress) throw new Error('Token registry address is required'); + if (!tokenId) throw new Error('Token ID is required'); titleEscrowAddress = await getTitleEscrowAddress( tokenRegistryAddress, tokenId as string, @@ -181,7 +213,13 @@ const rejectTransferOwners = async ( const { remarks } = params; // Connect V5 contract by default - const titleEscrowContract = v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + const Contract = getEthersContractFromProvider(signer.provider); + const titleEscrowContract: ContractV5 | ContractV6 = new Contract( + titleEscrowAddress, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); const encryptedRemarks = remarks ? `0x${encrypt(remarks, options.id!)}` : '0x'; @@ -201,7 +239,14 @@ const rejectTransferOwners = async ( // Check callStatic (dry run) try { - await titleEscrowContract.callStatic.rejectTransferOwners(encryptedRemarks); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [encryptedRemarks] : []; + + if (isV6) { + await (titleEscrowContract as ContractV6).rejectTransferOwners.staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic.rejectTransferOwners(...args); + } } catch (e) { console.error('callStatic failed:', e); throw new Error('Pre-check (callStatic) for rejectTransferOwners failed'); From 703be01a0c15d122e4f56af938d40da0901ac30f Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Thu, 17 Jul 2025 20:02:12 +0530 Subject: [PATCH 09/14] fix: e2e return token tests (#84) * chore: e2e tests for reject functions * fix: reject function ethers v6 compatible * fix: update imports * fix: mock test cases * fix: static call fixes * chore: add e2e test cases * fix: update imports * fix: update imports * fix: tests * fix: mock functions * fix: change name * fix: update imports * fix: update src imports --- .../returnToken.e2e.test.ts | 1556 +++++++++++++++++ .../token-registry-functions/fixtures.ts | 9 +- .../returnToken.test.ts | 74 +- src/token-registry-functions/returnToken.ts | 125 +- 4 files changed, 1674 insertions(+), 90 deletions(-) create mode 100644 src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts diff --git a/src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts b/src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts new file mode 100644 index 0000000..9337359 --- /dev/null +++ b/src/__tests__/e2e/token-registry-functions/returnToken.e2e.test.ts @@ -0,0 +1,1556 @@ +import { expect } from 'chai'; +import { ethers as ethersV6, ZeroAddress } from 'ethersV6'; +import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; + +// Import the functions we want to test +import { + transferBeneficiary, + transferOwners, + nominate, + mint, + rejectReturned, + rejectTransferBeneficiary, + rejectTransferHolder, + rejectTransferOwners, + returnToIssuer, +} from '../../../token-registry-functions'; +import type { + MintTokenOptions, + MintTokenParams, + TransactionOptions, + ProviderInfo, +} from '../../../token-registry-functions/types'; +import { ethers, Signer } from 'ethers'; + +// Import our new signer utilities +import { getSignersV5, getSignersV6, providerV5, providerV6 } from '../fixtures'; +import { createContract, getVersionedContractFactory } from '../utils'; +interface ContractAddresses { + tokenAddress: string; + titleEscrow: string; + holder: string; + beneficiary: string; + newHolder: string; + newBeneficiary: string; + owner: string; + newOwner: string; +} + +const providers: ProviderInfo[] = [ + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV5, + ethersVersion: 'v5', + titleEscrowVersion: 'v4', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v5', + }, + { + Provider: providerV6, + ethersVersion: 'v6', + titleEscrowVersion: 'v4', + }, +]; + +providers.forEach(({ ethersVersion, titleEscrowVersion }) => { + describe(`Return Token Functions E2E Tests -with ethers ${ethersVersion} and token registry ${titleEscrowVersion}`, async function () { + let TradeTrustTokenContract: any; + let TitleEscrowFactoryContract: any; + let titleEscrowFactoryAddress: any; + let titleEscrow: any; + let deployer: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let owner: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let newOwner: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let holder: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let beneficiary: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let newHolder: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let newBeneficiary: ethers.Wallet | ethersV6.Wallet | SignerWithAddress; + let addresses: ContractAddresses; + let tradeTrustTokenAddress: string; + + before(async function () { + // Reset nonce tracker for clean state (especially important for v6) + + // Get signers using our custom utility (returns ethers.Wallet[]) + // For v6, use unique private keys based on provider index to avoid nonce conflicts + const signers = ethersVersion === 'v5' ? await getSignersV5(11) : await getSignersV6(11); // Larger offset for v6 + // const signers = await hardhatEthers.getSigners(); + [deployer, owner, newOwner, holder, beneficiary, newHolder, newBeneficiary] = signers; + + // Deploy TitleEscrowFactory first + console.log('Deploying TitleEscrowFactory...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const titleEscrowFactory = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + titleEscrowVersion, + deployer, + ); + + TitleEscrowFactoryContract = await titleEscrowFactory.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContract.waitForDeployment(); + } else { + await TitleEscrowFactoryContract.deployTransaction.wait(); + } + + titleEscrowFactoryAddress = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContract as ethers.Contract).address + : (TitleEscrowFactoryContract as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + console.log('Deploying TradeTrustToken...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactory = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + titleEscrowVersion, + deployer, + ); + + // add a time delay here + + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContract = await tradeTrustTokenFactory.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddress, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContract = await tradeTrustTokenFactory.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddress, + ); + // await TradeTrustTokenContract.wait(); + } + + tradeTrustTokenAddress = + ethersVersion === 'v5' + ? (TradeTrustTokenContract as ethers.Contract).address + : await (TradeTrustTokenContract as ethersV6.Contract).getAddress(); + console.log('TradeTrustToken deployed to:', tradeTrustTokenAddress); + + console.log('All mock contracts deployed and initialized for E2E testing'); + console.log('Minting token...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddress, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion, + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const tx0 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await tx0.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + titleEscrow = createContract( + await TradeTrustTokenContract.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + titleEscrowVersion, + deployer, + ); + + addresses = { + tokenAddress: tradeTrustTokenAddress, + titleEscrow: titleEscrow.address || titleEscrow.target, + holder: holder.address, + beneficiary: beneficiary.address, + newHolder: newHolder.address, + newBeneficiary: newBeneficiary.address, + owner: owner.address, + newOwner: newOwner.address, + }; + }); + describe('returnToIssuer', () => { + describe.only('Successful Return to Issuer', () => { + beforeEach(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + }; + + const params = { + tokenId: '0', + remarks: 'Reject Returned Document', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const ownerOfToken = await TradeTrustTokenContract.ownerOf('0'); + if (ownerOfToken !== addresses.titleEscrow) { + const tx = await rejectReturned(contractOptions, deployer, params, options); + await tx.wait(); + } + }); + it('should have correct initial state', async function () { + const currentHolder = await titleEscrow.holder(); + const currentBeneficiary = await titleEscrow.beneficiary(); + + expect(currentHolder).to.equal(holder.address); + expect(currentBeneficiary).to.equal(holder.address); + }); + it('should return to issuer successfully with remarks provided', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + // Execute transfer using type assertion to bypass type issues + const tx = await returnToIssuer(contractOptions, holder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify token owner has changed + const ownerOfToken = await TradeTrustTokenContract.ownerOf('0'); + expect(ownerOfToken).to.equal(addresses.tokenAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + it('should return to issue successfully without remarks', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: '', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await returnToIssuer(contractOptions, holder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify token owner has changed + const ownerOfToken = await TradeTrustTokenContract.ownerOf('0'); + expect(ownerOfToken).to.equal(addresses.tokenAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + it('should detect version v5 automatically when titleEscrowVersion is not passed', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await returnToIssuer(contractOptions, holder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify owner has changed + const ownerOfToken = await TradeTrustTokenContract.ownerOf('0'); + expect(ownerOfToken).to.equal(addresses.tokenAddress); + }); + it('should handle undefined/empty options object without crashing (safeguards)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = {}; + + const options = { + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + + const tx = await returnToIssuer(contractOptions, holder, params, options); + await tx.wait(); + + // Verify owner has changed + const ownerOfToken = await TradeTrustTokenContract.ownerOf('0'); + expect(ownerOfToken).to.equal(addresses.tokenAddress); + }); + }); + describe('Error Handling', () => { + it('should fail if titleEscrowAddress is not derivable from tokenRegistryAddress and tokenId', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '2', //invalid token ID + }; + + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + try { + await rejectTransferHolder(contractOptions, holder as any, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + // Both are acceptable for this test case + expect(error.message).to.include('ERC721: owner query for nonexistent token'); + } + }); + + it('should throw error if signer has no provider', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + try { + await rejectTransferHolder( + contractOptions, + signerWithoutProvider as any, + params, + options, + ); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + + it('should throw error if titleEscrow contract is not version v5', async () => { + const titleEscrowFactoryV4 = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + 'v4', + deployer, + ); + + const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContractV4.waitForDeployment(); + } + + const titleEscrowFactoryAddressV4 = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContractV4 as ethers.Contract).address + : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactoryV4 = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + 'v4', + deployer, + ); + + // add a time delay here + let TradeTrustTokenContractV4: any; + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + ); + // await TradeTrustTokenContract.wait(); + } + + const tradeTrustTokenAddressV4 = + ethersVersion === 'v5' + ? (TradeTrustTokenContractV4 as ethers.Contract).address + : await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddressV4, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: 'v4', + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await txV4.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const titleEscrowv4 = createContract( + await TradeTrustTokenContractV4.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + 'v4', + deployer, + ); + const contractOptionsV4 = { + titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string, + }; + + const paramsV4 = { + newBeneficiaryAddress: addresses.newBeneficiary, + newHolderAddress: addresses.newHolder, + remarks: 'Transfer both roles', + }; + + const optionsV4 = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4); + await tx.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptionsV4Reject = { + titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target, + }; + + const paramsV4Reject = { + remarks: 'Reject transfer holder to new address', + }; + + const optionsV4Reject = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder( + contractOptionsV4Reject, + newHolder, + paramsV4Reject, + optionsV4Reject, + ); + } catch (error: any) { + expect(error.message).to.equal('Only Token Registry V5 is supported'); + } + }); + + it('should throw error when callStatic rejectTransferHolder fails', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); //reject is invalid + } catch (error: any) { + expect(error.message).to.equal( + 'Pre-check (callStatic) for rejectTransferHolder failed', + ); + } + }); + + it('should fail if tokenRegistryAddress is not provided when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should fail if tokenId is missing when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '', + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token ID is required'); + } + }); + + it('should throw error if `encrypt` function throws (invalid remarks or id)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = { + remarks: 'Transfer holder to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferHolder(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal( + `Cannot read properties of undefined (reading 'length')`, + ); + } + }); + // it('should allow retrying the transaction if it fails due to nonce issues'); + }); + }); + describe('rejectTransferBeneficiary', () => { + describe('Successful Rejection of Beneficiary', () => { + beforeEach(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + newBeneficiaryAddress: addresses.newBeneficiary, + remarks: 'Transfer Beneficiary', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + // Execute transfer using current holder (newHolder) + if (prevBeneficiary == ZeroAddress) { + const tx0 = await nominate(contractOptions, beneficiary, params, options); + await tx0.wait(); + const tx1 = await transferBeneficiary(contractOptions, holder, params, options); + await tx1.wait(); + } + }); + it('should have correct initial state', async function () { + const currentHolder = await titleEscrow.holder(); + const currentBeneficiary = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(currentHolder).to.equal(holder.address); + expect(currentBeneficiary).to.equal(newBeneficiary.address); + expect(prevHolder).to.equal(ZeroAddress); + expect(prevBeneficiary).to.equal(beneficiary.address); + }); + it('should reject beneficiary transfer successfully with remarks provided', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify holder has changed + const newHolderAddress = await titleEscrow.holder(); + expect(newHolderAddress).to.equal(holder.address); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevHolder = await titleEscrow.prevHolder(); + expect(prevHolder).to.equal(ZeroAddress); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should reject holder transfer successfully without remarks', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: '', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should detect version v5 automatically when titleEscrowVersion is not passed', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + }); + + it('should handle undefined/empty options object without crashing (safeguards)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = {}; + + const options = { + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + + const tx = await rejectTransferBeneficiary( + contractOptions, + newBeneficiary, + params, + options, + ); + await tx.wait(); + + // Verify beneficiary has changed + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + expect(newBeneficiaryAddress).to.equal(beneficiary.address); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + expect(prevBeneficiary).to.equal(ZeroAddress); + }); + }); + describe('Error Handling', () => { + it('should fail if titleEscrowAddress is not derivable from tokenRegistryAddress and tokenId', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '2', //invalid token ID + }; + + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + try { + await rejectTransferBeneficiary(contractOptions, newBeneficiary, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + // Both are acceptable for this test case + expect(error.message).to.include('ERC721: owner query for nonexistent token'); + } + }); + + it('should throw error if signer has no provider', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + try { + await rejectTransferBeneficiary( + contractOptions, + signerWithoutProvider as any, + params, + options, + ); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + + it('should throw error if titleEscrow contract is not version v5', async () => { + const titleEscrowFactoryV4 = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + 'v4', + deployer, + ); + + const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContractV4.waitForDeployment(); + } + + const titleEscrowFactoryAddressV4 = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContractV4 as ethers.Contract).address + : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactoryV4 = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + 'v4', + deployer, + ); + + // add a time delay here + let TradeTrustTokenContractV4: any; + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + ); + // await TradeTrustTokenContract.wait(); + } + + const tradeTrustTokenAddressV4 = + ethersVersion === 'v5' + ? (TradeTrustTokenContractV4 as ethers.Contract).address + : await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress(); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddressV4, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: 'v4', + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await txV4.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const titleEscrowv4 = createContract( + await TradeTrustTokenContractV4.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + 'v4', + deployer, + ); + const contractOptionsV4 = { + titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string, + }; + + const paramsV4 = { + newBeneficiaryAddress: addresses.newBeneficiary, + newHolderAddress: addresses.newHolder, + remarks: 'Transfer both roles', + }; + + const optionsV4 = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4); + await tx.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptionsV4Reject = { + titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target, + }; + + const paramsV4Reject = { + remarks: 'Reject transfer beneficiary to new address', + }; + + const optionsV4Reject = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary( + contractOptionsV4Reject, + newHolder, + paramsV4Reject, + optionsV4Reject, + ); + } catch (error: any) { + expect(error.message).to.equal('Only Token Registry V5 is supported'); + } + }); + + it('should throw error when callStatic rejectTransferHolder fails', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); //reject is invalid + } catch (error: any) { + expect(error.message).to.equal( + 'Pre-check (callStatic) for rejectTransferBeneficiary failed', + ); + } + }); + + it('should fail if tokenRegistryAddress is not provided when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should fail if tokenId is missing when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token ID is required'); + } + }); + + it('should throw error if `encrypt` function throws (invalid remarks or id)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferBeneficiary(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal( + `Cannot read properties of undefined (reading 'length')`, + ); + } + }); + // it('should allow retrying the transaction if it fails due to nonce issues'); + }); + }); + describe('rejectTransferOwners', () => { + before(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + newBeneficiaryAddress: addresses.holder, + remarks: 'Transfer Beneficiary', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + // Execute transfer using current holder (newHolder) + const tx0 = await nominate(contractOptions, beneficiary, params, options); + await tx0.wait(); + const tx1 = await transferBeneficiary(contractOptions, holder, params, options); + await tx1.wait(); + }); + describe('Successful Rejection of Owners', () => { + beforeEach(async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + newBeneficiaryAddress: addresses.newHolder, //keeping both beneficiary and holder same + newHolderAddress: addresses.newHolder, + remarks: 'Transfer Owners', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + + // Execute transfer using current holder (newHolder) + if (prevBeneficiary == ZeroAddress || prevHolder == ZeroAddress) { + const tx1 = await transferOwners(contractOptions, holder, params, options); + await tx1.wait(); + } + }); + it('should have correct initial state', async function () { + const currentHolder = await titleEscrow.holder(); + const currentBeneficiary = await titleEscrow.beneficiary(); + + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(currentHolder).to.equal(newHolder.address); + expect(currentBeneficiary).to.equal(newHolder.address); + + expect(prevHolder).to.equal(holder.address); + expect(prevBeneficiary).to.equal(holder.address); + }); + it('should reject Owners transfer successfully with remarks provided', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Reject transfer owners', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should reject holder transfer successfully without remarks', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: '', + }; + + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should detect version v5 automatically when titleEscrowVersion is not passed', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Reject Transfer Owners to Previous address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + + // Wait for transaction to be mined + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + + it('should handle undefined/empty options object without crashing (safeguards)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = {}; + + const options = { + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + + const tx = await rejectTransferOwners(contractOptions, newHolder, params, options); + await tx.wait(); + + // Verify Owners has changed + const newHolderAddress = await titleEscrow.holder(); + const newBeneficiaryAddress = await titleEscrow.beneficiary(); + const prevHolder = await titleEscrow.prevHolder(); + const prevBeneficiary = await titleEscrow.prevBeneficiary(); + + expect(newHolderAddress).to.equal(holder.address); + expect(newBeneficiaryAddress).to.equal(holder.address); + expect(prevBeneficiary).to.equal(ZeroAddress); + expect(prevHolder).to.equal(ZeroAddress); + + // Verify event was emitted + const receipt = await tx.wait(); + const events = receipt?.logs || []; + expect(events.length).to.be.greaterThan(0); + }); + }); + describe('Error Handling', () => { + it('should fail if titleEscrowAddress is not derivable from tokenRegistryAddress and tokenId', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '2', //invalid token ID + }; + + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + expect.fail('Expected transaction to revert but it succeeded'); + } catch (error: any) { + // The function should fail either at callStatic level or with a contract revert + expect(error.message).to.include('ERC721: owner query for nonexistent token'); + } + }); + + it('should throw error if signer has no provider', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + const params = { + remarks: 'Transfer both roles', + }; + const options = { + chainId: CHAIN_ID.local, + titleEscrowVersion, + id: 'test-encryption-id', + }; + const signerWithoutProvider = new ethers.Wallet( + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + + try { + await rejectTransferOwners( + contractOptions, + signerWithoutProvider as any, + params, + options, + ); + } catch (error: any) { + expect(error.message).to.equal('Provider is required'); + } + }); + + it('should throw error if titleEscrow contract is not version v5', async () => { + const titleEscrowFactoryV4 = getVersionedContractFactory( + 'TitleEscrowFactory', + ethersVersion, + 'v4', + deployer, + ); + + const TitleEscrowFactoryContractV4 = await titleEscrowFactoryV4.deploy(); + if (ethersVersion === 'v6') { + await TitleEscrowFactoryContractV4.waitForDeployment(); + } + + const titleEscrowFactoryAddressV4 = + ethersVersion === 'v5' + ? (TitleEscrowFactoryContractV4 as ethers.Contract).address + : (TitleEscrowFactoryContractV4 as ethersV6.Contract).target; + + // Deploy TradeTrustToken with proper constructor arguments + await new Promise((resolve) => setTimeout(resolve, 1000)); + const tradeTrustTokenFactoryV4 = getVersionedContractFactory( + 'TradeTrustToken', + ethersVersion, + 'v4', + deployer, + ); + + // add a time delay here + let TradeTrustTokenContractV4: any; + if (ethersVersion === 'v6') { + const nonce = await providerV6.getTransactionCount(deployer.address, 'pending'); + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + { + nonce: nonce, + }, + ); + } else { + TradeTrustTokenContractV4 = await tradeTrustTokenFactoryV4.deploy( + 'Test TradeTrust Token', + 'TTT', + titleEscrowFactoryAddressV4, + ); + // await TradeTrustTokenContract.wait(); + } + + const tradeTrustTokenAddressV4 = + ethersVersion === 'v5' + ? (TradeTrustTokenContractV4 as ethers.Contract).address + : await (TradeTrustTokenContractV4 as ethersV6.Contract).getAddress(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const contractOptions: MintTokenOptions = { + tokenRegistryAddress: tradeTrustTokenAddressV4, + }; + + const params: MintTokenParams = { + beneficiaryAddress: holder.address, //keeping both initial holder and beneficiary same + holderAddress: holder.address, + tokenId: '0', + remarks: 'Initial mint for testing', + }; + + const options: TransactionOptions = { + titleEscrowVersion: 'v4', + chainId: CHAIN_ID.local, + id: 'test-encryption-key', + }; + + const txV4 = await mint(contractOptions, deployer as unknown as Signer, params, options); + await txV4.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const titleEscrowv4 = createContract( + await TradeTrustTokenContractV4.ownerOf('0'), + 'TitleEscrow', + ethersVersion, + 'v4', + deployer, + ); + const contractOptionsV4 = { + titleEscrowAddress: (titleEscrowv4.address || titleEscrowv4.target) as string, + }; + + const paramsV4 = { + newBeneficiaryAddress: addresses.newBeneficiary, + newHolderAddress: addresses.newHolder, + remarks: 'Transfer both roles', + }; + + const optionsV4 = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using current holder (newHolder) + const tx = await transferOwners(contractOptionsV4, holder as any, paramsV4, optionsV4); + await tx.wait(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const contractOptionsV4Reject = { + titleEscrowAddress: titleEscrowv4.address || titleEscrowv4.target, + }; + + const paramsV4Reject = { + remarks: 'Reject transfer beneficiary to new address', + }; + + const optionsV4Reject = { + chainId: CHAIN_ID.local, + titleEscrowVersion: 'v4' as const, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners( + contractOptionsV4Reject, + newHolder, + paramsV4Reject, + optionsV4Reject, + ); + } catch (error: any) { + expect(error.message).to.equal('Only Token Registry V5 is supported'); + } + }); + + it('should throw error when callStatic rejectTransferHolder fails', async () => { + const contractOptions = { + titleEscrowAddress: addresses.titleEscrow, + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); //reject is invalid + } catch (error: any) { + expect(error.message).to.equal( + 'Pre-check (callStatic) for rejectTransferOwners failed', + ); + } + }); + + it('should fail if tokenRegistryAddress is not provided when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: '', + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token registry address is required'); + } + }); + + it('should fail if tokenId is missing when titleEscrowAddress is undefined', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + id: 'test-encryption-id', + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal('Token ID is required'); + } + }); + + it('should throw error if `encrypt` function throws (invalid remarks or id)', async () => { + const contractOptions = { + tokenRegistryAddress: addresses.tokenAddress, + tokenId: '0', + }; + + const params = { + remarks: 'Transfer Beneficiary to new address', + }; + + const options = { + chainId: CHAIN_ID.local, + }; + + // Execute transfer using type assertion to bypass type issues + try { + await rejectTransferOwners(contractOptions, newHolder, params, options); + } catch (error: any) { + expect(error.message).to.equal( + `Cannot read properties of undefined (reading 'length')`, + ); + } + }); + // it('should allow retrying the transaction if it fails due to nonce issues'); + }); + }); + }); +}); diff --git a/src/__tests__/token-registry-functions/fixtures.ts b/src/__tests__/token-registry-functions/fixtures.ts index fa2bfc2..d37bc3d 100644 --- a/src/__tests__/token-registry-functions/fixtures.ts +++ b/src/__tests__/token-registry-functions/fixtures.ts @@ -244,7 +244,14 @@ export const mockV4TitleEscrowContract = { ), holder: vi.fn(() => Promise.resolve('0xcurrent_holder')), beneficiary: vi.fn(() => Promise.resolve('0xcurrent_beneficiary')), - surrender: vi.fn(() => Promise.resolve('v4_surrender_tx_hash')), + surrender: Object.assign( + // Direct call returns hash string + vi.fn(() => Promise.resolve('v4_surrender_tx_hash')), + { + // Static call returns boolean + staticCall: vi.fn(() => Promise.resolve(true)), + }, + ), }; export const mockV4TitleEscrowFactoryContract = { callStatic: { diff --git a/src/__tests__/token-registry-functions/returnToken.test.ts b/src/__tests__/token-registry-functions/returnToken.test.ts index 7ed81b2..ec1cc5d 100644 --- a/src/__tests__/token-registry-functions/returnToken.test.ts +++ b/src/__tests__/token-registry-functions/returnToken.test.ts @@ -5,13 +5,7 @@ import { Wallet as WalletV6, Network, ethers as ethersV6 } from 'ethersV6'; import * as coreModule from '../../core'; import { CHAIN_ID } from '@tradetrust-tt/tradetrust-utils'; -import { v5Contracts } from '../../token-registry-v5'; -import { v4Contracts } from '../../token-registry-v4'; -import { - acceptReturned, - rejectReturned, - returnToIssuer, -} from '../../token-registry-functions/returnToken'; +import { acceptReturned, rejectReturned, returnToIssuer } from '../../token-registry-functions'; import { MOCK_V4_ADDRESS, MOCK_V5_ADDRESS, @@ -53,6 +47,7 @@ describe('Return Token', () => { const mockRemarks = 'Return remarks'; const mockChainId = CHAIN_ID.local; const mockEncryptedRemarks = '0xencryptedRemarks'; + describe.each(providers)( 'Return Token with TR version $titleEscrowVersion and ethers version $ethersVersion', async ({ Provider, ethersVersion, titleEscrowVersion }) => { @@ -71,11 +66,7 @@ describe('Return Token', () => { } as unknown as Network); } const isV5TT = titleEscrowVersion === 'v5'; - const mockTitleEscrowContract = isV5TT - ? mockV5TitleEscrowContract - : mockV4TitleEscrowContract; const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; - // Handle both v5 and v6 contract constructors beforeAll(() => { // Clear any existing mocks first @@ -83,10 +74,9 @@ describe('Return Token', () => { const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); // Only set up the mock if it hasn't been set up yet vi.mocked(getEthersContractFromProvider).mockReturnValue( - mockContractConstructor(mockTitleEscrowContract), + mockContractConstructor(isV5TT ? mockV5TitleEscrowContract : mockV4TitleEscrowContract), ); }); - beforeEach(() => { vi.clearAllMocks(); vi.spyOn(coreModule, 'getTitleEscrowAddress').mockResolvedValue(titleEscrowAddress); @@ -98,6 +88,8 @@ describe('Return Token', () => { ); mockV5TitleEscrowContract.callStatic.returnToIssuer.mockResolvedValue(true); mockV4TitleEscrowContract.callStatic.surrender.mockResolvedValue(true); + mockV5TitleEscrowContract.returnToIssuer.staticCall.mockResolvedValue(true); + mockV4TitleEscrowContract.surrender.staticCall.mockResolvedValue(true); }); it('should return to issuer with signer and remarks', async () => { @@ -112,9 +104,6 @@ describe('Return Token', () => { expect(result).toEqual(mockTxResponse); expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); - expect( - (isV5TT ? v5Contracts : v4Contracts).TitleEscrow__factory.connect, - ).toHaveBeenCalled(); }); it('should return to issuer without remarks', async () => { @@ -130,14 +119,13 @@ describe('Return Token', () => { }); it('should throw when callStatic fails', async () => { + const mockError = new Error('Simulated failure'); if (isV5TT) { - mockV5TitleEscrowContract.callStatic.returnToIssuer.mockRejectedValue( - new Error('Simulated failure'), - ); + mockV5TitleEscrowContract.callStatic.returnToIssuer.mockRejectedValue(mockError); + mockV5TitleEscrowContract.returnToIssuer.staticCall.mockRejectedValue(mockError); } else { - mockV4TitleEscrowContract.callStatic.surrender.mockRejectedValue( - new Error('Simulated failure'), - ); + mockV4TitleEscrowContract.callStatic.surrender.mockRejectedValue(mockError); + mockV4TitleEscrowContract.surrender.staticCall.mockRejectedValue(mockError); } await expect( @@ -215,7 +203,17 @@ describe('Return Token', () => { } as unknown as Network); } const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; - // const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + beforeAll(() => { + // Clear any existing mocks first + vi.clearAllMocks(); + const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); + // Only set up the mock if it hasn't been set up yet + vi.mocked(getEthersContractFromProvider).mockReturnValue( + mockContractConstructor( + isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract, + ), + ); + }); beforeEach(() => { vi.clearAllMocks(); // vi.spyOn(coreModule, 'encrypt').mockReturnValue(mockEncryptedRemarks.slice(2)); @@ -241,9 +239,6 @@ describe('Return Token', () => { expect(result).toEqual(mockTxResponse); if (isV5TT) expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); - expect( - (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, - ).toHaveBeenCalled(); }); it('should reject returned token without remarks', async () => { @@ -259,11 +254,13 @@ describe('Return Token', () => { }); it('should throw when callStatic fails', async () => { - const mockError = new Error('callStatic error'); + const mockError = new Error('Simulated failure'); if (isV5TT) { mockV5TradeTrustTokenContract.callStatic.restore.mockRejectedValue(mockError); + mockV5TradeTrustTokenContract.restore.staticCall.mockRejectedValue(mockError); } else { mockV4TradeTrustTokenContract.callStatic.restore.mockRejectedValue(mockError); + mockV4TradeTrustTokenContract.restore.staticCall.mockRejectedValue(mockError); } await expect( rejectReturned( @@ -275,8 +272,10 @@ describe('Return Token', () => { ).rejects.toThrow('Pre-check (callStatic) for rejectReturned failed'); if (isV5TT) { mockV5TradeTrustTokenContract.callStatic.restore = vi.fn(); + mockV5TradeTrustTokenContract.restore.staticCall = vi.fn(); } else { mockV4TradeTrustTokenContract.callStatic.restore = vi.fn(); + mockV4TradeTrustTokenContract.restore.staticCall = vi.fn(); } }); @@ -349,7 +348,17 @@ describe('Return Token', () => { } as unknown as Network); } const mockTokenRegistryAddress = isV5TT ? MOCK_V5_ADDRESS : MOCK_V4_ADDRESS; - // const titleEscrowAddress = isV5TT ? '0xv5contract' : '0xv4contract'; + beforeAll(() => { + // Clear any existing mocks first + vi.clearAllMocks(); + const mockContractConstructor = (mockContract: any) => vi.fn(() => mockContract); + // Only set up the mock if it hasn't been set up yet + vi.mocked(getEthersContractFromProvider).mockReturnValue( + mockContractConstructor( + isV5TT ? mockV5TradeTrustTokenContract : mockV4TradeTrustTokenContract, + ), + ); + }); beforeEach(() => { vi.clearAllMocks(); @@ -375,9 +384,6 @@ describe('Return Token', () => { expect(result).toEqual(mockTxResponse); if (isV5TT) expect(coreModule.encrypt).toHaveBeenCalledWith(mockRemarks, 'encryption-id'); - expect( - (isV5TT ? v5Contracts : v4Contracts).TradeTrustToken__factory.connect, - ).toHaveBeenCalled(); }); it('should accept returned token without remarks', async () => { @@ -393,11 +399,13 @@ describe('Return Token', () => { }); it('should throw when callStatic fails', async () => { - const mockError = new Error('callStatic error'); + const mockError = new Error('Simulated failure'); if (isV5TT) { mockV5TradeTrustTokenContract.callStatic.burn.mockRejectedValue(mockError); + mockV5TradeTrustTokenContract.burn.staticCall.mockRejectedValue(mockError); } else { mockV4TradeTrustTokenContract.callStatic.burn.mockRejectedValue(mockError); + mockV4TradeTrustTokenContract.burn.staticCall.mockRejectedValue(mockError); } await expect( acceptReturned( @@ -409,8 +417,10 @@ describe('Return Token', () => { ).rejects.toThrow('Pre-check (callStatic) for acceptReturned failed'); if (isV5TT) { mockV5TradeTrustTokenContract.callStatic.burn = vi.fn(); + mockV5TradeTrustTokenContract.burn.staticCall = vi.fn(); } else { mockV4TradeTrustTokenContract.callStatic.burn = vi.fn(); + mockV4TradeTrustTokenContract.burn.staticCall = vi.fn(); } }); diff --git a/src/token-registry-functions/returnToken.ts b/src/token-registry-functions/returnToken.ts index 3754437..bd6a311 100644 --- a/src/token-registry-functions/returnToken.ts +++ b/src/token-registry-functions/returnToken.ts @@ -7,8 +7,8 @@ import { } from '../core'; import { v5Contracts, v5SupportInterfaceIds } from '../token-registry-v5'; import { v4Contracts, v4SupportInterfaceIds } from '../token-registry-v4'; -import { Signer as SignerV6 } from 'ethersV6'; -import { ContractTransaction, Signer } from 'ethers'; +import { Signer as SignerV6, Contract as ContractV6 } from 'ethersV6'; +import { Contract as ContractV5, ContractTransaction, Signer } from 'ethers'; import { getTxOptions } from './utils'; import { AcceptReturnedOptions, @@ -19,6 +19,7 @@ import { ReturnToIssuerParams, TransactionOptions, } from './types'; +import { getEthersContractFromProvider, isV6EthersProvider } from '../utils/ethers'; /** * Returns the token to the original issuer from the Title Escrow contract. @@ -54,8 +55,8 @@ const returnToIssuer = async ( const { remarks } = params; // Connect V5 contract by default - let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = - v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); + // let titleEscrowContract: v5Contracts.TitleEscrow | v4Contracts.TitleEscrow = + // v5Contracts.TitleEscrow__factory.connect(titleEscrowAddress, signer); const encryptedRemarks = remarks && options.id ? `0x${encrypt(remarks, options.id)}` : '0x'; @@ -82,21 +83,35 @@ const returnToIssuer = async ( throw new Error('Only Token Registry V4/V5 is supported'); } - if (isV4TT) { - titleEscrowContract = v4Contracts.TitleEscrow__factory.connect( + const Contract = getEthersContractFromProvider(signer.provider); + // Connect V5 contract by default + let titleEscrowContract: ContractV5 | ContractV6; + if (isV5TT) { + titleEscrowContract = new Contract( + titleEscrowAddress, + v5Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, + ); + } else if (isV4TT) { + titleEscrowContract = new Contract( titleEscrowAddress, - signer as Signer, + v4Contracts.TitleEscrow__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } // Check callStatic (dry run) try { - if (isV5TT) { - await (titleEscrowContract as v5Contracts.TitleEscrow).callStatic.returnToIssuer( - encryptedRemarks, - ); - } else if (isV4TT) { - await (titleEscrowContract as v4Contracts.TitleEscrow).callStatic.surrender(); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [encryptedRemarks] : []; + const staticCallFxn = isV5TT ? 'returnToIssuer' : 'surrender'; + + if (isV6) { + await (titleEscrowContract as ContractV6)[staticCallFxn].staticCall(...args); + } else { + await (titleEscrowContract as ContractV5).callStatic[staticCallFxn](...args); } } catch (e) { console.error('callStatic failed:', e); @@ -107,12 +122,9 @@ const returnToIssuer = async ( // Send the actual transaction if (isV5TT) { - return await (titleEscrowContract as v5Contracts.TitleEscrow).returnToIssuer( - encryptedRemarks, - txOptions, - ); + return await titleEscrowContract.returnToIssuer(encryptedRemarks, txOptions); } else if (isV4TT) { - return await (titleEscrowContract as v4Contracts.TitleEscrow).surrender(txOptions); + return await titleEscrowContract.surrender(txOptions); } }; @@ -163,30 +175,35 @@ const rejectReturned = async ( if (!isV4TT && !isV5TT) { throw new Error('Only Token Registry V4/V5 is supported'); } + const Contract = getEthersContractFromProvider(signer.provider); // Connect V5 contract by default - let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + let tradeTrustTokenContract: ContractV5 | ContractV6; if (isV5TT) { - tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tradeTrustTokenContract = new Contract( tokenRegistryAddress, - signer, + v5Contracts.TradeTrustToken__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } else if (isV4TT) { - tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tradeTrustTokenContract = new Contract( tokenRegistryAddress, - signer as Signer, + v4Contracts.TradeTrustToken__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } const encryptedRemarks = remarks && isV5TT ? `0x${encrypt(remarks, options.id!)}` : '0x'; // Check callStatic (dry run) try { - if (isV5TT) { - await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).callStatic.restore( - tokenId, - encryptedRemarks, - ); - } else if (isV4TT) { - await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).callStatic.restore(tokenId); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [tokenId, encryptedRemarks] : [tokenId]; + + if (isV6) { + await (tradeTrustTokenContract as ContractV6).restore.staticCall(...args); + } else { + await (tradeTrustTokenContract as ContractV5).callStatic.restore(...args); } } catch (e) { console.error('callStatic failed:', e); @@ -198,16 +215,9 @@ const rejectReturned = async ( // Send the actual transaction if (isV5TT) { - return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).restore( - tokenId, - encryptedRemarks, - txOptions, - ); + return await tradeTrustTokenContract.restore(tokenId, encryptedRemarks, txOptions); } else if (isV4TT) { - return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).restore( - tokenId, - txOptions, - ); + return await tradeTrustTokenContract.restore(tokenId, txOptions); } }; /** @@ -257,17 +267,22 @@ const acceptReturned = async ( if (!isV4TT && !isV5TT) { throw new Error('Only Token Registry V4/V5 is supported'); } + const Contract = getEthersContractFromProvider(signer.provider); // Connect V5 contract by default - let tradeTrustTokenContract: v5Contracts.TradeTrustToken | v4Contracts.TradeTrustToken; + let tradeTrustTokenContract: ContractV5 | ContractV6; if (isV5TT) { - tradeTrustTokenContract = v5Contracts.TradeTrustToken__factory.connect( + tradeTrustTokenContract = new Contract( tokenRegistryAddress, - signer, + v5Contracts.TradeTrustToken__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } else if (isV4TT) { - tradeTrustTokenContract = v4Contracts.TradeTrustToken__factory.connect( + tradeTrustTokenContract = new Contract( tokenRegistryAddress, - signer as Signer, + v4Contracts.TradeTrustToken__factory.abi, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + signer as any, ); } @@ -275,13 +290,13 @@ const acceptReturned = async ( // Check callStatic (dry run) try { - if (isV5TT) { - await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).callStatic.burn( - tokenId, - encryptedRemarks, - ); - } else if (isV4TT) { - await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).callStatic.burn(tokenId); + const isV6 = isV6EthersProvider(signer.provider); + const args = isV5TT ? [encryptedRemarks] : []; + + if (isV6) { + await (tradeTrustTokenContract as ContractV6).burn.staticCall(...args); + } else { + await (tradeTrustTokenContract as ContractV5).callStatic.burn(...args); } } catch (e) { console.error('callStatic failed:', e); @@ -293,13 +308,9 @@ const acceptReturned = async ( // Send the actual transaction if (isV5TT) { - return await (tradeTrustTokenContract as v5Contracts.TradeTrustToken).burn( - tokenId, - encryptedRemarks, - txOptions, - ); + return await tradeTrustTokenContract.burn(tokenId, encryptedRemarks, txOptions); } else if (isV4TT) { - return await (tradeTrustTokenContract as v4Contracts.TradeTrustToken).burn(tokenId, txOptions); + return await tradeTrustTokenContract.burn(tokenId, txOptions); } }; From de2073bb89511abdfa3a19924b3558a7896ec868 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 18 Jul 2025 01:09:39 +0000 Subject: [PATCH 10/14] chore(release): 1.6.0-alpha.3 [skip ci] ## [1.6.0-alpha.3](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.2...v1.6.0-alpha.3) (2025-07-18) ### Bug Fixes * e2e return token tests ([#84](https://github.com/TrustVC/trustvc/issues/84)) ([703be01](https://github.com/TrustVC/trustvc/commit/703be01a0c15d122e4f56af938d40da0901ac30f)) ### Miscellaneous Chores * e2e tests reject transfer ([#83](https://github.com/TrustVC/trustvc/issues/83)) ([58a8da2](https://github.com/TrustVC/trustvc/commit/58a8da209e68cc7aa1928cd507cdee66a3031203)) * e2e transfers tests ([#82](https://github.com/TrustVC/trustvc/issues/82)) ([145e763](https://github.com/TrustVC/trustvc/commit/145e7630a53cac9ed26fd335aee89c2b3677ae95)) --- CHANGELOG.md | 13 +++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddb1913..70fcea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [1.6.0-alpha.3](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.2...v1.6.0-alpha.3) (2025-07-18) + + +### Bug Fixes + +* e2e return token tests ([#84](https://github.com/TrustVC/trustvc/issues/84)) ([703be01](https://github.com/TrustVC/trustvc/commit/703be01a0c15d122e4f56af938d40da0901ac30f)) + + +### Miscellaneous Chores + +* e2e tests reject transfer ([#83](https://github.com/TrustVC/trustvc/issues/83)) ([58a8da2](https://github.com/TrustVC/trustvc/commit/58a8da209e68cc7aa1928cd507cdee66a3031203)) +* e2e transfers tests ([#82](https://github.com/TrustVC/trustvc/issues/82)) ([145e763](https://github.com/TrustVC/trustvc/commit/145e7630a53cac9ed26fd335aee89c2b3677ae95)) + ## [1.6.0-alpha.2](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15) diff --git a/package-lock.json b/package-lock.json index 0cfd4b0..ed5401e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.2", + "version": "1.6.0-alpha.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.2", + "version": "1.6.0-alpha.3", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", diff --git a/package.json b/package.json index 4b121a8..26f29ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.2", + "version": "1.6.0-alpha.3", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From b81b4221bae8f133aef91130c652a585d0855249 Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:30:28 +0530 Subject: [PATCH 11/14] chore: merge main into v1 (#85) * fix: add w3c credential status check (#72) * fix: add w3c credential status check * fix: update test * fix: update enum status codes * fix: remove console * chore(release): 1.5.4 [skip ci] ## [1.5.4](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.5.4) (2025-06-17) ### Bug Fixes * add w3c credential status check ([#72](https://github.com/TrustVC/trustvc/issues/72)) ([0111cb3](https://github.com/TrustVC/trustvc/commit/0111cb3e48ac86f0cea715ceb5277d199f139763)) * fix: upgrade package (#73) * chore(release): 1.5.5 [skip ci] ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) ### Bug Fixes * upgrade package ([#73](https://github.com/TrustVC/trustvc/issues/73)) ([3c6c9c7](https://github.com/TrustVC/trustvc/commit/3c6c9c73675ec43e0514d9afe5df4444f6e4400b)) * feat: support passing titleEscrowAddress to fetchEndorsementChain (#80) Co-authored-by: moiz-sgtradex * chore(release): 1.6.0 [skip ci] ## [1.6.0](https://github.com/TrustVC/trustvc/compare/v1.5.5...v1.6.0) (2025-07-14) ### Features * support passing titleEscrowAddress to fetchEndorsementChain ([#80](https://github.com/TrustVC/trustvc/issues/80)) ([aa7b4f0](https://github.com/TrustVC/trustvc/commit/aa7b4f0e355b1ec97c0dca8c5740a479d59aaeb2)) * feat: add astron v5 (#81) Co-authored-by: maxufeng * chore(release): 1.7.0 [skip ci] ## [1.7.0](https://github.com/TrustVC/trustvc/compare/v1.6.0...v1.7.0) (2025-07-15) ### Features * add astron v5 ([#81](https://github.com/TrustVC/trustvc/issues/81)) ([0bebeae](https://github.com/TrustVC/trustvc/commit/0bebeae60b0b8bc17f892254639465e4f86319b0)) --------- Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Co-authored-by: semantic-release-bot Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Co-authored-by: moiz-sgtradex Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com> Co-authored-by: maxufeng --- CHANGELOG.md | 5 +++++ package-lock.json | 4 ++-- package.json | 2 +- src/__tests__/fixtures/endorsement-chain.ts | 20 +++++++++---------- .../endorsement-chain/useEndorsementChain.ts | 12 ++++++----- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70fcea3..6d1e814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * e2e transfers tests ([#82](https://github.com/TrustVC/trustvc/issues/82)) ([145e763](https://github.com/TrustVC/trustvc/commit/145e7630a53cac9ed26fd335aee89c2b3677ae95)) ## [1.6.0-alpha.2](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15) +## [1.7.0](https://github.com/TrustVC/trustvc/compare/v1.6.0...v1.7.0) (2025-07-15) ### Features @@ -20,6 +21,9 @@ * owner of function ([#79](https://github.com/TrustVC/trustvc/issues/79)) ([81d0e36](https://github.com/TrustVC/trustvc/commit/81d0e3633c1b011bd2b431dbb21854ade2082312)) ## [1.6.0-alpha.1](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.6.0-alpha.1) (2025-06-30) +* add astron v5 ([#81](https://github.com/TrustVC/trustvc/issues/81)) ([0bebeae](https://github.com/TrustVC/trustvc/commit/0bebeae60b0b8bc17f892254639465e4f86319b0)) + +## [1.6.0](https://github.com/TrustVC/trustvc/compare/v1.5.5...v1.6.0) (2025-07-14) ### Features @@ -30,6 +34,7 @@ ### Miscellaneous Chores * back merge ([#75](https://github.com/TrustVC/trustvc/issues/75)) ([7cc1891](https://github.com/TrustVC/trustvc/commit/7cc1891ffebceb4eebf1421d3bc348926efa3f10)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) +* support passing titleEscrowAddress to fetchEndorsementChain ([#80](https://github.com/TrustVC/trustvc/issues/80)) ([aa7b4f0](https://github.com/TrustVC/trustvc/commit/aa7b4f0e355b1ec97c0dca8c5740a479d59aaeb2)) ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) diff --git a/package-lock.json b/package-lock.json index ed5401e..dbaa938 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.3", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.3", + "version": "1.7.0", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", diff --git a/package.json b/package.json index 26f29ac..359107b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.3", + "version": "1.7.0", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", diff --git a/src/__tests__/fixtures/endorsement-chain.ts b/src/__tests__/fixtures/endorsement-chain.ts index 81dff0d..4e9b0a9 100644 --- a/src/__tests__/fixtures/endorsement-chain.ts +++ b/src/__tests__/fixtures/endorsement-chain.ts @@ -3519,18 +3519,18 @@ export const testCases = [ timeout: 180_000, }, { - rpcUrl: `https://astronlayer2.bitfactory.cn/rpc/`, - description: 'Token Registry V4 with Transfer, Surrender, Burnt events - Astron', - tokenRegistryAddress: '0xf717d93c751f1835078b513275b14121798c7740', - tokenId: '0x2820EE82FAA19A68DA11372E69581122C18B9134FE4BC91608155EFAA8370FB3', + rpcUrl: `https://astronlayer2.bitfactory.cn/query/`, + description: 'Token Registry V5 with Transfer, Surrender, Burnt events - Astron', + tokenRegistryAddress: '0x18bc0127Ae33389cD96593a1a612774fD14c0737', + tokenId: '0xfba6e2994c6bf9d845a046d0b63361a305b9a14165c0da5bc17beca635155b61', expected: [ { - blockNumber: 1052524, - holder: '0xCA93690Bb57EEaB273c796a9309246BC0FB93649', - owner: '0xCA93690Bb57EEaB273c796a9309246BC0FB93649', - remark: '', - timestamp: 1731914085000, - transactionHash: '0x7f2b3b92ec86e2d5bbc32c985a4e4d017d387b0b4a253c03cd65733706443f9d', + blockNumber: 5116023, + holder: '0x7C7F27B47976c21ECAda42cE6a15b0e4a1ECC592', + owner: '0x7C7F27B47976c21ECAda42cE6a15b0e4a1ECC592', + remark: '�', + timestamp: 1752233175000, + transactionHash: '0xc83110f001522e26be52f73c7a8a493f14fd171ff46b6ad3a08928e2f809d7b4', transactionIndex: 0, type: 'INITIAL', }, diff --git a/src/core/endorsement-chain/useEndorsementChain.ts b/src/core/endorsement-chain/useEndorsementChain.ts index d5f389c..5d8695d 100644 --- a/src/core/endorsement-chain/useEndorsementChain.ts +++ b/src/core/endorsement-chain/useEndorsementChain.ts @@ -198,20 +198,22 @@ export const fetchEndorsementChain = async ( tokenId: string, provider: Provider | ethersV6.Provider, keyId?: string, + titleEscrowAddress?: string, ): Promise => { if (!tokenRegistryAddress || !tokenId || !provider) { throw new Error('Missing required dependencies'); } - const titleEscrowAddress = await getTitleEscrowAddress(tokenRegistryAddress, tokenId, provider); + const resolvedTitleEscrowAddress = + titleEscrowAddress ?? (await getTitleEscrowAddress(tokenRegistryAddress, tokenId, provider)); const [isV4, isV5] = await Promise.all([ isTitleEscrowVersion({ - titleEscrowAddress, + titleEscrowAddress: resolvedTitleEscrowAddress, versionInterface: TitleEscrowInterface.V4, provider, }), isTitleEscrowVersion({ - titleEscrowAddress, + titleEscrowAddress: resolvedTitleEscrowAddress, versionInterface: TitleEscrowInterface.V5, provider, }), @@ -226,14 +228,14 @@ export const fetchEndorsementChain = async ( if (isV4) { const [tokenLogs, titleEscrowLogs] = await Promise.all([ fetchTokenTransfers(provider, tokenRegistryAddress, tokenId), - fetchEscrowTransfersV4(provider, titleEscrowAddress), + fetchEscrowTransfersV4(provider, resolvedTitleEscrowAddress), ]); transferEvents = mergeTransfersV4([...titleEscrowLogs, ...tokenLogs]); } else if (isV5) { const titleEscrowLogs = await fetchEscrowTransfersV5( provider, - titleEscrowAddress, + resolvedTitleEscrowAddress, tokenRegistryAddress, ); transferEvents = mergeTransfersV5(titleEscrowLogs); From d2fb6fb723cec3005a99e7b89e22a4bdd38d7d2e Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:49:26 +0530 Subject: [PATCH 12/14] fix: trigger release (#86) Co-authored-by: moiz-sgtradex --- src/token-registry-functions/mint.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/token-registry-functions/mint.ts b/src/token-registry-functions/mint.ts index 78a7b91..a111e10 100644 --- a/src/token-registry-functions/mint.ts +++ b/src/token-registry-functions/mint.ts @@ -19,6 +19,7 @@ import { getEthersContractFromProvider, isV6EthersProvider } from '../utils/ethe * @throws {Error} If neither V4 nor V5 interfaces are supported. * @throws {Error} If the `callStatic.mint` fails as a pre-check. */ + const mint = async ( contractOptions: MintTokenOptions, signer: Signer | SignerV6, From bc7405bf0d2bedd51292b49da9c72cd8299ceef0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 23 Jul 2025 06:21:30 +0000 Subject: [PATCH 13/14] chore(release): 1.6.0-alpha.4 [skip ci] ## [1.6.0-alpha.4](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.3...v1.6.0-alpha.4) (2025-07-23) ### Bug Fixes * trigger release ([#86](https://github.com/TrustVC/trustvc/issues/86)) ([d2fb6fb](https://github.com/TrustVC/trustvc/commit/d2fb6fb723cec3005a99e7b89e22a4bdd38d7d2e)) ### Miscellaneous Chores * merge main into v1 ([#85](https://github.com/TrustVC/trustvc/issues/85)) ([b81b422](https://github.com/TrustVC/trustvc/commit/b81b4221bae8f133aef91130c652a585d0855249)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) [#80](https://github.com/TrustVC/trustvc/issues/80) [#80](https://github.com/TrustVC/trustvc/issues/80) [#81](https://github.com/TrustVC/trustvc/issues/81) [#81](https://github.com/TrustVC/trustvc/issues/81) --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d1e814..28d9912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [1.6.0-alpha.4](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.3...v1.6.0-alpha.4) (2025-07-23) + + +### Bug Fixes + +* trigger release ([#86](https://github.com/TrustVC/trustvc/issues/86)) ([d2fb6fb](https://github.com/TrustVC/trustvc/commit/d2fb6fb723cec3005a99e7b89e22a4bdd38d7d2e)) + + +### Miscellaneous Chores + +* merge main into v1 ([#85](https://github.com/TrustVC/trustvc/issues/85)) ([b81b422](https://github.com/TrustVC/trustvc/commit/b81b4221bae8f133aef91130c652a585d0855249)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) [#80](https://github.com/TrustVC/trustvc/issues/80) [#80](https://github.com/TrustVC/trustvc/issues/80) [#81](https://github.com/TrustVC/trustvc/issues/81) [#81](https://github.com/TrustVC/trustvc/issues/81) + ## [1.6.0-alpha.3](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.2...v1.6.0-alpha.3) (2025-07-18) diff --git a/package-lock.json b/package-lock.json index dbaa938..c74343b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@trustvc/trustvc", - "version": "1.7.0", + "version": "1.6.0-alpha.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.7.0", + "version": "1.6.0-alpha.4", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.17.0", diff --git a/package.json b/package.json index 359107b..c2be7b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.7.0", + "version": "1.6.0-alpha.4", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From b54b1469b4603295fb02321fd068497b59348d35 Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 30 Jul 2025 10:55:13 +0530 Subject: [PATCH 14/14] chore: rebase v1 with main (#95) * fix: add w3c credential status check (#72) * fix: add w3c credential status check * fix: update test * fix: update enum status codes * fix: remove console * chore(release): 1.5.4 [skip ci] ## [1.5.4](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.5.4) (2025-06-17) ### Bug Fixes * add w3c credential status check ([#72](https://github.com/TrustVC/trustvc/issues/72)) ([0111cb3](https://github.com/TrustVC/trustvc/commit/0111cb3e48ac86f0cea715ceb5277d199f139763)) * fix: upgrade package (#73) * chore(release): 1.5.5 [skip ci] ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) ### Bug Fixes * upgrade package ([#73](https://github.com/TrustVC/trustvc/issues/73)) ([3c6c9c7](https://github.com/TrustVC/trustvc/commit/3c6c9c73675ec43e0514d9afe5df4444f6e4400b)) * feat: support passing titleEscrowAddress to fetchEndorsementChain (#80) Co-authored-by: moiz-sgtradex * chore(release): 1.6.0 [skip ci] ## [1.6.0](https://github.com/TrustVC/trustvc/compare/v1.5.5...v1.6.0) (2025-07-14) ### Features * support passing titleEscrowAddress to fetchEndorsementChain ([#80](https://github.com/TrustVC/trustvc/issues/80)) ([aa7b4f0](https://github.com/TrustVC/trustvc/commit/aa7b4f0e355b1ec97c0dca8c5740a479d59aaeb2)) * feat: add astron v5 (#81) Co-authored-by: maxufeng * chore(release): 1.7.0 [skip ci] ## [1.7.0](https://github.com/TrustVC/trustvc/compare/v1.6.0...v1.7.0) (2025-07-15) ### Features * add astron v5 ([#81](https://github.com/TrustVC/trustvc/issues/81)) ([0bebeae](https://github.com/TrustVC/trustvc/commit/0bebeae60b0b8bc17f892254639465e4f86319b0)) * fix: update tradetrust-tt/tradetrust package (#87) * fix: update tradetrust-tt/tradetrust package * fix: update version * fix: update imports * chore(release): 1.7.1 [skip ci] ## [1.7.1](https://github.com/TrustVC/trustvc/compare/v1.7.0...v1.7.1) (2025-07-25) ### Bug Fixes * update tradetrust-tt/tradetrust package ([#87](https://github.com/TrustVC/trustvc/issues/87)) ([e4f75a4](https://github.com/TrustVC/trustvc/commit/e4f75a472cc046c68203241c977262572c50be13)) * fix: upgrade packages (#88) * chore(release): 1.7.2 [skip ci] ## [1.7.2](https://github.com/TrustVC/trustvc/compare/v1.7.1...v1.7.2) (2025-07-28) ### Bug Fixes * upgrade packages ([#88](https://github.com/TrustVC/trustvc/issues/88)) ([0cc314e](https://github.com/TrustVC/trustvc/commit/0cc314e3043525e5fcd7edaed029d9ba22d6d66b)) * fix: error message types (#89) * chore(release): 1.7.3 [skip ci] ## [1.7.3](https://github.com/TrustVC/trustvc/compare/v1.7.2...v1.7.3) (2025-07-28) ### Bug Fixes * error message types ([#89](https://github.com/TrustVC/trustvc/issues/89)) ([d83bada](https://github.com/TrustVC/trustvc/commit/d83bada0a7b73c86370b7fef8e5d0bdb025449ff)) * fix: upgrade packages (#90) * chore(release): 1.7.4 [skip ci] ## [1.7.4](https://github.com/TrustVC/trustvc/compare/v1.7.3...v1.7.4) (2025-07-29) ### Bug Fixes * upgrade packages ([#90](https://github.com/TrustVC/trustvc/issues/90)) ([758651d](https://github.com/TrustVC/trustvc/commit/758651d30a358a614192bcd26ce7df33bd5874b0)) --------- Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Co-authored-by: semantic-release-bot Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Co-authored-by: moiz-sgtradex Co-authored-by: caict-develop-zhangbo <68949988+caict-develop-zhangbo@users.noreply.github.com> Co-authored-by: maxufeng --- CHANGELOG.md | 32 +- package-lock.json | 2275 +++++++++++++++--------------- package.json | 12 +- src/core/documentBuilder.ts | 2 +- src/utils/errorMessages/index.ts | 9 +- src/utils/errorMessages/types.ts | 26 + 6 files changed, 1226 insertions(+), 1130 deletions(-) create mode 100644 src/utils/errorMessages/types.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d9912..db2c814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,38 +1,36 @@ -## [1.6.0-alpha.4](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.3...v1.6.0-alpha.4) (2025-07-23) +## [1.7.4](https://github.com/TrustVC/trustvc/compare/v1.7.3...v1.7.4) (2025-07-29) ### Bug Fixes -* trigger release ([#86](https://github.com/TrustVC/trustvc/issues/86)) ([d2fb6fb](https://github.com/TrustVC/trustvc/commit/d2fb6fb723cec3005a99e7b89e22a4bdd38d7d2e)) +* upgrade packages ([#90](https://github.com/TrustVC/trustvc/issues/90)) ([758651d](https://github.com/TrustVC/trustvc/commit/758651d30a358a614192bcd26ce7df33bd5874b0)) +## [1.7.3](https://github.com/TrustVC/trustvc/compare/v1.7.2...v1.7.3) (2025-07-28) -### Miscellaneous Chores -* merge main into v1 ([#85](https://github.com/TrustVC/trustvc/issues/85)) ([b81b422](https://github.com/TrustVC/trustvc/commit/b81b4221bae8f133aef91130c652a585d0855249)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) [#80](https://github.com/TrustVC/trustvc/issues/80) [#80](https://github.com/TrustVC/trustvc/issues/80) [#81](https://github.com/TrustVC/trustvc/issues/81) [#81](https://github.com/TrustVC/trustvc/issues/81) +### Bug Fixes + +* error message types ([#89](https://github.com/TrustVC/trustvc/issues/89)) ([d83bada](https://github.com/TrustVC/trustvc/commit/d83bada0a7b73c86370b7fef8e5d0bdb025449ff)) -## [1.6.0-alpha.3](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.2...v1.6.0-alpha.3) (2025-07-18) +## [1.7.2](https://github.com/TrustVC/trustvc/compare/v1.7.1...v1.7.2) (2025-07-28) ### Bug Fixes -* e2e return token tests ([#84](https://github.com/TrustVC/trustvc/issues/84)) ([703be01](https://github.com/TrustVC/trustvc/commit/703be01a0c15d122e4f56af938d40da0901ac30f)) +* upgrade packages ([#88](https://github.com/TrustVC/trustvc/issues/88)) ([0cc314e](https://github.com/TrustVC/trustvc/commit/0cc314e3043525e5fcd7edaed029d9ba22d6d66b)) +## [1.7.1](https://github.com/TrustVC/trustvc/compare/v1.7.0...v1.7.1) (2025-07-25) -### Miscellaneous Chores -* e2e tests reject transfer ([#83](https://github.com/TrustVC/trustvc/issues/83)) ([58a8da2](https://github.com/TrustVC/trustvc/commit/58a8da209e68cc7aa1928cd507cdee66a3031203)) -* e2e transfers tests ([#82](https://github.com/TrustVC/trustvc/issues/82)) ([145e763](https://github.com/TrustVC/trustvc/commit/145e7630a53cac9ed26fd335aee89c2b3677ae95)) +### Bug Fixes + +* update tradetrust-tt/tradetrust package ([#87](https://github.com/TrustVC/trustvc/issues/87)) ([e4f75a4](https://github.com/TrustVC/trustvc/commit/e4f75a472cc046c68203241c977262572c50be13)) -## [1.6.0-alpha.2](https://github.com/TrustVC/trustvc/compare/v1.6.0-alpha.1...v1.6.0-alpha.2) (2025-07-15) ## [1.7.0](https://github.com/TrustVC/trustvc/compare/v1.6.0...v1.7.0) (2025-07-15) ### Features -* mint function ([#78](https://github.com/TrustVC/trustvc/issues/78)) ([2ea52ce](https://github.com/TrustVC/trustvc/commit/2ea52ce2ed010ba2da095d6444f135f014dbb442)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) [#72](https://github.com/TrustVC/trustvc/issues/72) -* owner of function ([#79](https://github.com/TrustVC/trustvc/issues/79)) ([81d0e36](https://github.com/TrustVC/trustvc/commit/81d0e3633c1b011bd2b431dbb21854ade2082312)) - -## [1.6.0-alpha.1](https://github.com/TrustVC/trustvc/compare/v1.5.3...v1.6.0-alpha.1) (2025-06-30) * add astron v5 ([#81](https://github.com/TrustVC/trustvc/issues/81)) ([0bebeae](https://github.com/TrustVC/trustvc/commit/0bebeae60b0b8bc17f892254639465e4f86319b0)) ## [1.6.0](https://github.com/TrustVC/trustvc/compare/v1.5.5...v1.6.0) (2025-07-14) @@ -40,12 +38,6 @@ ### Features -* token registry functions ([#74](https://github.com/TrustVC/trustvc/issues/74)) ([5690fcd](https://github.com/TrustVC/trustvc/commit/5690fcda798192609b0060fab0a3f3f77dca8012)) - - -### Miscellaneous Chores - -* back merge ([#75](https://github.com/TrustVC/trustvc/issues/75)) ([7cc1891](https://github.com/TrustVC/trustvc/commit/7cc1891ffebceb4eebf1421d3bc348926efa3f10)), closes [#72](https://github.com/TrustVC/trustvc/issues/72) [#72](https://github.com/TrustVC/trustvc/issues/72) [#73](https://github.com/TrustVC/trustvc/issues/73) [#73](https://github.com/TrustVC/trustvc/issues/73) * support passing titleEscrowAddress to fetchEndorsementChain ([#80](https://github.com/TrustVC/trustvc/issues/80)) ([aa7b4f0](https://github.com/TrustVC/trustvc/commit/aa7b4f0e355b1ec97c0dca8c5740a479d59aaeb2)) ## [1.5.5](https://github.com/TrustVC/trustvc/compare/v1.5.4...v1.5.5) (2025-06-18) diff --git a/package-lock.json b/package-lock.json index c74343b..b07b207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,21 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.4", + "version": "1.7.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.4", + "version": "1.7.4", "license": "Apache-2.0", "dependencies": { - "@tradetrust-tt/dnsprove": "^2.17.0", + "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.4", "@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0", - "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.3.0", - "@tradetrust-tt/tradetrust": "^6.10.1", - "@tradetrust-tt/tradetrust-utils": "^2.3.2", - "@tradetrust-tt/tt-verify": "^9.4.0", + "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.5.0", + "@tradetrust-tt/tradetrust": "^6.10.2", + "@tradetrust-tt/tradetrust-utils": "^2.4.2", + "@tradetrust-tt/tt-verify": "^9.5.1", "@trustvc/w3c-context": "^1.2.13", "@trustvc/w3c-credential-status": "^1.2.13", "@trustvc/w3c-issuer": "^1.2.4", @@ -175,7 +175,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", @@ -190,7 +189,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -202,7 +200,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" @@ -215,7 +212,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" @@ -228,7 +224,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", @@ -242,7 +237,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" } @@ -251,7 +245,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", @@ -262,7 +255,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -274,7 +266,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" @@ -287,7 +278,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" @@ -297,48 +287,47 @@ } }, "node_modules/@aws-sdk/client-kms": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.830.0.tgz", - "integrity": "sha512-y24IvqKn21nF13tkhsKMCKcz0/z6UEePvpV5JAWwZSUmNJj2spagucD/ksykNqBPalbNZIuTicUqtHyBtYAWYQ==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.848.0.tgz", + "integrity": "sha512-kMb40oqSrEKtQChgdkJi5pCAWCFvthttgiGugwoXFZ/vDv54XRKGClAVzJ/b51Dkh1NLmuWgteXVtnDsfo9PHg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.826.0", - "@aws-sdk/credential-provider-node": "3.830.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.828.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.828.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/credential-provider-node": "3.848.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.848.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.848.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.848.0", "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.5.3", - "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/core": "^3.7.0", + "@smithy/fetch-http-handler": "^5.1.0", "@smithy/hash-node": "^4.0.4", "@smithy/invalid-dependency": "^4.0.4", "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.11", - "@smithy/middleware-retry": "^4.1.12", + "@smithy/middleware-endpoint": "^4.1.15", + "@smithy/middleware-retry": "^4.1.16", "@smithy/middleware-serde": "^4.0.8", "@smithy/middleware-stack": "^4.0.4", "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", + "@smithy/node-http-handler": "^4.1.0", "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.7", "@smithy/types": "^4.3.1", "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.19", - "@smithy/util-defaults-mode-node": "^4.0.19", + "@smithy/util-defaults-mode-browser": "^4.0.23", + "@smithy/util-defaults-mode-node": "^4.0.23", "@smithy/util-endpoints": "^3.0.6", "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.5", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -347,47 +336,46 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.830.0.tgz", - "integrity": "sha512-5zCEpfI+zwX2SIa258L+TItNbBoAvQQ6w74qdFM6YJufQ1F9tvwjTX8T+eSTT9nsFIvfYnUaGalWwJVfmJUgVQ==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.848.0.tgz", + "integrity": "sha512-mD+gOwoeZQvbecVLGoCmY6pS7kg02BHesbtIxUj+PeBqYoZV5uLvjUOmuGfw1SfoSobKvS11urxC9S7zxU/Maw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.826.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.828.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.828.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.848.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.848.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.848.0", "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.5.3", - "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/core": "^3.7.0", + "@smithy/fetch-http-handler": "^5.1.0", "@smithy/hash-node": "^4.0.4", "@smithy/invalid-dependency": "^4.0.4", "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.11", - "@smithy/middleware-retry": "^4.1.12", + "@smithy/middleware-endpoint": "^4.1.15", + "@smithy/middleware-retry": "^4.1.16", "@smithy/middleware-serde": "^4.0.8", "@smithy/middleware-stack": "^4.0.4", "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", + "@smithy/node-http-handler": "^4.1.0", "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.7", "@smithy/types": "^4.3.1", "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.19", - "@smithy/util-defaults-mode-node": "^4.0.19", + "@smithy/util-defaults-mode-browser": "^4.0.23", + "@smithy/util-defaults-mode-node": "^4.0.23", "@smithy/util-endpoints": "^3.0.6", "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.5", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -396,25 +384,24 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", - "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", - "license": "Apache-2.0", + "version": "3.846.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.846.0.tgz", + "integrity": "sha512-7CX0pM906r4WSS68fCTNMTtBCSkTtf3Wggssmx13gD40gcWEZXsU00KzPp1bYheNRyPlAq3rE22xt4wLPXbuxA==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.5.3", + "@smithy/core": "^3.7.0", "@smithy/node-config-provider": "^4.1.3", "@smithy/property-provider": "^4.0.4", "@smithy/protocol-http": "^5.1.2", "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.7", "@smithy/types": "^4.3.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.4", "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" }, "engines": { @@ -422,13 +409,12 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.826.0.tgz", - "integrity": "sha512-DK3pQY8+iKK3MGDdC3uOZQ2psU01obaKlTYhEwNu4VWzgwQL4Vi3sWj4xSWGEK41vqZxiRLq6fOq7ysRI+qEZA==", - "license": "Apache-2.0", + "version": "3.846.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.846.0.tgz", + "integrity": "sha512-QuCQZET9enja7AWVISY+mpFrEIeHzvkx/JEEbHYzHhUkxcnC2Kq2c0bB7hDihGD0AZd3Xsm653hk1O97qu69zg==", "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/types": "3.821.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/types": "3.840.0", "@smithy/property-provider": "^4.0.4", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -438,20 +424,19 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.826.0.tgz", - "integrity": "sha512-N+IVZBh+yx/9GbMZTKO/gErBi/FYZQtcFRItoLbY+6WU+0cSWyZYfkoeOxHmQV3iX9k65oljERIWUmL9x6OSQg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/types": "3.821.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", + "version": "3.846.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.846.0.tgz", + "integrity": "sha512-Jh1iKUuepdmtreMYozV2ePsPcOF5W9p3U4tWhi3v6nDvz0GsBjzjAROW+BW8XMz9vAD3I9R+8VC3/aq63p5nlw==", + "dependencies": { + "@aws-sdk/core": "3.846.0", + "@aws-sdk/types": "3.840.0", + "@smithy/fetch-http-handler": "^5.1.0", + "@smithy/node-http-handler": "^4.1.0", "@smithy/property-provider": "^4.0.4", "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.7", "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@smithy/util-stream": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -459,19 +444,18 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.830.0.tgz", - "integrity": "sha512-zeQenzvh8JRY5nULd8izdjVGoCM1tgsVVsrLSwDkHxZTTW0hW/bmOmXfvdaE0wDdomXW7m2CkQDSmP7XdvNXZg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/credential-provider-env": "3.826.0", - "@aws-sdk/credential-provider-http": "3.826.0", - "@aws-sdk/credential-provider-process": "3.826.0", - "@aws-sdk/credential-provider-sso": "3.830.0", - "@aws-sdk/credential-provider-web-identity": "3.830.0", - "@aws-sdk/nested-clients": "3.830.0", - "@aws-sdk/types": "3.821.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.848.0.tgz", + "integrity": "sha512-r6KWOG+En2xujuMhgZu7dzOZV3/M5U/5+PXrG8dLQ3rdPRB3vgp5tc56KMqLwm/EXKRzAOSuw/UE4HfNOAB8Hw==", + "dependencies": { + "@aws-sdk/core": "3.846.0", + "@aws-sdk/credential-provider-env": "3.846.0", + "@aws-sdk/credential-provider-http": "3.846.0", + "@aws-sdk/credential-provider-process": "3.846.0", + "@aws-sdk/credential-provider-sso": "3.848.0", + "@aws-sdk/credential-provider-web-identity": "3.848.0", + "@aws-sdk/nested-clients": "3.848.0", + "@aws-sdk/types": "3.840.0", "@smithy/credential-provider-imds": "^4.0.6", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -483,18 +467,17 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.830.0.tgz", - "integrity": "sha512-X/2LrTgwtK1pkWrvofxQBI8VTi6QVLtSMpsKKPPnJQ0vgqC0e4czSIs3ZxiEsOkCBaQ2usXSiKyh0ccsQ6k2OA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.826.0", - "@aws-sdk/credential-provider-http": "3.826.0", - "@aws-sdk/credential-provider-ini": "3.830.0", - "@aws-sdk/credential-provider-process": "3.826.0", - "@aws-sdk/credential-provider-sso": "3.830.0", - "@aws-sdk/credential-provider-web-identity": "3.830.0", - "@aws-sdk/types": "3.821.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.848.0.tgz", + "integrity": "sha512-AblNesOqdzrfyASBCo1xW3uweiSro4Kft9/htdxLeCVU1KVOnFWA5P937MNahViRmIQm2sPBCqL8ZG0u9lnh5g==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.846.0", + "@aws-sdk/credential-provider-http": "3.846.0", + "@aws-sdk/credential-provider-ini": "3.848.0", + "@aws-sdk/credential-provider-process": "3.846.0", + "@aws-sdk/credential-provider-sso": "3.848.0", + "@aws-sdk/credential-provider-web-identity": "3.848.0", + "@aws-sdk/types": "3.840.0", "@smithy/credential-provider-imds": "^4.0.6", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -506,13 +489,12 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.826.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.826.0.tgz", - "integrity": "sha512-kURrc4amu3NLtw1yZw7EoLNEVhmOMRUTs+chaNcmS+ERm3yK0nKjaJzmKahmwlTQTSl3wJ8jjK7x962VPo+zWw==", - "license": "Apache-2.0", + "version": "3.846.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.846.0.tgz", + "integrity": "sha512-mEpwDYarJSH+CIXnnHN0QOe0MXI+HuPStD6gsv3z/7Q6ESl8KRWon3weFZCDnqpiJMUVavlDR0PPlAFg2MQoPg==", "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/types": "3.821.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/types": "3.840.0", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", "@smithy/types": "^4.3.1", @@ -523,15 +505,14 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.830.0.tgz", - "integrity": "sha512-+VdRpZmfekzpySqZikAKx6l5ndnLGluioIgUG4ZznrButgFD/iogzFtGmBDFB3ZLViX1l4pMXru0zFwJEZT21Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.830.0", - "@aws-sdk/core": "3.826.0", - "@aws-sdk/token-providers": "3.830.0", - "@aws-sdk/types": "3.821.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.848.0.tgz", + "integrity": "sha512-pozlDXOwJZL0e7w+dqXLgzVDB7oCx4WvtY0sk6l4i07uFliWF/exupb6pIehFWvTUcOvn5aFTTqcQaEzAD5Wsg==", + "dependencies": { + "@aws-sdk/client-sso": "3.848.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/token-providers": "3.848.0", + "@aws-sdk/types": "3.840.0", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", "@smithy/types": "^4.3.1", @@ -542,14 +523,13 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.830.0.tgz", - "integrity": "sha512-hPYrKsZeeOdLROJ59T6Y8yZ0iwC/60L3qhZXjapBFjbqBtMaQiMTI645K6xVXBioA6vxXq7B4aLOhYqk6Fy/Ww==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.848.0.tgz", + "integrity": "sha512-D1fRpwPxtVDhcSc/D71exa2gYweV+ocp4D3brF0PgFd//JR3XahZ9W24rVnTQwYEcK9auiBZB89Ltv+WbWN8qw==", "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/nested-clients": "3.830.0", - "@aws-sdk/types": "3.821.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/nested-clients": "3.848.0", + "@aws-sdk/types": "3.840.0", "@smithy/property-provider": "^4.0.4", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -559,12 +539,11 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", - "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.840.0.tgz", + "integrity": "sha512-ub+hXJAbAje94+Ya6c6eL7sYujoE8D4Bumu1NUI8TXjUhVVn0HzVWQjpRLshdLsUp1AW7XyeJaxyajRaJQ8+Xg==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -574,12 +553,11 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", - "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.840.0.tgz", + "integrity": "sha512-lSV8FvjpdllpGaRspywss4CtXV8M7NNNH+2/j86vMH+YCOZ6fu2T/TyFd/tHwZ92vDfHctWkRbQxg0bagqwovA==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, @@ -588,12 +566,11 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", - "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.840.0.tgz", + "integrity": "sha512-Gu7lGDyfddyhIkj1Z1JtrY5NHb5+x/CRiB87GjaSrKxkDaydtX2CU977JIABtt69l9wLbcGDIQ+W0uJ5xPof7g==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -603,15 +580,14 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.828.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.828.0.tgz", - "integrity": "sha512-nixvI/SETXRdmrVab4D9LvXT3lrXkwAWGWk2GVvQvzlqN1/M/RfClj+o37Sn4FqRkGH9o9g7Fqb1YqZ4mqDAtA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@smithy/core": "^3.5.3", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.848.0.tgz", + "integrity": "sha512-rjMuqSWJEf169/ByxvBqfdei1iaduAnfolTshsZxwcmLIUtbYrFUmts0HrLQqsAG8feGPpDLHA272oPl+NTCCA==", + "dependencies": { + "@aws-sdk/core": "3.846.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.848.0", + "@smithy/core": "^3.7.0", "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -621,47 +597,46 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.830.0.tgz", - "integrity": "sha512-5N5YTlBr1vtxf7+t+UaIQ625KEAmm7fY9o1e3MgGOi/paBoI0+axr3ud24qLIy0NSzFlAHEaxUSWxcERNjIoZw==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.848.0.tgz", + "integrity": "sha512-joLsyyo9u61jnZuyYzo1z7kmS7VgWRAkzSGESVzQHfOA1H2PYeUFek6vLT4+c9xMGrX/Z6B0tkRdzfdOPiatLg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.826.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.828.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.828.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.848.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.848.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.848.0", "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.5.3", - "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/core": "^3.7.0", + "@smithy/fetch-http-handler": "^5.1.0", "@smithy/hash-node": "^4.0.4", "@smithy/invalid-dependency": "^4.0.4", "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.11", - "@smithy/middleware-retry": "^4.1.12", + "@smithy/middleware-endpoint": "^4.1.15", + "@smithy/middleware-retry": "^4.1.16", "@smithy/middleware-serde": "^4.0.8", "@smithy/middleware-stack": "^4.0.4", "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", + "@smithy/node-http-handler": "^4.1.0", "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.7", "@smithy/types": "^4.3.1", "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.19", - "@smithy/util-defaults-mode-node": "^4.0.19", + "@smithy/util-defaults-mode-browser": "^4.0.23", + "@smithy/util-defaults-mode-node": "^4.0.23", "@smithy/util-endpoints": "^3.0.6", "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.5", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -670,12 +645,11 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", - "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.840.0.tgz", + "integrity": "sha512-Qjnxd/yDv9KpIMWr90ZDPtRj0v75AqGC92Lm9+oHXZ8p1MjG5JE2CW0HL8JRgK9iKzgKBL7pPQRXI8FkvEVfrA==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@smithy/node-config-provider": "^4.1.3", "@smithy/types": "^4.3.1", "@smithy/util-config-provider": "^4.0.0", @@ -687,14 +661,13 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.830.0.tgz", - "integrity": "sha512-aJ4guFwj92nV9D+EgJPaCFKK0I3y2uMchiDfh69Zqnmwfxxxfxat6F79VA7PS0BdbjRfhLbn+Ghjftnomu2c1g==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.848.0.tgz", + "integrity": "sha512-oNPyM4+Di2Umu0JJRFSxDcKQ35+Chl/rAwD47/bS0cDPI8yrao83mLXLeDqpRPHyQW4sXlP763FZcuAibC0+mg==", "dependencies": { - "@aws-sdk/core": "3.826.0", - "@aws-sdk/nested-clients": "3.830.0", - "@aws-sdk/types": "3.821.0", + "@aws-sdk/core": "3.846.0", + "@aws-sdk/nested-clients": "3.848.0", + "@aws-sdk/types": "3.840.0", "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", "@smithy/types": "^4.3.1", @@ -705,10 +678,9 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", - "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -718,13 +690,13 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.828.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.828.0.tgz", - "integrity": "sha512-RvKch111SblqdkPzg3oCIdlGxlQs+k+P7Etory9FmxPHyPDvsP1j1c74PmgYqtzzMWmoXTjd+c9naUHh9xG8xg==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.848.0.tgz", + "integrity": "sha512-fY/NuFFCq/78liHvRyFKr+aqq1aA/uuVSANjzr5Ym8c+9Z3HRPE9OrExAHoMrZ6zC8tHerQwlsXYYH5XZ7H+ww==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-endpoints": "^3.0.6", "tslib": "^2.6.2" }, @@ -736,7 +708,6 @@ "version": "3.804.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.804.0.tgz", "integrity": "sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -745,25 +716,23 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", - "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.840.0.tgz", + "integrity": "sha512-JdyZM3EhhL4PqwFpttZu1afDpPJCCc3eyZOLi+srpX11LsGj6sThf47TYQN75HT1CarZ7cCdQHGzP2uy3/xHfQ==", "dependencies": { - "@aws-sdk/types": "3.821.0", + "@aws-sdk/types": "3.840.0", "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.828.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.828.0.tgz", - "integrity": "sha512-LdN6fTBzTlQmc8O8f1wiZN0qF3yBWVGis7NwpWK7FUEzP9bEZRxYfIkV9oV9zpt6iNRze1SedK3JQVB/udxBoA==", - "license": "Apache-2.0", + "version": "3.848.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.848.0.tgz", + "integrity": "sha512-Zz1ft9NiLqbzNj/M0jVNxaoxI2F4tGXN0ZbZIj+KJ+PbJo+w5+Jo6d0UDAtbj3AEd79pjcCaP4OA9NTVzItUdw==", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.828.0", - "@aws-sdk/types": "3.821.0", + "@aws-sdk/middleware-user-agent": "3.848.0", + "@aws-sdk/types": "3.840.0", "@smithy/node-config-provider": "^4.1.3", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -784,7 +753,6 @@ "version": "3.821.0", "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -794,44 +762,44 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", - "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "dev": true, "dependencies": { - "@babel/types": "^7.26.7" + "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -841,13 +809,13 @@ } }, "node_modules/@babel/types": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", - "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -870,17 +838,17 @@ } }, "node_modules/@commitlint/cli": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.8.0.tgz", - "integrity": "sha512-t/fCrLVu+Ru01h0DtlgHZXbHV2Y8gKocTR5elDOqIRUzQd0/6hpt2VIWOj9b3NDo7y4/gfxeR2zRtXq/qO6iUg==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.8.1.tgz", + "integrity": "sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==", "dev": true, "dependencies": { - "@commitlint/format": "^19.8.0", - "@commitlint/lint": "^19.8.0", - "@commitlint/load": "^19.8.0", - "@commitlint/read": "^19.8.0", - "@commitlint/types": "^19.8.0", - "tinyexec": "^0.3.0", + "@commitlint/format": "^19.8.1", + "@commitlint/lint": "^19.8.1", + "@commitlint/load": "^19.8.1", + "@commitlint/read": "^19.8.1", + "@commitlint/types": "^19.8.1", + "tinyexec": "^1.0.0", "yargs": "^17.0.0" }, "bin": { @@ -891,12 +859,12 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.8.0.tgz", - "integrity": "sha512-9I2kKJwcAPwMoAj38hwqFXG0CzS2Kj+SAByPUQ0SlHTfb7VUhYVmo7G2w2tBrqmOf7PFd6MpZ/a1GQJo8na8kw==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz", + "integrity": "sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0", + "@commitlint/types": "^19.8.1", "conventional-changelog-conventionalcommits": "^7.0.2" }, "engines": { @@ -904,12 +872,12 @@ } }, "node_modules/@commitlint/config-nx-scopes": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-nx-scopes/-/config-nx-scopes-19.8.0.tgz", - "integrity": "sha512-cHyonFkbKN12EYFjnb5+CgNJZYMRTUBmkNLhnecRVZcB5qlQREs9kqqmrS6Vahme8PD2gmPA7I6b7kFfMHqRoQ==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-nx-scopes/-/config-nx-scopes-19.8.1.tgz", + "integrity": "sha512-BPkNs+grzc0bPmQCCP52Ml1FnGmS4JESOuD61Rz0oO/SaM0GM5+0XJBThb7xdgpu4YltH8tYBg5cVqVu93CMug==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0" + "@commitlint/types": "^19.8.1" }, "engines": { "node": ">=v18" @@ -924,12 +892,12 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.0.tgz", - "integrity": "sha512-+r5ZvD/0hQC3w5VOHJhGcCooiAVdynFlCe2d6I9dU+PvXdV3O+fU4vipVg+6hyLbQUuCH82mz3HnT/cBQTYYuA==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz", + "integrity": "sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0", + "@commitlint/types": "^19.8.1", "ajv": "^8.11.0" }, "engines": { @@ -937,12 +905,12 @@ } }, "node_modules/@commitlint/ensure": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.8.0.tgz", - "integrity": "sha512-kNiNU4/bhEQ/wutI1tp1pVW1mQ0QbAjfPRo5v8SaxoVV+ARhkB8Wjg3BSseNYECPzWWfg/WDqQGIfV1RaBFQZg==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.8.1.tgz", + "integrity": "sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0", + "@commitlint/types": "^19.8.1", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -954,21 +922,21 @@ } }, "node_modules/@commitlint/execute-rule": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.8.0.tgz", - "integrity": "sha512-fuLeI+EZ9x2v/+TXKAjplBJWI9CNrHnyi5nvUQGQt4WRkww/d95oVRsc9ajpt4xFrFmqMZkd/xBQHZDvALIY7A==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz", + "integrity": "sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==", "dev": true, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/format": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.8.0.tgz", - "integrity": "sha512-EOpA8IERpQstxwp/WGnDArA7S+wlZDeTeKi98WMOvaDLKbjptuHWdOYYr790iO7kTCif/z971PKPI2PkWMfOxg==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.8.1.tgz", + "integrity": "sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0", + "@commitlint/types": "^19.8.1", "chalk": "^5.3.0" }, "engines": { @@ -976,12 +944,12 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.8.0.tgz", - "integrity": "sha512-L2Jv9yUg/I+jF3zikOV0rdiHUul9X3a/oU5HIXhAJLE2+TXTnEBfqYP9G5yMw/Yb40SnR764g4fyDK6WR2xtpw==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz", + "integrity": "sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0", + "@commitlint/types": "^19.8.1", "semver": "^7.6.0" }, "engines": { @@ -989,30 +957,30 @@ } }, "node_modules/@commitlint/lint": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.0.tgz", - "integrity": "sha512-+/NZKyWKSf39FeNpqhfMebmaLa1P90i1Nrb1SrA7oSU5GNN/lksA4z6+ZTnsft01YfhRZSYMbgGsARXvkr/VLQ==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.1.tgz", + "integrity": "sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==", "dev": true, "dependencies": { - "@commitlint/is-ignored": "^19.8.0", - "@commitlint/parse": "^19.8.0", - "@commitlint/rules": "^19.8.0", - "@commitlint/types": "^19.8.0" + "@commitlint/is-ignored": "^19.8.1", + "@commitlint/parse": "^19.8.1", + "@commitlint/rules": "^19.8.1", + "@commitlint/types": "^19.8.1" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.8.0.tgz", - "integrity": "sha512-4rvmm3ff81Sfb+mcWT5WKlyOa+Hd33WSbirTVUer0wjS1Hv/Hzr07Uv1ULIV9DkimZKNyOwXn593c+h8lsDQPQ==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.8.1.tgz", + "integrity": "sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^19.8.0", - "@commitlint/execute-rule": "^19.8.0", - "@commitlint/resolve-extends": "^19.8.0", - "@commitlint/types": "^19.8.0", + "@commitlint/config-validator": "^19.8.1", + "@commitlint/execute-rule": "^19.8.1", + "@commitlint/resolve-extends": "^19.8.1", + "@commitlint/types": "^19.8.1", "chalk": "^5.3.0", "cosmiconfig": "^9.0.0", "cosmiconfig-typescript-loader": "^6.1.0", @@ -1025,21 +993,21 @@ } }, "node_modules/@commitlint/message": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.8.0.tgz", - "integrity": "sha512-qs/5Vi9bYjf+ZV40bvdCyBn5DvbuelhR6qewLE8Bh476F7KnNyLfdM/ETJ4cp96WgeeHo6tesA2TMXS0sh5X4A==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.8.1.tgz", + "integrity": "sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==", "dev": true, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/parse": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.8.0.tgz", - "integrity": "sha512-YNIKAc4EXvNeAvyeEnzgvm1VyAe0/b3Wax7pjJSwXuhqIQ1/t2hD3OYRXb6D5/GffIvaX82RbjD+nWtMZCLL7Q==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.8.1.tgz", + "integrity": "sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==", "dev": true, "dependencies": { - "@commitlint/types": "^19.8.0", + "@commitlint/types": "^19.8.1", "conventional-changelog-angular": "^7.0.0", "conventional-commits-parser": "^5.0.0" }, @@ -1048,14 +1016,14 @@ } }, "node_modules/@commitlint/prompt": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/prompt/-/prompt-19.8.0.tgz", - "integrity": "sha512-WO6L4D2uK4kqoRBsK7TFdawfYP7Eu1tFut/LmCKKvc4fi9mpT+RHEQtvIVTENMYKU1O8CA3mz9jKD863KyzVfg==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/prompt/-/prompt-19.8.1.tgz", + "integrity": "sha512-IH3zJBJ2GSffgAJtW5EklK72skEAa3PZsbWQ5+Ybumd9QjKMnI9vagz5lprGRImdysaFREsMCOVpmcWjxpxPxg==", "dev": true, "dependencies": { - "@commitlint/ensure": "^19.8.0", - "@commitlint/load": "^19.8.0", - "@commitlint/types": "^19.8.0", + "@commitlint/ensure": "^19.8.1", + "@commitlint/load": "^19.8.1", + "@commitlint/types": "^19.8.1", "chalk": "^5.3.0", "inquirer": "^9.2.15" }, @@ -1064,29 +1032,29 @@ } }, "node_modules/@commitlint/read": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.8.0.tgz", - "integrity": "sha512-6ywxOGYajcxK1y1MfzrOnwsXO6nnErna88gRWEl3qqOOP8MDu/DTeRkGLXBFIZuRZ7mm5yyxU5BmeUvMpNte5w==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.8.1.tgz", + "integrity": "sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==", "dev": true, "dependencies": { - "@commitlint/top-level": "^19.8.0", - "@commitlint/types": "^19.8.0", + "@commitlint/top-level": "^19.8.1", + "@commitlint/types": "^19.8.1", "git-raw-commits": "^4.0.0", "minimist": "^1.2.8", - "tinyexec": "^0.3.0" + "tinyexec": "^1.0.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/resolve-extends": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.8.0.tgz", - "integrity": "sha512-CLanRQwuG2LPfFVvrkTrBR/L/DMy3+ETsgBqW1OvRxmzp/bbVJW0Xw23LnnExgYcsaFtos967lul1CsbsnJlzQ==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz", + "integrity": "sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^19.8.0", - "@commitlint/types": "^19.8.0", + "@commitlint/config-validator": "^19.8.1", + "@commitlint/types": "^19.8.1", "global-directory": "^4.0.1", "import-meta-resolve": "^4.0.0", "lodash.mergewith": "^4.6.2", @@ -1097,33 +1065,33 @@ } }, "node_modules/@commitlint/rules": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.8.0.tgz", - "integrity": "sha512-IZ5IE90h6DSWNuNK/cwjABLAKdy8tP8OgGVGbXe1noBEX5hSsu00uRlLu6JuruiXjWJz2dZc+YSw3H0UZyl/mA==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.8.1.tgz", + "integrity": "sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==", "dev": true, "dependencies": { - "@commitlint/ensure": "^19.8.0", - "@commitlint/message": "^19.8.0", - "@commitlint/to-lines": "^19.8.0", - "@commitlint/types": "^19.8.0" + "@commitlint/ensure": "^19.8.1", + "@commitlint/message": "^19.8.1", + "@commitlint/to-lines": "^19.8.1", + "@commitlint/types": "^19.8.1" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/to-lines": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.8.0.tgz", - "integrity": "sha512-3CKLUw41Cur8VMjh16y8LcsOaKbmQjAKCWlXx6B0vOUREplp6em9uIVhI8Cv934qiwkbi2+uv+mVZPnXJi1o9A==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.8.1.tgz", + "integrity": "sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==", "dev": true, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/top-level": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.8.0.tgz", - "integrity": "sha512-Rphgoc/omYZisoNkcfaBRPQr4myZEHhLPx2/vTXNLjiCw4RgfPR1wEgUpJ9OOmDCiv5ZyIExhprNLhteqH4FuQ==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.8.1.tgz", + "integrity": "sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==", "dev": true, "dependencies": { "find-up": "^7.0.0" @@ -1133,9 +1101,9 @@ } }, "node_modules/@commitlint/types": { - "version": "19.8.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.8.0.tgz", - "integrity": "sha512-LRjP623jPyf3Poyfb0ohMj8I3ORyBDOwXAgxxVPbSD0unJuW2mJWeiRfaQinjtccMqC5Wy1HOMfa4btKjbNxbg==", + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.8.1.tgz", + "integrity": "sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==", "dev": true, "dependencies": { "@types/conventional-commits-parser": "^5.0.0", @@ -1181,23 +1149,25 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz", - "integrity": "sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==", + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", "dev": true, "dependencies": { + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", "cpu": [ "ppc64" ], @@ -1211,9 +1181,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", "cpu": [ "arm" ], @@ -1227,9 +1197,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", "cpu": [ "arm64" ], @@ -1243,9 +1213,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", "cpu": [ "x64" ], @@ -1259,9 +1229,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", "cpu": [ "arm64" ], @@ -1275,9 +1245,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", "cpu": [ "x64" ], @@ -1291,9 +1261,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", "cpu": [ "arm64" ], @@ -1307,9 +1277,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", "cpu": [ "x64" ], @@ -1323,9 +1293,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", "cpu": [ "arm" ], @@ -1339,9 +1309,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", "cpu": [ "arm64" ], @@ -1355,9 +1325,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", "cpu": [ "ia32" ], @@ -1371,9 +1341,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", "cpu": [ "loong64" ], @@ -1387,9 +1357,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", "cpu": [ "mips64el" ], @@ -1403,9 +1373,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", "cpu": [ "ppc64" ], @@ -1419,9 +1389,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", "cpu": [ "riscv64" ], @@ -1435,9 +1405,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", "cpu": [ "s390x" ], @@ -1451,9 +1421,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", "cpu": [ "x64" ], @@ -1467,9 +1437,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", "cpu": [ "arm64" ], @@ -1483,9 +1453,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", "cpu": [ "x64" ], @@ -1499,9 +1469,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", "cpu": [ "arm64" ], @@ -1515,9 +1485,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", "cpu": [ "x64" ], @@ -1530,10 +1500,26 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", "cpu": [ "x64" ], @@ -1547,9 +1533,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", "cpu": [ "arm64" ], @@ -1563,9 +1549,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", "cpu": [ "ia32" ], @@ -1579,9 +1565,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", "cpu": [ "x64" ], @@ -1595,9 +1581,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -1634,9 +1620,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, "dependencies": { "@eslint/object-schema": "^2.1.6", @@ -1648,18 +1634,18 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.15" @@ -1714,12 +1700,15 @@ "dev": true }, "node_modules/@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -1732,12 +1721,12 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, "dependencies": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { @@ -2611,9 +2600,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "engines": { "node": ">=18.18" @@ -2624,9 +2613,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.10.tgz", - "integrity": "sha512-Ey6176gZmeqZuY/W/nZiUyvmb1/qInjcpiZjXWi6nON+nxJpD1bxtSoBxNliGISae32n6OwbY+TSXPZ1CfS4bw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", "dev": true, "engines": { "node": ">=18" @@ -2738,17 +2727,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -2760,25 +2745,16 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2927,6 +2903,55 @@ "yarn": "1.x" } }, + "node_modules/@mattrglobal/jsonld-signatures-bbs/node_modules/jsonld": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-4.0.1.tgz", + "integrity": "sha512-ltEqMQB37ZxZnsgmI+9rqHYkz1M6PqUykuS1t2aQNuH1oiLrUDYz5nyVkHQDgjFd7CFKTIWeLiNhwdwFrH5o5A==", + "dependencies": { + "canonicalize": "^1.0.1", + "lru-cache": "^5.1.1", + "object.fromentries": "^2.0.2", + "rdf-canonize": "^2.0.1", + "request": "^2.88.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mattrglobal/jsonld-signatures-bbs/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@mattrglobal/jsonld-signatures-bbs/node_modules/rdf-canonize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-2.0.1.tgz", + "integrity": "sha512-/GVELjrfW8G/wS4QfDZ5Kq68cS1belVNJqZlcwiErerexeBUsgOINCROnP7UumWIBNdeCwTVLE9NVXMnRYK0lA==", + "dependencies": { + "semver": "^6.3.0", + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mattrglobal/jsonld-signatures-bbs/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mattrglobal/jsonld-signatures-bbs/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/@mattrglobal/node-bbs-signatures": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/@mattrglobal/node-bbs-signatures/-/node-bbs-signatures-0.18.1.tgz", @@ -3093,9 +3118,9 @@ } }, "node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "engines": { "node": "^14.21.3 || >=16" }, @@ -3520,15 +3545,15 @@ } }, "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://opencollective.com/pkgr" } }, "node_modules/@pnpm/config.env-replace": { @@ -3573,9 +3598,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -3595,9 +3620,9 @@ } }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "engines": { "node": ">=12" @@ -3607,9 +3632,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", - "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", + "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", "cpu": [ "arm" ], @@ -3620,9 +3645,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", - "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", + "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", "cpu": [ "arm64" ], @@ -3633,9 +3658,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", - "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", "cpu": [ "arm64" ], @@ -3646,9 +3671,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", - "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", + "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", "cpu": [ "x64" ], @@ -3659,9 +3684,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", - "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", + "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", "cpu": [ "arm64" ], @@ -3672,9 +3697,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", - "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", + "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", "cpu": [ "x64" ], @@ -3685,9 +3710,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", - "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", + "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", "cpu": [ "arm" ], @@ -3698,9 +3723,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", - "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", + "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", "cpu": [ "arm" ], @@ -3711,9 +3736,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", - "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", + "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", "cpu": [ "arm64" ], @@ -3724,9 +3749,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", - "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", + "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", "cpu": [ "arm64" ], @@ -3737,9 +3762,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", - "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", + "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", "cpu": [ "loong64" ], @@ -3750,9 +3775,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", - "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", + "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", "cpu": [ "ppc64" ], @@ -3763,9 +3788,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", - "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", + "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", "cpu": [ "riscv64" ], @@ -3776,9 +3801,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", - "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", + "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", "cpu": [ "riscv64" ], @@ -3789,9 +3814,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", - "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", + "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", "cpu": [ "s390x" ], @@ -3802,9 +3827,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz", + "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==", "cpu": [ "x64" ], @@ -3814,9 +3839,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", - "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", + "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", "cpu": [ "x64" ], @@ -3827,9 +3852,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", - "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", + "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", "cpu": [ "arm64" ], @@ -3840,9 +3865,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", - "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", + "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", "cpu": [ "ia32" ], @@ -3853,9 +3878,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", - "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", + "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", "cpu": [ "x64" ], @@ -4436,9 +4461,9 @@ } }, "node_modules/@semantic-release/github/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "engines": { "node": ">= 14" @@ -5072,7 +5097,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5085,7 +5109,6 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.4.tgz", "integrity": "sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==", - "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.1.3", "@smithy/types": "^4.3.1", @@ -5098,10 +5121,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.5.3.tgz", - "integrity": "sha512-xa5byV9fEguZNofCclv6v9ra0FYh5FATQW/da7FQUVTic94DfrN/NvmKZjrMyzbpqfot9ZjBaO8U1UeTbmSLuA==", - "license": "Apache-2.0", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.7.2.tgz", + "integrity": "sha512-JoLw59sT5Bm8SAjFCYZyuCGxK8y3vovmoVbZWLDPTH5XpPEIwpFd9m90jjVMwoypDuB/SdVgje5Y4T7w50lJaw==", "dependencies": { "@smithy/middleware-serde": "^4.0.8", "@smithy/protocol-http": "^5.1.2", @@ -5109,7 +5131,7 @@ "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.4", - "@smithy/util-stream": "^4.2.2", + "@smithy/util-stream": "^4.2.3", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -5121,7 +5143,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.6.tgz", "integrity": "sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==", - "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.1.3", "@smithy/property-provider": "^4.0.4", @@ -5134,10 +5155,9 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz", - "integrity": "sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==", - "license": "Apache-2.0", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.1.0.tgz", + "integrity": "sha512-mADw7MS0bYe2OGKkHYMaqarOXuDwRbO6ArD91XhHcl2ynjGCFF+hvqf0LyQcYxkA1zaWjefSkU7Ne9mqgApSgQ==", "dependencies": { "@smithy/protocol-http": "^5.1.2", "@smithy/querystring-builder": "^4.0.4", @@ -5153,7 +5173,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.4.tgz", "integrity": "sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "@smithy/util-buffer-from": "^4.0.0", @@ -5168,7 +5187,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.4.tgz", "integrity": "sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5181,7 +5199,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5193,7 +5210,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.4.tgz", "integrity": "sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==", - "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", @@ -5204,12 +5220,11 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.11.tgz", - "integrity": "sha512-zDogwtRLzKl58lVS8wPcARevFZNBOOqnmzWWxVe9XiaXU2CADFjvJ9XfNibgkOWs08sxLuSr81NrpY4mgp9OwQ==", - "license": "Apache-2.0", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.17.tgz", + "integrity": "sha512-S3hSGLKmHG1m35p/MObQCBCdRsrpbPU8B129BVzRqRfDvQqPMQ14iO4LyRw+7LNizYc605COYAcjqgawqi+6jA==", "dependencies": { - "@smithy/core": "^3.5.3", + "@smithy/core": "^3.7.2", "@smithy/middleware-serde": "^4.0.8", "@smithy/node-config-provider": "^4.1.3", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -5223,18 +5238,17 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.12.tgz", - "integrity": "sha512-wvIH70c4e91NtRxdaLZF+mbLZ/HcC6yg7ySKUiufL6ESp6zJUSnJucZ309AvG9nqCFHSRB5I6T3Ez1Q9wCh0Ww==", - "license": "Apache-2.0", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.18.tgz", + "integrity": "sha512-bYLZ4DkoxSsPxpdmeapvAKy7rM5+25gR7PGxq2iMiecmbrRGBHj9s75N74Ylg+aBiw9i5jIowC/cLU2NR0qH8w==", "dependencies": { "@smithy/node-config-provider": "^4.1.3", "@smithy/protocol-http": "^5.1.2", - "@smithy/service-error-classification": "^4.0.5", - "@smithy/smithy-client": "^4.4.3", + "@smithy/service-error-classification": "^4.0.6", + "@smithy/smithy-client": "^4.4.9", "@smithy/types": "^4.3.1", "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.5", + "@smithy/util-retry": "^4.0.6", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -5246,7 +5260,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz", "integrity": "sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==", - "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", @@ -5260,7 +5273,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.4.tgz", "integrity": "sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5273,7 +5285,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz", "integrity": "sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==", - "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.0.4", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -5285,10 +5296,9 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "license": "Apache-2.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.1.0.tgz", + "integrity": "sha512-vqfSiHz2v8b3TTTrdXi03vNz1KLYYS3bhHCDv36FYDqxT7jvTll1mMnCrkD+gOvgwybuunh/2VmvOMqwBegxEg==", "dependencies": { "@smithy/abort-controller": "^4.0.4", "@smithy/protocol-http": "^5.1.2", @@ -5304,7 +5314,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.4.tgz", "integrity": "sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5317,7 +5326,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.2.tgz", "integrity": "sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5330,7 +5338,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz", "integrity": "sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "@smithy/util-uri-escape": "^4.0.0", @@ -5344,7 +5351,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz", "integrity": "sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5354,10 +5360,9 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.5.tgz", - "integrity": "sha512-LvcfhrnCBvCmTee81pRlh1F39yTS/+kYleVeLCwNtkY8wtGg8V/ca9rbZZvYIl8OjlMtL6KIjaiL/lgVqHD2nA==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.6.tgz", + "integrity": "sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg==", "dependencies": { "@smithy/types": "^4.3.1" }, @@ -5369,7 +5374,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz", "integrity": "sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5382,7 +5386,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.2.tgz", "integrity": "sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==", - "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "@smithy/protocol-http": "^5.1.2", @@ -5398,17 +5401,16 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.3.tgz", - "integrity": "sha512-xxzNYgA0HD6ETCe5QJubsxP0hQH3QK3kbpJz3QrosBCuIWyEXLR/CO5hFb2OeawEKUxMNhz3a1nuJNN2np2RMA==", - "license": "Apache-2.0", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.9.tgz", + "integrity": "sha512-mbMg8mIUAWwMmb74LoYiArP04zWElPzDoA1jVOp3or0cjlDMgoS6WTC3QXK0Vxoc9I4zdrX0tq6qsOmaIoTWEQ==", "dependencies": { - "@smithy/core": "^3.5.3", - "@smithy/middleware-endpoint": "^4.1.11", + "@smithy/core": "^3.7.2", + "@smithy/middleware-endpoint": "^4.1.17", "@smithy/middleware-stack": "^4.0.4", "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@smithy/util-stream": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -5419,7 +5421,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5431,7 +5432,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.4.tgz", "integrity": "sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==", - "license": "Apache-2.0", "dependencies": { "@smithy/querystring-parser": "^4.0.4", "@smithy/types": "^4.3.1", @@ -5445,7 +5445,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", - "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", @@ -5459,7 +5458,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5471,7 +5469,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5483,7 +5480,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", - "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" @@ -5496,7 +5492,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5505,13 +5500,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.19", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.19.tgz", - "integrity": "sha512-mvLMh87xSmQrV5XqnUYEPoiFFeEGYeAKIDDKdhE2ahqitm8OHM3aSvhqL6rrK6wm1brIk90JhxDf5lf2hbrLbQ==", - "license": "Apache-2.0", + "version": "4.0.25", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.25.tgz", + "integrity": "sha512-pxEWsxIsOPLfKNXvpgFHBGFC3pKYKUFhrud1kyooO9CJai6aaKDHfT10Mi5iiipPXN/JhKAu3qX9o75+X85OdQ==", "dependencies": { "@smithy/property-provider": "^4.0.4", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.9", "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -5521,16 +5515,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.19", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.19.tgz", - "integrity": "sha512-8tYnx+LUfj6m+zkUUIrIQJxPM1xVxfRBvoGHua7R/i6qAxOMjqR6CpEpDwKoIs1o0+hOjGvkKE23CafKL0vJ9w==", - "license": "Apache-2.0", + "version": "4.0.25", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.25.tgz", + "integrity": "sha512-+w4n4hKFayeCyELZLfsSQG5mCC3TwSkmRHv4+el5CzFU8ToQpYGhpV7mrRzqlwKkntlPilT1HJy1TVeEvEjWOQ==", "dependencies": { "@smithy/config-resolver": "^4.1.4", "@smithy/credential-provider-imds": "^4.0.6", "@smithy/node-config-provider": "^4.1.3", "@smithy/property-provider": "^4.0.4", - "@smithy/smithy-client": "^4.4.3", + "@smithy/smithy-client": "^4.4.9", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, @@ -5542,7 +5535,6 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.6.tgz", "integrity": "sha512-YARl3tFL3WgPuLzljRUnrS2ngLiUtkwhQtj8PAL13XZSyUiNLQxwG3fBBq3QXFqGFUXepIN73pINp3y8c2nBmA==", - "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.1.3", "@smithy/types": "^4.3.1", @@ -5556,7 +5548,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5568,7 +5559,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.4.tgz", "integrity": "sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" @@ -5578,12 +5568,11 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.5.tgz", - "integrity": "sha512-V7MSjVDTlEt/plmOFBn1762Dyu5uqMrV2Pl2X0dYk4XvWfdWJNe9Bs5Bzb56wkCuiWjSfClVMGcsuKrGj7S/yg==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.6.tgz", + "integrity": "sha512-+YekoF2CaSMv6zKrA6iI/N9yva3Gzn4L6n35Luydweu5MMPYpiGZlWqehPHDHyNbnyaYlz/WJyYAZnC+loBDZg==", "dependencies": { - "@smithy/service-error-classification": "^4.0.5", + "@smithy/service-error-classification": "^4.0.6", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, @@ -5592,13 +5581,12 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.2.tgz", - "integrity": "sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==", - "license": "Apache-2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.3.tgz", + "integrity": "sha512-cQn412DWHHFNKrQfbHY8vSFI3nTROY1aIKji9N0tpp8gUABRilr7wdf8fqBbSlXresobM+tQFNk6I+0LXK/YZg==", "dependencies": { - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", + "@smithy/fetch-http-handler": "^5.1.0", + "@smithy/node-http-handler": "^4.1.0", "@smithy/types": "^4.3.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", @@ -5614,7 +5602,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -5626,7 +5613,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", - "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" @@ -5663,9 +5649,9 @@ "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" }, "node_modules/@tradetrust-tt/dnsprove": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/dnsprove/-/dnsprove-2.17.0.tgz", - "integrity": "sha512-UvPLQMGRWt0AQjxqQScokWcOU4+q/nLoXNnqw5tPruE6mXU9Q3jw5FXKpH/03otxHN2HCpjiN1no3O6bmc1jEA==", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/dnsprove/-/dnsprove-2.18.0.tgz", + "integrity": "sha512-UgcwV17hZSSBW5oDb+DUtXle5XdBRWXURSASkr207PYjCxZOhZV88KHJi3PB45UgtUCbtvrJK7czSsgDNnpRtg==", "dependencies": { "axios": "1.7.2", "debug": "^4.3.1", @@ -5706,16 +5692,10 @@ "node": ">=18.17.0" } }, - "node_modules/@tradetrust-tt/ethers-aws-kms-signer/node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", - "license": "MIT" - }, "node_modules/@tradetrust-tt/token-registry": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.2.0.tgz", - "integrity": "sha512-VM09UNdCR5hQT/49EySG/vnSXa33kjjreU1CHc+nHdhWk8Sz47Z1ScznZbj0JYKeIKakWTjh8usnQbPTPjnGEw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.5.0.tgz", + "integrity": "sha512-oiNI3L/zPxXPHaMltSPxZFaXH/Ej9MMy5eaiKXLOSiCxYwcqd7qe/NfFlvO1sR3OLASEnRNZxnWLl9yPY5+wnw==", "dependencies": { "ethers": "^6.13.4" } @@ -5734,20 +5714,21 @@ }, "node_modules/@tradetrust-tt/token-registry-v5": { "name": "@tradetrust-tt/token-registry", - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.3.0.tgz", - "integrity": "sha512-fh+t/PQQjIzFGj8HqkowBATAY4WW/vS0hkTBjzQZQkOXNcRj7O38QVcjJ8EVmEc/rnIPSzS8MhTjikJU9DqswQ==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.5.0.tgz", + "integrity": "sha512-oiNI3L/zPxXPHaMltSPxZFaXH/Ej9MMy5eaiKXLOSiCxYwcqd7qe/NfFlvO1sR3OLASEnRNZxnWLl9yPY5+wnw==", "dependencies": { "ethers": "^6.13.4" } }, "node_modules/@tradetrust-tt/tradetrust": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust/-/tradetrust-6.10.1.tgz", - "integrity": "sha512-Vk5TOlRKFbZ0qMitcYDcUGU5Nu5E5POHNlBnv61lrPoMq0gseIBaprgF/gIRC0Q4LVQLjCPOi1ufW11bDSpILQ==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust/-/tradetrust-6.10.2.tgz", + "integrity": "sha512-4zj4zlsrrQiUJQxvl4N8Pa4cLHtFtFIs0lMg6daP/gRJXIn1QWD0Kl4mQ5FsjuopeM7JOBX/xok22SmElEtT5w==", "hasInstallScript": true, "dependencies": { "@govtechsg/jsonld": "^0.1.1", + "@trustvc/w3c-vc": "^1.2.17", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "cross-fetch": "^4.0.0", @@ -5766,11 +5747,12 @@ } }, "node_modules/@tradetrust-tt/tradetrust-utils": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.3.2.tgz", - "integrity": "sha512-T3rikZ3v0qqB3xzmq+KM30OEziyesHgN0CRQrhEvLlQw5IULtmcuwLZGHLE8KyaI8Zd7mqbuubJlfyEMNXJZuA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.4.2.tgz", + "integrity": "sha512-RFCgCMQTadLhSF94syRKCxfHyn678RrUw4wkChL1tdZkcq/LM4dAnZuJOELUhsDlstoM6cVxiisEDGBSM3mB4g==", + "license": "Apache-2.0", "dependencies": { - "@tradetrust-tt/tt-verify": "^9.4.0", + "@tradetrust-tt/tt-verify": "^9.5.1", "dotenv": "^16.4.5", "ethers": "^5.8.0", "node-fetch": "^2.7.0" @@ -5780,13 +5762,13 @@ } }, "node_modules/@tradetrust-tt/tt-verify": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tt-verify/-/tt-verify-9.4.0.tgz", - "integrity": "sha512-ZcMlpBvGf4vr9iJRHtZY+xwo9/aHdvn77s6jXs2hisv0s+2E6MU5C1h9mDf3sUanSAP4PAnSmcthg63AjW/MXA==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tt-verify/-/tt-verify-9.5.1.tgz", + "integrity": "sha512-aPJ1yzGJlpa92iS6qkbS6/+Gfje006uVchgpXkr8249/diHRf/L/Qm19W92kHz7ZiloSJG8QKKU6i/bE4pQzGg==", "dependencies": { - "@tradetrust-tt/dnsprove": "^2.17.0", + "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/document-store": "^4.1.1", - "@tradetrust-tt/token-registry": "^5.2.0", + "@tradetrust-tt/token-registry": "^5.5.0", "@tradetrust-tt/tradetrust": "^6.10.1", "axios": "^1.7.2", "debug": "^4.3.1", @@ -5804,11 +5786,6 @@ "ethers": "^5.7.2" } }, - "node_modules/@tradetrust-tt/tt-verify/node_modules/did-resolver": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-3.2.2.tgz", - "integrity": "sha512-Eeo2F524VM5N3W4GwglZrnul2y6TLTwMQP3In62JdG34NZoqihYyOZLk+5wUW8sSgvIYIcJM8Dlt3xsdKZZ3tg==" - }, "node_modules/@trustvc/w3c-context": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/@trustvc/w3c-context/-/w3c-context-1.2.13.tgz", @@ -5821,6 +5798,11 @@ "node": ">=18.x" } }, + "node_modules/@trustvc/w3c-context/node_modules/did-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-4.1.0.tgz", + "integrity": "sha512-S6fWHvCXkZg2IhS4RcVHxwuyVejPR7c+a4Go0xbQ9ps5kILa8viiYQgrM4gfTyeTjJ0ekgJH9gk/BawTpmkbZA==" + }, "node_modules/@trustvc/w3c-credential-status": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/@trustvc/w3c-credential-status/-/w3c-credential-status-1.2.13.tgz", @@ -5850,6 +5832,11 @@ "node": ">=18.x" } }, + "node_modules/@trustvc/w3c-issuer/node_modules/did-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-4.1.0.tgz", + "integrity": "sha512-S6fWHvCXkZg2IhS4RcVHxwuyVejPR7c+a4Go0xbQ9ps5kILa8viiYQgrM4gfTyeTjJ0ekgJH9gk/BawTpmkbZA==" + }, "node_modules/@trustvc/w3c-vc": { "version": "1.2.17", "resolved": "https://registry.npmjs.org/@trustvc/w3c-vc/-/w3c-vc-1.2.17.tgz", @@ -5870,19 +5857,10 @@ "jsonld": "^6.0.0" } }, - "node_modules/@trustvc/w3c-vc/node_modules/jsonld": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-6.0.0.tgz", - "integrity": "sha512-1SkN2RXhMCTCSkX+bzHvr9ycM2HTmjWyV41hn2xG7k6BqlCgRjw0zHmuqfphjBRPqi1gKMIqgBCe/0RZMcWrAA==", - "dependencies": { - "@digitalbazaar/http-client": "^3.2.0", - "canonicalize": "^1.0.1", - "lru-cache": "^6.0.0", - "rdf-canonize": "^3.0.0" - }, - "engines": { - "node": ">=14" - } + "node_modules/@trustvc/w3c-vc/node_modules/did-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-4.1.0.tgz", + "integrity": "sha512-S6fWHvCXkZg2IhS4RcVHxwuyVejPR7c+a4Go0xbQ9ps5kILa8viiYQgrM4gfTyeTjJ0ekgJH9gk/BawTpmkbZA==" }, "node_modules/@trustvc/w3c-vc/node_modules/uuid": { "version": "10.0.0", @@ -5976,9 +5954,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true }, "node_modules/@types/json-schema": { @@ -5988,9 +5966,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.17.16", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", - "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", "dev": true }, "node_modules/@types/lru-cache": { @@ -6012,10 +5990,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.112", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.112.tgz", - "integrity": "sha512-i+Vukt9POdS/MBI7YrrkkI5fMfwFtOjphSmt4WXYLfwqsfr6z/HdCx7LqT9M7JktGob8WNgj8nFB4TbGNE4Cog==", - "license": "MIT", + "version": "18.19.120", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.120.tgz", + "integrity": "sha512-WtCGHFXnVI8WHLxDAt5TbnCM4eSE+nI0QN2NJtwzcgMhht2eNz6V9evJrk+lwC8bCY8OWV5Ym8Jz7ZEyGnKnMA==", "dependencies": { "undici-types": "~5.26.4" } @@ -6033,20 +6010,20 @@ "peer": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz", - "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/type-utils": "8.31.0", - "@typescript-eslint/utils": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6056,21 +6033,30 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz", - "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "engines": { @@ -6085,14 +6071,35 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", + "dev": true, + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz", - "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0" + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6102,16 +6109,33 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz", - "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/utils": "8.31.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6126,9 +6150,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz", - "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6139,19 +6163,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz", - "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6165,9 +6191,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "dependencies": { "balanced-match": "^1.0.0" @@ -6189,15 +6215,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz", - "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6212,13 +6238,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz", - "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.31.0", - "eslint-visitor-keys": "^4.2.0" + "@typescript-eslint/types": "8.38.0", + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6298,6 +6324,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@vitest/runner/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, "node_modules/@vitest/snapshot": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", @@ -6312,6 +6344,12 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/snapshot/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, "node_modules/@vitest/spy": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", @@ -6377,26 +6415,26 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.18.tgz", + "integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==", "dev": true, "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.13", + "@babel/parser": "^7.28.0", + "@vue/shared": "3.5.18", "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" + "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz", + "integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==", "dev": true, "dependencies": { - "@vue/compiler-core": "3.5.13", - "@vue/shared": "3.5.13" + "@vue/compiler-core": "3.5.18", + "@vue/shared": "3.5.18" } }, "node_modules/@vue/language-core": { @@ -6425,9 +6463,9 @@ } }, "node_modules/@vue/language-core/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "dependencies": { "balanced-match": "^1.0.0" @@ -6449,9 +6487,9 @@ } }, "node_modules/@vue/shared": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==", "dev": true }, "node_modules/abbrev": { @@ -6471,7 +6509,6 @@ "url": "https://github.com/sponsors/wagmi-dev" } ], - "license": "WAGMIT", "engines": { "pnpm": ">=7" }, @@ -6491,9 +6528,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -6673,9 +6710,9 @@ } }, "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", "optional": true }, "node_modules/are-docs-informative": { @@ -6798,7 +6835,6 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -6809,8 +6845,7 @@ "node_modules/asn1.js/node_modules/bn.js": { "version": "4.12.2", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==" }, "node_modules/assert-plus": { "version": "1.0.0", @@ -6894,9 +6929,9 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base-x": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", - "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", "dependencies": { "safe-buffer": "^5.0.1" } @@ -6991,9 +7026,9 @@ } }, "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==" }, "node_modules/bottleneck": { "version": "2.19.5", @@ -7004,8 +7039,7 @@ "node_modules/bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "license": "MIT" + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "node_modules/boxen": { "version": "5.1.2", @@ -7102,9 +7136,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7916,9 +7950,9 @@ "dev": true }, "node_modules/consola": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", - "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "dev": true, "engines": { "node": "^14.18.0 || >=16.10.0" @@ -8055,9 +8089,9 @@ } }, "node_modules/conventional-changelog-writer/node_modules/normalize-package-data/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -8453,7 +8487,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -8712,18 +8745,18 @@ "dev": true }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "optional": true, "engines": { "node": ">=8" } }, "node_modules/did-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-4.1.0.tgz", - "integrity": "sha512-S6fWHvCXkZg2IhS4RcVHxwuyVejPR7c+a4Go0xbQ9ps5kILa8viiYQgrM4gfTyeTjJ0ekgJH9gk/BawTpmkbZA==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-3.2.2.tgz", + "integrity": "sha512-Eeo2F524VM5N3W4GwglZrnul2y6TLTwMQP3In62JdG34NZoqihYyOZLk+5wUW8sSgvIYIcJM8Dlt3xsdKZZ3tg==" }, "node_modules/diff": { "version": "4.0.2", @@ -8768,9 +8801,9 @@ } }, "node_modules/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "engines": { "node": ">=12" }, @@ -8866,9 +8899,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -9155,12 +9188,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "dev": true - }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -9203,9 +9230,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", "dev": true, "hasInstallScript": true, "bin": { @@ -9215,31 +9242,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" } }, "node_modules/escalade": { @@ -9264,19 +9292,19 @@ } }, "node_modules/eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", + "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", + "@eslint/js": "9.31.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -9287,9 +9315,9 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -9324,9 +9352,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -9399,22 +9427,21 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "50.6.9", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.6.9.tgz", - "integrity": "sha512-7/nHu3FWD4QRG8tCVqcv+BfFtctUtEDWc29oeDXB4bwmDM2/r1ndl14AG/2DUntdqH7qmpvdemJKwb3R97/QEw==", + "version": "50.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", + "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.49.0", + "@es-joy/jsdoccomment": "~0.50.2", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.6", + "debug": "^4.4.1", "escape-string-regexp": "^4.0.0", - "espree": "^10.1.0", + "espree": "^10.3.0", "esquery": "^1.6.0", - "parse-imports": "^2.1.1", - "semver": "^7.6.3", - "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.1" + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" }, "engines": { "node": ">=18" @@ -9423,16 +9450,6 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -9463,13 +9480,13 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.6.tgz", - "integrity": "sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz", + "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.0" + "synckit": "^0.11.7" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -9492,34 +9509,6 @@ } } }, - "node_modules/eslint-plugin-prettier/node_modules/@pkgr/core": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz", - "integrity": "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/eslint-plugin-prettier/node_modules/synckit": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz", - "integrity": "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.2.3", - "tslib": "^2.8.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, "node_modules/eslint-plugin-promise": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", @@ -9539,9 +9528,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -9579,9 +9568,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9726,14 +9715,14 @@ } }, "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9808,7 +9797,6 @@ "resolved": "https://registry.npmjs.org/eth-testing/-/eth-testing-1.14.0.tgz", "integrity": "sha512-KRVSXHogM4byUUqoGlUK0ce3U4GsZcf/BAbY/L1LzMPPVntWfm12XQP3pxy0OPTSgvvP7sDGz41qifAZeVRUeQ==", "dev": true, - "license": "MIT", "dependencies": { "abitype": "^0.1.6", "ethers": "^5.5.4" @@ -9867,9 +9855,9 @@ }, "node_modules/ethersV6": { "name": "ethers", - "version": "6.14.4", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.14.4.tgz", - "integrity": "sha512-Jm/dzRs2Z9iBrT6e9TvGxyb5YVKAPLlpna7hjxH7KH/++DSh2T/JVmQUv7iHI5E55hDbp/gEVvstWYXVxXFzsA==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", + "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", "funding": [ { "type": "individual", @@ -9880,7 +9868,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", @@ -9971,11 +9958,6 @@ "querystring": "^0.2.1" } }, - "node_modules/ethr-did-resolver/node_modules/did-resolver": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-3.2.2.tgz", - "integrity": "sha512-Eeo2F524VM5N3W4GwglZrnul2y6TLTwMQP3In62JdG34NZoqihYyOZLk+5wUW8sSgvIYIcJM8Dlt3xsdKZZ3tg==" - }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -9991,23 +9973,23 @@ "dev": true }, "node_modules/execa": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", - "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", + "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", "dev": true, "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.3", + "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", - "human-signals": "^8.0.0", + "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", - "pretty-ms": "^9.0.0", + "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.0.0" + "yoctocolors": "^2.1.1" }, "engines": { "node": "^18.19.0 || >=20.5.0" @@ -10109,31 +10091,26 @@ ] }, "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" } ], - "license": "MIT", "dependencies": { - "strnum": "^1.0.5" + "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -10243,6 +10220,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -10274,9 +10262,9 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true }, "node_modules/follow-redirects": { @@ -10313,12 +10301,12 @@ } }, "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -10337,12 +10325,14 @@ } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -10764,9 +10754,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "dependencies": { "balanced-match": "^1.0.0" @@ -10830,17 +10820,17 @@ } }, "node_modules/globby": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", - "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", "dev": true, "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.2", - "ignore": "^5.2.4", - "path-type": "^5.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", "slash": "^5.1.0", - "unicorn-magic": "^0.1.0" + "unicorn-magic": "^0.3.0" }, "engines": { "node": ">=18" @@ -10861,13 +10851,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/globby/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", "dev": true, "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11444,9 +11455,9 @@ } }, "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "engines": { "node": ">= 14" @@ -11480,9 +11491,9 @@ } }, "node_modules/human-signals": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", - "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", "dev": true, "engines": { "node": ">=18.18.0" @@ -12318,9 +12329,9 @@ } }, "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "dev": true, "bin": { "jiti": "lib/jiti-cli.mjs" @@ -12469,19 +12480,17 @@ } }, "node_modules/jsonld": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-4.0.1.tgz", - "integrity": "sha512-ltEqMQB37ZxZnsgmI+9rqHYkz1M6PqUykuS1t2aQNuH1oiLrUDYz5nyVkHQDgjFd7CFKTIWeLiNhwdwFrH5o5A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-6.0.0.tgz", + "integrity": "sha512-1SkN2RXhMCTCSkX+bzHvr9ycM2HTmjWyV41hn2xG7k6BqlCgRjw0zHmuqfphjBRPqi1gKMIqgBCe/0RZMcWrAA==", "dependencies": { + "@digitalbazaar/http-client": "^3.2.0", "canonicalize": "^1.0.1", - "lru-cache": "^5.1.1", - "object.fromentries": "^2.0.2", - "rdf-canonize": "^2.0.1", - "request": "^2.88.0", - "semver": "^6.3.0" + "lru-cache": "^6.0.0", + "rdf-canonize": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">=14" } }, "node_modules/jsonld-signatures": { @@ -12500,7 +12509,23 @@ "node": ">=10" } }, - "node_modules/jsonld/node_modules/lru-cache": { + "node_modules/jsonld-signatures/node_modules/jsonld": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-4.0.1.tgz", + "integrity": "sha512-ltEqMQB37ZxZnsgmI+9rqHYkz1M6PqUykuS1t2aQNuH1oiLrUDYz5nyVkHQDgjFd7CFKTIWeLiNhwdwFrH5o5A==", + "dependencies": { + "canonicalize": "^1.0.1", + "lru-cache": "^5.1.1", + "object.fromentries": "^2.0.2", + "rdf-canonize": "^2.0.1", + "request": "^2.88.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonld-signatures/node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", @@ -12508,7 +12533,7 @@ "yallist": "^3.0.2" } }, - "node_modules/jsonld/node_modules/rdf-canonize": { + "node_modules/jsonld-signatures/node_modules/rdf-canonize": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-2.0.1.tgz", "integrity": "sha512-/GVELjrfW8G/wS4QfDZ5Kq68cS1belVNJqZlcwiErerexeBUsgOINCROnP7UumWIBNdeCwTVLE9NVXMnRYK0lA==", @@ -12520,7 +12545,7 @@ "node": ">=6" } }, - "node_modules/jsonld/node_modules/semver": { + "node_modules/jsonld-signatures/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", @@ -12528,7 +12553,7 @@ "semver": "bin/semver.js" } }, - "node_modules/jsonld/node_modules/yallist": { + "node_modules/jsonld-signatures/node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" @@ -12707,9 +12732,9 @@ "dev": true }, "node_modules/lint-staged": { - "version": "15.5.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.1.tgz", - "integrity": "sha512-6m7u8mue4Xn6wK6gZvSCQwBvMBR36xfY24nF5bMTf2MHDYG6S3yhJuOgdYVw99hsjyDt2d4z168b3naI8+NWtQ==", + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", "dev": true, "dependencies": { "chalk": "^5.4.1", @@ -12856,9 +12881,9 @@ } }, "node_modules/listr2": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", - "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", @@ -14095,9 +14120,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -17533,17 +17558,13 @@ "node": ">=6" } }, - "node_modules/parse-imports": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", - "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", "dev": true, "dependencies": { - "es-module-lexer": "^1.5.3", - "slashes": "^3.0.12" - }, - "engines": { - "node": ">= 18" + "parse-statements": "1.0.11" } }, "node_modules/parse-json": { @@ -17576,6 +17597,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -17646,9 +17673,9 @@ } }, "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true }, "node_modules/pathval": { @@ -17705,9 +17732,9 @@ } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, "engines": { "node": ">= 6" @@ -17804,12 +17831,6 @@ "pathe": "^2.0.1" } }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", - "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==", - "dev": true - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -17819,9 +17840,9 @@ } }, "node_modules/postcss": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", - "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -17838,7 +17859,7 @@ } ], "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -17898,9 +17919,9 @@ } }, "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -18258,9 +18279,9 @@ } }, "node_modules/readdirp": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", - "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "engines": { "node": ">= 14.18.0" @@ -18353,9 +18374,9 @@ } }, "node_modules/registry-auth-token": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.3.tgz", - "integrity": "sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", "dev": true, "dependencies": { "@pnpm/npm-conf": "^2.1.0" @@ -18480,9 +18501,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "engines": { "iojs": ">=1.0.0", @@ -18516,12 +18537,12 @@ } }, "node_modules/rollup": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", - "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", + "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", "dev": true, "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -18531,29 +18552,42 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.0", - "@rollup/rollup-android-arm64": "4.40.0", - "@rollup/rollup-darwin-arm64": "4.40.0", - "@rollup/rollup-darwin-x64": "4.40.0", - "@rollup/rollup-freebsd-arm64": "4.40.0", - "@rollup/rollup-freebsd-x64": "4.40.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", - "@rollup/rollup-linux-arm-musleabihf": "4.40.0", - "@rollup/rollup-linux-arm64-gnu": "4.40.0", - "@rollup/rollup-linux-arm64-musl": "4.40.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-musl": "4.40.0", - "@rollup/rollup-linux-s390x-gnu": "4.40.0", - "@rollup/rollup-linux-x64-gnu": "4.40.0", - "@rollup/rollup-linux-x64-musl": "4.40.0", - "@rollup/rollup-win32-arm64-msvc": "4.40.0", - "@rollup/rollup-win32-ia32-msvc": "4.40.0", - "@rollup/rollup-win32-x64-msvc": "4.40.0", + "@rollup/rollup-android-arm-eabi": "4.45.1", + "@rollup/rollup-android-arm64": "4.45.1", + "@rollup/rollup-darwin-arm64": "4.45.1", + "@rollup/rollup-darwin-x64": "4.45.1", + "@rollup/rollup-freebsd-arm64": "4.45.1", + "@rollup/rollup-freebsd-x64": "4.45.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", + "@rollup/rollup-linux-arm-musleabihf": "4.45.1", + "@rollup/rollup-linux-arm64-gnu": "4.45.1", + "@rollup/rollup-linux-arm64-musl": "4.45.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-musl": "4.45.1", + "@rollup/rollup-linux-s390x-gnu": "4.45.1", + "@rollup/rollup-linux-x64-gnu": "4.45.1", + "@rollup/rollup-linux-x64-musl": "4.45.1", + "@rollup/rollup-win32-arm64-msvc": "4.45.1", + "@rollup/rollup-win32-ia32-msvc": "4.45.1", + "@rollup/rollup-win32-x64-msvc": "4.45.1", "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", + "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/run-async": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", @@ -18996,9 +19030,9 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "devOptional": true, "bin": { "semver": "bin/semver.js" @@ -19350,12 +19384,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/slashes": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", - "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", - "dev": true - }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -19471,6 +19499,16 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -19478,10 +19516,10 @@ "devOptional": true }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "devOptional": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -19581,9 +19619,9 @@ } }, "node_modules/std-env": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", - "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true }, "node_modules/stop-iteration-iterator": { @@ -19857,16 +19895,15 @@ "dev": true }, "node_modules/strnum": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", - "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" } - ], - "license": "MIT" + ] }, "node_modules/sucrase": { "version": "3.35.0", @@ -19936,19 +19973,18 @@ } }, "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" + "@pkgr/core": "^0.2.9" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://opencollective.com/synckit" } }, "node_modules/table": { @@ -20206,15 +20242,15 @@ "dev": true }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", "dev": true }, "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "dependencies": { "fdir": "^6.4.4", @@ -20228,9 +20264,9 @@ } }, "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, "peerDependencies": { "picomatch": "^3 || ^4" @@ -20242,9 +20278,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "engines": { "node": ">=12" @@ -20358,9 +20394,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "engines": { "node": ">=18.12" @@ -20509,9 +20545,9 @@ "dev": true }, "node_modules/tsup": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.4.0.tgz", - "integrity": "sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.0.tgz", + "integrity": "sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==", "dev": true, "dependencies": { "bundle-require": "^5.1.0", @@ -20520,6 +20556,7 @@ "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.25.0", + "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", @@ -20571,6 +20608,12 @@ "node": ">= 8" } }, + "node_modules/tsup/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true + }, "node_modules/tsup/node_modules/tr46": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", @@ -20827,14 +20870,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.0.tgz", - "integrity": "sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "8.31.0", - "@typescript-eslint/parser": "8.31.0", - "@typescript-eslint/utils": "8.31.0" + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -20857,9 +20901,9 @@ } }, "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", "dev": true }, "node_modules/uglify-js": { @@ -21004,6 +21048,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/validate-npm-package-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", @@ -21014,9 +21068,9 @@ } }, "node_modules/validator": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", - "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "version": "13.15.15", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", + "integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==", "engines": { "node": ">= 0.10" } @@ -21035,9 +21089,9 @@ } }, "node_modules/vite": { - "version": "5.4.14", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", - "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, "dependencies": { "esbuild": "^0.21.3", @@ -21115,6 +21169,12 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/vite-node/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, "node_modules/vite-plugin-dts": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.9.1.tgz", @@ -21723,6 +21783,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/vitest/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, "node_modules/vitest/node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -21810,6 +21876,11 @@ "did-resolver": "^4.1.0" } }, + "node_modules/web-did-resolver/node_modules/did-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-4.1.0.tgz", + "integrity": "sha512-S6fWHvCXkZg2IhS4RcVHxwuyVejPR7c+a4Go0xbQ9ps5kILa8viiYQgrM4gfTyeTjJ0ekgJH9gk/BawTpmkbZA==" + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -22117,15 +22188,15 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "dev": true, "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "node_modules/yargs": { @@ -22213,9 +22284,9 @@ } }, "node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "dev": true, "engines": { "node": ">=12.20" diff --git a/package.json b/package.json index c2be7b6..b8accd1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/trustvc", - "version": "1.6.0-alpha.4", + "version": "1.7.4", "description": "TrustVC library", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -114,13 +114,13 @@ } }, "dependencies": { - "@tradetrust-tt/dnsprove": "^2.17.0", + "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.4", "@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0", - "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.3.0", - "@tradetrust-tt/tradetrust": "^6.10.1", - "@tradetrust-tt/tradetrust-utils": "^2.3.2", - "@tradetrust-tt/tt-verify": "^9.4.0", + "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.5.0", + "@tradetrust-tt/tradetrust": "^6.10.2", + "@tradetrust-tt/tradetrust-utils": "^2.4.2", + "@tradetrust-tt/tt-verify": "^9.5.1", "@trustvc/w3c-context": "^1.2.13", "@trustvc/w3c-credential-status": "^1.2.13", "@trustvc/w3c-issuer": "^1.2.4", diff --git a/src/core/documentBuilder.ts b/src/core/documentBuilder.ts index bfe4b87..9f7900c 100644 --- a/src/core/documentBuilder.ts +++ b/src/core/documentBuilder.ts @@ -12,7 +12,7 @@ import { constants as constantsV4 } from '@tradetrust-tt/token-registry-v4'; import { constants as constantsV5 } from '@tradetrust-tt/token-registry-v5'; import { v4Contracts } from '../token-registry-v4'; import { v5Contracts } from '../token-registry-v5'; -import { SUPPORTED_CHAINS } from '@tradetrust-tt/tradetrust-utils'; +import { SUPPORTED_CHAINS } from '../utils'; /** * Configuration for a W3C Verifiable Document using a Bitstring Status List. diff --git a/src/utils/errorMessages/index.ts b/src/utils/errorMessages/index.ts index a20d966..eb6d67e 100644 --- a/src/utils/errorMessages/index.ts +++ b/src/utils/errorMessages/index.ts @@ -1 +1,8 @@ -export { CONSTANTS as errorMessages } from '@tradetrust-tt/tradetrust-utils'; +import { CONSTANTS } from '@tradetrust-tt/tradetrust-utils'; +import { ErrorMessages } from './types'; + +// Re-export with proper typing +export const errorMessages: ErrorMessages = CONSTANTS; + +// Export types to be used by consumers +export * from './types'; diff --git a/src/utils/errorMessages/types.ts b/src/utils/errorMessages/types.ts new file mode 100644 index 0000000..c2fbbd5 --- /dev/null +++ b/src/utils/errorMessages/types.ts @@ -0,0 +1,26 @@ +/** + * Type definitions matching the structure in @tradetrust-tt/tradetrust-utils/VerificationErrorMessages.ts + */ + +// Define the structure of an error message +export interface ErrorMessage { + failureTitle: string; + failureMessage: string; + successTitle: string; // Always present in the original, even if empty string +} + +// Define the dictionary mapping error types to message objects +export interface MessagesDictionary { + [key: string]: ErrorMessage; +} + +// Define the error types object +export interface ErrorMessageTypes { + [key: string]: string; +} + +// Define the main errorMessages export structure +export interface ErrorMessages { + MESSAGES: MessagesDictionary; + TYPES: ErrorMessageTypes; +}