diff --git a/.gitignore b/.gitignore index 632f2b292..b84a92e49 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ .vscode .idea coverage +coverage-ts dist node_modules npm-debug.log diff --git a/CHANGELOG.md b/CHANGELOG.md index 6591b56de..0ef332ead 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ### Bug Fixes -- starkne types 0.7 ([#1087](https://github.com/starknet-io/starknet.js/issues/1087)) ([b038c76](https://github.com/starknet-io/starknet.js/commit/b038c76fe204746f1d1023c2ad3b46c022f6edbd)) +- starknet types 0.7 ([#1087](https://github.com/starknet-io/starknet.js/issues/1087)) ([b038c76](https://github.com/starknet-io/starknet.js/commit/b038c76fe204746f1d1023c2ad3b46c022f6edbd)) + - tslib ([#1068](https://github.com/starknet-io/starknet.js/issues/1068)) ([dd7dc10](https://github.com/starknet-io/starknet.js/commit/dd7dc10c57fc3cc35298c0d584a178666e9cfed1)) - **utils:** fix block identifier ([#1076](https://github.com/starknet-io/starknet.js/issues/1076)) ([0a3499d](https://github.com/starknet-io/starknet.js/commit/0a3499d49751061ceae1a4d6023b34f402376efc)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a0fb65c1..f312e0d2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,6 +97,7 @@ For major changes that markedly transform the existing API or significantly alte - We’re using [Prettier](https://github.com/prettier/prettier) to format code, so don’t worry much about code formatting. - Don’t commit generated files, like minified JavaScript. - Don’t change the version number or changelog. +- Use `npm run ts:coverage` to check the global type coverage rate and `npm run ts:coverage:report` to generate a complete report (summary displayed in the console, full HTML report available in the `coverage-ts` folder by launching `./coverage-ts/index.html` in your browser) and find files having low coverage. ## Need help? diff --git a/package-lock.json b/package-lock.json index 17aa7a8b3..46ee3630a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,8 +58,10 @@ "prettier-plugin-import-sort": "^0.0.7", "semantic-release": "^23.0.5", "tsup": "^8.0.2", + "type-coverage": "^2.28.1", "typedoc": "^0.25.7", - "typescript": "~5.4.0" + "typescript": "~5.4.0", + "typescript-coverage-report": "^1.0.0" } }, "../starknet-types": { @@ -3205,6 +3207,20 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@hypnosphi/create-react-context": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz", + "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==", + "dev": true, + "dependencies": { + "gud": "^1.0.0", + "warning": "^4.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": ">=0.14.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -5114,6 +5130,20 @@ "semantic-release": ">=20.1.0" } }, + "node_modules/@semantic-ui-react/event-stack": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.3.tgz", + "integrity": "sha512-FdTmJyWvJaYinHrKRsMLDrz4tTMGdFfds299Qory53hBugiDvGC0tEJf+cHsi5igDwWb/CLOgOiChInHwq8URQ==", + "dev": true, + "dependencies": { + "exenv": "^1.2.2", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -6589,6 +6619,12 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "dev": true + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -7471,6 +7507,26 @@ } } }, + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "dev": true, + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -8579,6 +8635,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==", + "dev": true + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -9215,6 +9277,12 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==", + "dev": true + }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -9788,6 +9856,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -12290,6 +12374,12 @@ "node": "*" } }, + "node_modules/keyboard-key": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", + "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==", + "dev": true + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -12799,6 +12889,18 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lossless-json": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lossless-json/-/lossless-json-4.0.1.tgz", @@ -13073,6 +13175,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", + "dev": true, + "bin": { + "ncp": "bin/ncp" + } + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -16056,6 +16167,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -16604,6 +16731,17 @@ "node": ">=8" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -16744,6 +16882,23 @@ "node": ">= 6" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -16828,6 +16983,33 @@ "node": ">=0.10.0" } }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -17286,6 +17468,16 @@ "node": ">=v12.22.7" } }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/semantic-release": { "version": "23.0.6", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.6.tgz", @@ -17584,6 +17776,82 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/semantic-ui-react": { + "version": "0.88.2", + "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.88.2.tgz", + "integrity": "sha512-+02kN2z8PuA/cMdvDUsHhbJmBzxxgOXVHMFr9XK7zGb0wkW9A6OPQMFokWz7ozlVtKjN6r7zsb+Qvjk/qq1OWw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.1.2", + "@semantic-ui-react/event-stack": "^3.1.0", + "@stardust-ui/react-component-event-listener": "~0.38.0", + "@stardust-ui/react-component-ref": "~0.38.0", + "classnames": "^2.2.6", + "keyboard-key": "^1.0.4", + "lodash": "^4.17.15", + "prop-types": "^15.7.2", + "react-is": "^16.8.6", + "react-popper": "^1.3.4", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } + }, + "node_modules/semantic-ui-react/node_modules/@stardust-ui/react-component-event-listener": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@stardust-ui/react-component-event-listener/-/react-component-event-listener-0.38.0.tgz", + "integrity": "sha512-sIP/e0dyOrrlb8K7KWumfMxj/gAifswTBC4o68Aa+C/GA73ccRp/6W1VlHvF/dlOR4KLsA+5SKnhjH36xzPsWg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.1.2", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } + }, + "node_modules/semantic-ui-react/node_modules/@stardust-ui/react-component-ref": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@stardust-ui/react-component-ref/-/react-component-ref-0.38.0.tgz", + "integrity": "sha512-xjs6WnvJVueSIXMWw0C3oWIgAPpcD03qw43oGOjUXqFktvpNkB73JoKIhS4sCrtQxBdct75qqr4ZL6JiyPcESw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.1.2", + "prop-types": "^15.7.2", + "react-is": "^16.6.3" + }, + "peerDependencies": { + "react": "^16.8.0", + "react-dom": "^16.8.0" + } + }, + "node_modules/semantic-ui-react/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/semantic-ui-react/node_modules/react-popper": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", + "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.1.2", + "@hypnosphi/create-react-context": "^0.3.1", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + }, + "peerDependencies": { + "react": "0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -17690,6 +17958,12 @@ "node": ">= 0.4" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -18641,6 +18915,27 @@ "webidl-conversions": "^4.0.2" } }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/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/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -18653,6 +18948,35 @@ "node": ">= 0.8.0" } }, + "node_modules/type-coverage": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/type-coverage/-/type-coverage-2.28.1.tgz", + "integrity": "sha512-nFpCkjyDPA+QeA0aRp3mVJ/XccounJ0Ls5IXVlCKI3XCQPzO3QFUl5zjFnmulw8hWe+r9u9EFjDsAxp8PnLMvQ==", + "dev": true, + "dependencies": { + "minimist": "1", + "type-coverage-core": "^2.28.1" + }, + "bin": { + "type-coverage": "bin/type-coverage" + } + }, + "node_modules/type-coverage-core": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/type-coverage-core/-/type-coverage-core-2.28.1.tgz", + "integrity": "sha512-NniLJtLiDg0+dhrf/9ACGwi3OAhIfvd20f1CB0yxIUBMECwmJp7e7me3lM8djkrDBJtqSY+uXA6PRs+yv3HTnA==", + "dev": true, + "dependencies": { + "fast-glob": "3", + "minimatch": "6 || 7 || 8 || 9", + "normalize-path": "3", + "tslib": "1 || 2", + "tsutils": "3" + }, + "peerDependencies": { + "typescript": "2 || 3 || 4 || 5" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -18747,6 +19071,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==", + "dev": true + }, "node_modules/typedoc": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.12.tgz", @@ -18793,6 +19123,108 @@ "node": ">=14.17" } }, + "node_modules/typescript-coverage-report": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typescript-coverage-report/-/typescript-coverage-report-1.0.0.tgz", + "integrity": "sha512-ys/DG6eaO0XaHZIPZobJQLj9lUPSOIa1xt5Pz6tvr7QAWRt3OSCuMLiPduWtg7oTeZcOHqG90owA/zOeyZdq3g==", + "dev": true, + "dependencies": { + "chalk": "4.1.2", + "cli-table3": "^0.6.1", + "commander": "^5.0.0", + "ncp": "^2.0.0", + "rimraf": "^3.0.2", + "semantic-ui-react": "^0.88.2", + "type-coverage-core": "^2.23.0" + }, + "bin": { + "typescript-coverage-report": "dist/bin/typescript-coverage-report.js" + }, + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "typescript": "2 || 3 || 4 || 5" + } + }, + "node_modules/typescript-coverage-report/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/typescript-coverage-report/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/typescript-coverage-report/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/typescript-coverage-report/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/typescript-coverage-report/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/typescript-coverage-report/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-coverage-report/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/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", @@ -19033,6 +19465,15 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index f3f8b697e..1bc920ade 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,9 @@ "info:version": "npm pkg get version | xargs", "format": "prettier --log-level log --write \"**/*.{ts,js,md,yml,json}\"", "lint": "eslint . --cache --fix --ext .ts", - "ts:check": "tsc --noEmit --resolveJsonModule --project tsconfig.eslint.json" + "ts:check": "tsc --noEmit --resolveJsonModule --project tsconfig.eslint.json", + "ts:coverage": "type-coverage --at-least 95", + "ts:coverage:report": "typescript-coverage-report" }, "keywords": [ "starknet", @@ -86,8 +88,10 @@ "prettier-plugin-import-sort": "^0.0.7", "semantic-release": "^23.0.5", "tsup": "^8.0.2", + "type-coverage": "^2.28.1", "typedoc": "^0.25.7", - "typescript": "~5.4.0" + "typescript": "~5.4.0", + "typescript-coverage-report": "^1.0.0" }, "dependencies": { "@noble/curves": "~1.4.0", @@ -98,9 +102,9 @@ "isomorphic-fetch": "^3.0.0", "lossless-json": "^4.0.1", "pako": "^2.0.4", + "starknet-types-07": "npm:starknet-types@^0.7.2", "ts-mixer": "^6.0.3", - "url-join": "^4.0.1", - "starknet-types-07": "npm:starknet-types@^0.7.2" + "url-join": "^4.0.1" }, "lint-staged": { "*.ts": "eslint --cache --fix", diff --git a/src/provider/extensions/starknetId.ts b/src/provider/extensions/starknetId.ts index 1c9848ee5..61675adb9 100644 --- a/src/provider/extensions/starknetId.ts +++ b/src/provider/extensions/starknetId.ts @@ -1,4 +1,4 @@ -import { BigNumberish, StarkProfile } from '../../types'; +import { BigNumberish, RawArgsArray, StarkProfile } from '../../types'; import { CallData } from '../../utils/calldata'; import { getSelectorFromName } from '../../utils/hash'; import { decodeShortString, encodeShortString } from '../../utils/shortString'; @@ -67,13 +67,7 @@ export class StarknetId { const contract = StarknetIdContract ?? getStarknetIdContract(chainId); try { - const hexDomain = await provider.callContract({ - contractAddress: contract, - entrypoint: 'address_to_domain', - calldata: CallData.compile({ - address, - }), - }); + const hexDomain = await this.executeStarkName(provider, address as string, contract); const decimalDomain = hexDomain.map((element) => BigInt(element)).slice(1); const stringDomain = useDecoded(decimalDomain); @@ -91,6 +85,29 @@ export class StarknetId { } } + static async executeStarkName(provider: ProviderInterface, address: string, contract: string) { + try { + // Attempt the initial call with the hint parameter + return await provider.callContract({ + contractAddress: contract as string, + entrypoint: 'address_to_domain', + calldata: CallData.compile({ + address, + hint: [], + }), + }); + } catch (initialError) { + // If the initial call fails, try with the fallback calldata without the hint parameter + return await provider.callContract({ + contractAddress: contract as string, + entrypoint: 'address_to_domain', + calldata: CallData.compile({ + address, + }), + }); + } + } + static async getAddressFromStarkName( provider: ProviderInterface, name: string, @@ -136,101 +153,116 @@ export class StarknetId { const multicallAddress = StarknetIdMulticallContract ?? getStarknetIdMulticallContract(chainId); try { - const data = await provider.callContract({ - contractAddress: multicallAddress, - entrypoint: 'aggregate', - calldata: CallData.compile({ - calls: [ - { - execution: execution({}), - to: dynamicFelt(contract), - selector: dynamicFelt(getSelectorFromName('address_to_domain')), - calldata: [dynamicCallData(address)], - }, - { - execution: execution({}), - to: dynamicFelt(contract), - selector: dynamicFelt(getSelectorFromName('domain_to_id')), - calldata: [dynamicCallData(undefined, undefined, [0, 0])], - }, - { - execution: execution({}), - to: dynamicFelt(identityContract), - selector: dynamicFelt(getSelectorFromName('get_verifier_data')), - calldata: [ - dynamicCallData(undefined, [1, 0]), - dynamicCallData(encodeShortString('twitter')), - dynamicCallData(verifierContract), - dynamicCallData('0'), - ], - }, - { - execution: execution({}), - to: dynamicFelt(identityContract), - selector: dynamicFelt(getSelectorFromName('get_verifier_data')), - calldata: [ - dynamicCallData(undefined, [1, 0]), - dynamicCallData(encodeShortString('github')), - dynamicCallData(verifierContract), - dynamicCallData('0'), - ], - }, - { - execution: execution({}), - to: dynamicFelt(identityContract), - selector: dynamicFelt(getSelectorFromName('get_verifier_data')), - calldata: [ - dynamicCallData(undefined, [1, 0]), - dynamicCallData(encodeShortString('discord')), - dynamicCallData(verifierContract), - dynamicCallData('0'), - ], - }, - { - execution: execution({}), - to: dynamicFelt(identityContract), - selector: dynamicFelt(getSelectorFromName('get_verifier_data')), - calldata: [ - dynamicCallData(undefined, [1, 0]), - dynamicCallData(encodeShortString('proof_of_personhood')), - dynamicCallData(popContract), - dynamicCallData('0'), - ], - }, - // PFP - { - execution: execution({}), - to: dynamicFelt(identityContract), - selector: dynamicFelt(getSelectorFromName('get_verifier_data')), - calldata: [ - dynamicCallData(undefined, [1, 0]), - dynamicCallData(encodeShortString('nft_pp_contract')), - dynamicCallData(pfpContract), - dynamicCallData('0'), - ], - }, - { - execution: execution({}), - to: dynamicFelt(identityContract), - selector: dynamicFelt(getSelectorFromName('get_extended_verifier_data')), - calldata: [ - dynamicCallData(undefined, [1, 0]), - dynamicCallData(encodeShortString('nft_pp_id')), - dynamicCallData('2'), - dynamicCallData(pfpContract), - dynamicCallData('0'), - ], - }, - { - execution: execution(undefined, undefined, [6, 0, 0]), - to: dynamicFelt(undefined, [6, 0]), - selector: dynamicFelt(getSelectorFromName('tokenURI')), - calldata: [dynamicCallData(undefined, [7, 1]), dynamicCallData(undefined, [7, 2])], - }, - ], - }), + const initialCalldata: RawArgsArray = []; + const fallbackCalldata: RawArgsArray = []; + + initialCalldata.push({ + execution: execution({}), + to: dynamicCallData(contract), + selector: dynamicCallData(getSelectorFromName('address_to_domain')), + calldata: [dynamicCallData(address), dynamicCallData('0')], + }); + fallbackCalldata.push({ + execution: execution({}), + to: dynamicCallData(contract), + selector: dynamicFelt(getSelectorFromName('address_to_domain')), + calldata: [dynamicCallData(address)], }); + const calls = [ + { + execution: execution({}), + to: dynamicFelt(contract), + selector: dynamicFelt(getSelectorFromName('domain_to_id')), + calldata: [dynamicCallData(undefined, undefined, [0, 0])], + }, + { + execution: execution({}), + to: dynamicFelt(identityContract), + selector: dynamicFelt(getSelectorFromName('get_verifier_data')), + calldata: [ + dynamicCallData(undefined, [1, 0]), + dynamicCallData(encodeShortString('twitter')), + dynamicCallData(verifierContract), + dynamicCallData('0'), + ], + }, + { + execution: execution({}), + to: dynamicFelt(identityContract), + selector: dynamicFelt(getSelectorFromName('get_verifier_data')), + calldata: [ + dynamicCallData(undefined, [1, 0]), + dynamicCallData(encodeShortString('github')), + dynamicCallData(verifierContract), + dynamicCallData('0'), + ], + }, + { + execution: execution({}), + to: dynamicFelt(identityContract), + selector: dynamicFelt(getSelectorFromName('get_verifier_data')), + calldata: [ + dynamicCallData(undefined, [1, 0]), + dynamicCallData(encodeShortString('discord')), + dynamicCallData(verifierContract), + dynamicCallData('0'), + ], + }, + { + execution: execution({}), + to: dynamicFelt(identityContract), + selector: dynamicFelt(getSelectorFromName('get_verifier_data')), + calldata: [ + dynamicCallData(undefined, [1, 0]), + dynamicCallData(encodeShortString('proof_of_personhood')), + dynamicCallData(popContract), + dynamicCallData('0'), + ], + }, + // PFP + { + execution: execution({}), + to: dynamicFelt(identityContract), + selector: dynamicFelt(getSelectorFromName('get_verifier_data')), + calldata: [ + dynamicCallData(undefined, [1, 0]), + dynamicCallData(encodeShortString('nft_pp_contract')), + dynamicCallData(pfpContract), + dynamicCallData('0'), + ], + }, + { + execution: execution({}), + to: dynamicFelt(identityContract), + selector: dynamicFelt(getSelectorFromName('get_extended_verifier_data')), + calldata: [ + dynamicCallData(undefined, [1, 0]), + dynamicCallData(encodeShortString('nft_pp_id')), + dynamicCallData('2'), + dynamicCallData(pfpContract), + dynamicCallData('0'), + ], + }, + { + execution: execution(undefined, undefined, [6, 0, 0]), + to: dynamicFelt(undefined, [6, 0]), + selector: dynamicFelt(getSelectorFromName('tokenURI')), + calldata: [dynamicCallData(undefined, [7, 1]), dynamicCallData(undefined, [7, 2])], + }, + ]; + + initialCalldata.push(...calls); + fallbackCalldata.push(...calls); + + const data = await this.executeStarkProfile( + provider, + multicallAddress, + 'aggregate', + initialCalldata, + fallbackCalldata + ); + if (Array.isArray(data)) { // Format data const size = parseInt(data[0], 16); @@ -288,4 +320,32 @@ export class StarknetId { throw Error('Could not get user stark profile data from address'); } } + + static async executeStarkProfile( + provider: ProviderInterface, + contract: string, + functionName: string, + initialCalldata: RawArgsArray, + fallbackCalldata: RawArgsArray + ) { + try { + // Attempt the initial call with the hint parameter + return await provider.callContract({ + contractAddress: contract as string, + entrypoint: functionName, + calldata: CallData.compile({ + calls: initialCalldata, + }), + }); + } catch (initialError) { + // If the initial call fails, try with the fallback calldata without the hint parameter + return await provider.callContract({ + contractAddress: contract as string, + entrypoint: functionName, + calldata: CallData.compile({ + calls: fallbackCalldata, + }), + }); + } + } } diff --git a/src/types/lib/contract/abi.ts b/src/types/lib/contract/abi.ts index 6583165dd..1b23e1b47 100644 --- a/src/types/lib/contract/abi.ts +++ b/src/types/lib/contract/abi.ts @@ -1,5 +1,5 @@ /** ABI */ -export type Abi = ReadonlyArray; +export type Abi = ReadonlyArray; // Basic elements export type AbiEntry = { name: string; type: 'felt' | 'felt*' | string }; @@ -31,6 +31,13 @@ export type StructAbi = { type: 'struct'; }; +export type AbiInterfaces = { [name: string]: InterfaceAbi }; +export type InterfaceAbi = { + items: FunctionAbi[]; + name: string; + type: 'interface'; +}; + export type AbiEnums = { [name: string]: EnumAbi }; export type EnumAbi = { variants: (AbiEntry & { offset: number })[]; diff --git a/src/utils/address.ts b/src/utils/address.ts index a611d627f..fe5a012e4 100644 --- a/src/utils/address.ts +++ b/src/utils/address.ts @@ -11,6 +11,12 @@ import { assertInRange, toHex } from './num'; * Format a hex number to '0x' and 64 characters, adding leading zeros if necessary. * @param {BigNumberish} address * @returns {string} Hex string : 0x followed by 64 characters. No upper case characters in the response. + * @example + * ```typescript + * const address = "0x90591d9fa3efc87067d95a643f8455e0b8190eb8cb7bfd39e4fb7571fdf"; + * const result = addAddressPadding(address); + * // result = "0x0000090591d9fa3efc87067d95a643f8455e0b8190eb8cb7bfd39e4fb7571fdf" + * ``` */ export function addAddressPadding(address: BigNumberish): string { return addHexPrefix(removeHexPrefix(toHex(address)).padStart(64, '0')); @@ -20,6 +26,12 @@ export function addAddressPadding(address: BigNumberish): string { * Check the validity of a Starknet address, and format it as a hex number : '0x' and 64 characters, adding leading zeros if necessary. * @param {BigNumberish} address * @returns {string} Hex string : 0x followed by 64 characters. No upper case characters in the response. + * @example + * ```typescript + * const address = "0x90591d9fa3efc87067d95a643f8455e0b8190eb8cb7bfd39e4fb7571fdf"; + * const result = validateAndParseAddress(address); + * // result = "0x0000090591d9fa3efc87067d95a643f8455e0b8190eb8cb7bfd39e4fb7571fdf" + * ``` */ export function validateAndParseAddress(address: BigNumberish): string { assertInRange(address, ZERO, ADDR_BOUND - 1n, 'Starknet Address'); @@ -34,13 +46,18 @@ export function validateAndParseAddress(address: BigNumberish): string { } /** - * Computes the checksum address for the given Starknet address. - * - * From https://github.com/ethers-io/ethers.js/blob/fc1e006575d59792fa97b4efb9ea2f8cca1944cf/packages/address/src.ts/index.ts#L12 - * @param {BigNumberish} address - The address to compute the checksum for. - * - * @returns {string} The checksum address. + * Convert an address to her checksum representation which uses a specific pattern of uppercase and lowercase letters within + * a given address to reduce the risk of errors introduced from typing an address or cut and paste issues. + * @param {BigNumberish} address + * @returns {string} Hex string : 0x followed by 64 characters. Mix of uppercase and lowercase + * @example + * ```typescript + * const address = "0x90591d9fa3efc87067d95a643f8455e0b8190eb8cb7bfd39e4fb7571fdf"; + * const result = getChecksumAddress(address); + * // result = "0x0000090591D9fA3EfC87067d95a643f8455E0b8190eb8Cb7bFd39e4fb7571fDF" + * ``` */ +// from https://github.com/ethers-io/ethers.js/blob/fc1e006575d59792fa97b4efb9ea2f8cca1944cf/packages/address/src.ts/index.ts#L12 export function getChecksumAddress(address: BigNumberish): string { const chars = removeHexPrefix(validateAndParseAddress(address)).toLowerCase().split(''); const hex = removeHexPrefix(keccakBn(address)); @@ -65,6 +82,12 @@ export function getChecksumAddress(address: BigNumberish): string { * @param address string * * @returns true if the ChecksumAddress is valid + * @example + * ```typescript + * const address = "0x0000090591D9fA3EfC87067d95a643f8455E0b8190eb8Cb7bFd39e4fb7571fDF"; + * const result = validateChecksumAddress(address); + * // result = true + * ``` */ export function validateChecksumAddress(address: string): boolean { return getChecksumAddress(address) === address; diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 4d0830ebb..ef35545a3 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -4,7 +4,7 @@ * @param {string} [message] - The optional message to include in the error. * @throws {Error} Throws an error if the condition is false. */ -export default function assert(condition: any, message?: string): asserts condition { +export default function assert(condition: boolean, message?: string): asserts condition { if (!condition) { throw new Error(message || 'Assertion failure'); } diff --git a/src/utils/calldata/formatter.ts b/src/utils/calldata/formatter.ts index a0adc3a68..b49ddc0b6 100644 --- a/src/utils/calldata/formatter.ts +++ b/src/utils/calldata/formatter.ts @@ -2,7 +2,7 @@ import { isBigInt } from '../num'; import { decodeShortString } from '../shortString'; const guard = { - isBN: (data: any, type: any, key: any) => { + isBN: (data: Record, type: Record, key: string) => { if (!isBigInt(data[key])) throw new Error( `Data and formatter mismatch on ${key}:${type[key]}, expected response data ${key}:${ @@ -10,7 +10,7 @@ const guard = { } to be BN instead it is ${typeof data[key]}` ); }, - unknown: (data: any, type: any, key: any) => { + unknown: (data: Record, type: Record, key: string) => { throw new Error(`Unhandled formatter type on ${key}:${type[key]} for data ${key}:${data[key]}`); }, }; @@ -23,51 +23,58 @@ const guard = { * @param {any} [sameType] - The same type definition to be used (optional). * @returns - The formatted data. */ -export default function formatter(data: any, type: any, sameType?: any) { +export default function formatter( + data: Record, + type: Record, + sameType?: any +) { // match data element with type element - return Object.entries(data).reduce((acc, [key, value]: [any, any]) => { - const elType = sameType ?? type[key]; + return Object.entries(data).reduce( + (acc, [key, value]: [string, any]) => { + const elType = sameType ?? type[key]; - if (!(key in type) && !sameType) { - // no type definition for element return original element - acc[key] = value; - return acc; - } + if (!(key in type) && !sameType) { + // no type definition for element return original element + acc[key] = value; + return acc; + } - if (elType === 'string') { - if (Array.isArray(data[key])) { - // long string (felt*) - const arrayStr = formatter( - data[key], - data[key].map((_: any) => elType) - ); - acc[key] = Object.values(arrayStr).join(''); + if (elType === 'string') { + if (Array.isArray(data[key])) { + // long string (felt*) + const arrayStr = formatter( + data[key], + data[key].map((_: any) => elType) + ); + acc[key] = Object.values(arrayStr).join(''); + return acc; + } + guard.isBN(data, type, key); + acc[key] = decodeShortString(value); + return acc; + } + if (elType === 'number') { + guard.isBN(data, type, key); + acc[key] = Number(value); + return acc; + } + if (typeof elType === 'function') { + acc[key] = elType(value); + return acc; + } + if (Array.isArray(elType)) { + const arrayObj = formatter(data[key], elType, elType[0]); + acc[key] = Object.values(arrayObj); + return acc; + } + if (typeof elType === 'object') { + acc[key] = formatter(data[key], elType); return acc; } - guard.isBN(data, type, key); - acc[key] = decodeShortString(value); - return acc; - } - if (elType === 'number') { - guard.isBN(data, type, key); - acc[key] = Number(value); - return acc; - } - if (typeof elType === 'function') { - acc[key] = elType(value); - return acc; - } - if (Array.isArray(elType)) { - const arrayObj = formatter(data[key], elType, elType[0]); - acc[key] = Object.values(arrayObj); - return acc; - } - if (typeof elType === 'object') { - acc[key] = formatter(data[key], elType); - return acc; - } - guard.unknown(data, type, key); - return acc; - }, {} as any); + guard.unknown(data, type, key); + return acc; + }, + {} as Record + ); } diff --git a/src/utils/calldata/index.ts b/src/utils/calldata/index.ts index e9765c806..904e99506 100644 --- a/src/utils/calldata/index.ts +++ b/src/utils/calldata/index.ts @@ -271,7 +271,7 @@ export class CallData { */ public format(method: string, response: string[], format: object): Result { const parsed = this.parse(method, response); - return formatter(parsed, format); + return formatter(parsed as Record, format); } /** diff --git a/src/utils/calldata/parser/parser-2.0.0.ts b/src/utils/calldata/parser/parser-2.0.0.ts index 6c9d7b2ba..53f0893a9 100644 --- a/src/utils/calldata/parser/parser-2.0.0.ts +++ b/src/utils/calldata/parser/parser-2.0.0.ts @@ -1,4 +1,4 @@ -import { Abi, FunctionAbi } from '../../../types'; +import { Abi, FunctionAbi, EventAbi, StructAbi, InterfaceAbi } from '../../../types'; import { AbiParserInterface } from './interface'; export class AbiParser2 implements AbiParserInterface { @@ -23,8 +23,10 @@ export class AbiParser2 implements AbiParserInterface { * @returns FunctionAbi | undefined */ public getMethod(name: string): FunctionAbi | undefined { - const intf = this.abi.find((it) => it.type === 'interface'); - return intf.items.find((it: any) => it.name === name); + const intf = this.abi.find( + (it: FunctionAbi | EventAbi | StructAbi | InterfaceAbi) => it.type === 'interface' + ) as InterfaceAbi; + return intf.items.find((it: FunctionAbi) => it.name === name); } /** @@ -32,7 +34,7 @@ export class AbiParser2 implements AbiParserInterface { * @returns Abi */ public getLegacyFormat(): Abi { - return this.abi.flatMap((e) => { + return this.abi.flatMap((e: FunctionAbi | EventAbi | StructAbi | InterfaceAbi) => { if (e.type === 'interface') { return e.items; } diff --git a/src/utils/encode.ts b/src/utils/encode.ts index 705d45d12..4095e6ba6 100644 --- a/src/utils/encode.ts +++ b/src/utils/encode.ts @@ -14,6 +14,18 @@ const STRING_ZERO = '0'; * Convert array buffer to string * * *[internal usage]* + * + * @param {ArrayBuffer} array The ArrayBuffer to convert to string. + * @returns {string} The converted string. + * + * @example + * ```typescript + * const buffer = new ArrayBuffer(5); + * const view = new Uint8Array(buffer); + * [72, 101, 108, 108, 111].forEach((x, idx) => view[idx] = x); + * const result = encode.arrayBufferToString(buffer); + * // result = "Hello" + * ``` */ export function arrayBufferToString(array: ArrayBuffer): string { return new Uint8Array(array).reduce((data, byte) => data + String.fromCharCode(byte), ''); @@ -23,6 +35,16 @@ export function arrayBufferToString(array: ArrayBuffer): string { * Convert utf8-string to Uint8Array * * *[internal usage]* + * + * @param {string} str The UTF-8 string to convert. + * @returns {Uint8Array} The encoded Uint8Array. + * + * @example + * ```typescript + * const myString = 'Hi'; + * const result = encode.utf8ToArray(myString); + * // result = Uint8Array(2) [ 72, 105 ] + * ``` */ export function utf8ToArray(str: string): Uint8Array { return new TextEncoder().encode(str); @@ -39,6 +61,16 @@ export function stringToArrayBuffer(str: string): Uint8Array { /** * Convert string to array buffer (browser and node compatible) + * + * @param {string} a The Base64 encoded string to convert. + * @returns {Uint8Array} The decoded Uint8Array. + * + * @example + * ```typescript + * const base64String = 'SGVsbG8='; // 'Hello' in Base64 + * const result = encode.atobUniversal(base64String); + * // result = Uint8Array(5) [ 72, 101, 108, 108, 111 ] + * ``` */ export function atobUniversal(a: string): Uint8Array { return base64.decode(a); @@ -46,6 +78,16 @@ export function atobUniversal(a: string): Uint8Array { /** * Convert array buffer to string (browser and node compatible) + * + * @param {ArrayBuffer} b The Array buffer. + * @returns {string} The Base64 encoded string. + * + * @example + * ```typescript + * const buffer = new Uint8Array([72, 101, 108, 108, 111]); // Array with ASCII values for 'Hello' + * const result = encode.btoaUniversal(buffer); + * // result = "SGVsbG8=" + * ``` */ export function btoaUniversal(b: ArrayBuffer): string { return base64.encode(new Uint8Array(b)); @@ -53,7 +95,16 @@ export function btoaUniversal(b: ArrayBuffer): string { /** * Convert array buffer to hex-string - * @returns format: hex-string + * + * @param {Uint8Array} buffer The encoded Uint8Array. + * @returns {string} The hex-string + * + * @example + * ```typescript + * const buffer = new Uint8Array([72, 101, 108, 108, 111]); // Array with ASCII values for 'Hello' + * const result = encode.buf2hex(buffer); + * // result = "48656c6c6f" + * ``` */ export function buf2hex(buffer: Uint8Array) { return buffer.reduce((r, x) => r + x.toString(16).padStart(2, '0'), ''); @@ -62,7 +113,14 @@ export function buf2hex(buffer: Uint8Array) { /** * Remove hex prefix '0x' from hex-string * @param hex hex-string - * @returns format: base16-string + * @returns {string} The hex-string + * + * @example + * ```typescript + * const hexStringWithPrefix = '0x48656c6c6f'; + * const result = encode.removeHexPrefix(hexStringWithPrefix); + * // result: "48656c6c6f" + * ``` */ export function removeHexPrefix(hex: string): string { return hex.replace(/^0x/i, ''); @@ -71,7 +129,14 @@ export function removeHexPrefix(hex: string): string { /** * Add hex prefix '0x' to base16-string * @param hex base16-string - * @returns format: hex-string + * @returns {string} The hex-string + * + * @example + * ```typescript + * const plainHexString = '48656c6c6f'; + * const result = encode.addHexPrefix(plainHexString); + * // result: "0x48656c6c6f" + * ``` */ export function addHexPrefix(hex: string): string { return `0x${removeHexPrefix(hex)}`; @@ -81,6 +146,22 @@ export function addHexPrefix(hex: string): string { * Prepend or append to string * * *[internal usage]* + * + * Pads a string to a certain length with a specific string. + * The padding can be applied either to the left or the right of the input string. + * + * @param {string} str The string to pad. + * @param {number} length The target length for the padded string. + * @param {boolean} left Set to true to add padding to the left, false to add it to the right. + * @param {string} [padding='0'] The string to use for padding. Defaults to '0'. + * @returns {string} The padded string. + * + * @example + * ```typescript + * const myString = 'hello'; + * const result = padString(myString, 10, true); + * // result = '00000hello' + * ``` */ function padString(str: string, length: number, left: boolean, padding = STRING_ZERO): string { const diff = length - str.length; @@ -94,6 +175,21 @@ function padString(str: string, length: number, left: boolean, padding = STRING_ /** * Prepend string (default with '0') + * + * Pads a string to a certain length with a specific string. + * The padding can be applied only to the left of the input string. + * + * @param {string} str The string to pad. + * @param {number} length The target length for the padded string. + * @param {string} [padding='0'] The string to use for padding. Defaults to '0'. + * @returns {string} The padded string. + * + * @example + * ```typescript + * const myString = '1A3F'; + * const result = encode.padLeft(myString, 10); + * // result: '0000001A3F' + * ``` */ export function padLeft(str: string, length: number, padding = STRING_ZERO): string { return padString(str, length, true, padding); @@ -103,6 +199,21 @@ export function padLeft(str: string, length: number, padding = STRING_ZERO): str * Calculate byte length of string * * *[no internal usage]* + * + * Calculates the byte length of a string based on a specified byte size. + * The function rounds up the byte count to the nearest multiple of the specified byte size. + * + * @param {string} str The string whose byte length is to be calculated. + * @param {number} [byteSize='8'] The size of the byte block to round up to. Defaults to 8. + * @returns {number} The calculated byte length, rounded to the nearest multiple of byteSize. + * + * @example + * ```typescript + * const myString = 'Hello'; + * const result = encode.calcByteLength(myString, 4); + * // result = 8 (rounded up to the nearest multiple of 4) + * + * ``` */ export function calcByteLength(str: string, byteSize = 8): number { const { length } = str; @@ -114,17 +225,41 @@ export function calcByteLength(str: string, byteSize = 8): number { * Prepend '0' to string bytes * * *[no internal usage]* + * + * + * * Prepends padding to the left of a string to ensure it matches a specific byte length. + * The function uses a specified padding character and rounds up the string length to the nearest multiple of `byteSize`. + * + * @param {string} str The string to be padded. + * @param {number} [byteSize='8'] The byte block size to which the string length should be rounded up. Defaults to 8. + * @param {string} [padding='0'] The character to use for padding. Defaults to '0'. + * @returns {string} The padded string. + * + * @example + * ```typescript + * const myString = '123'; + * const result = encode.sanitizeBytes(myString); + * // result: '00000123' (padded to 8 characters) + * ``` */ export function sanitizeBytes(str: string, byteSize = 8, padding = STRING_ZERO): string { return padLeft(str, calcByteLength(str, byteSize), padding); } /** - * Prepend '0' to hex-string bytes + * Sanitizes a hex-string by removing any existing '0x' prefix, padding the string with '0' to ensure it has even length, + * and then re-adding the '0x' prefix. * * *[no internal usage]* * @param hex hex-string * @returns format: hex-string + * + * @example + * ```typescript + * const unevenHex = '0x23abc'; + * const result = encode.sanitizeHex(unevenHex); + * // result = '0x023abc' (padded to ensure even length) + * ``` */ export function sanitizeHex(hex: string): string { hex = removeHexPrefix(hex); @@ -139,6 +274,16 @@ export function sanitizeHex(hex: string): string { * String transformation util * * Pascal case to screaming snake case + * + * @param {string} text The PascalCase string to convert. + * @returns {string} The converted snake_case string in uppercase. + * + * @example + * ```typescript + * const pascalString = 'PascalCaseExample'; + * const result = encode.pascalToSnake(pascalString); + * // result: 'PASCAL_CASE_EXAMPLE' + * ``` */ export const pascalToSnake = (text: string) => /[a-z]/.test(text) diff --git a/src/utils/eth.ts b/src/utils/eth.ts index d8c2a7536..21c1f60d2 100644 --- a/src/utils/eth.ts +++ b/src/utils/eth.ts @@ -32,6 +32,6 @@ export function ethRandomPrivateKey(): string { export function validateAndParseEthAddress(address: BigNumberish): string { assertInRange(address, ZERO, 2n ** 160n - 1n, 'Ethereum Address '); const result = addHexPrefix(removeHexPrefix(toHex(address)).padStart(40, '0')); - assert(result.match(/^(0x)?[0-9a-f]{40}$/), 'Invalid Ethereum Address Format'); + assert(Boolean(result.match(/^(0x)?[0-9a-f]{40}$/)), 'Invalid Ethereum Address Format'); return result; } diff --git a/src/utils/merkle.ts b/src/utils/merkle.ts index 71c850dee..daa28ae24 100644 --- a/src/utils/merkle.ts +++ b/src/utils/merkle.ts @@ -23,6 +23,17 @@ export class MerkleTree { * Create Merkle tree * @param leaves hex-string array * @returns format: hex-string; Merkle tree root + * @example + * ```typescript + * const leaves: string[] = [ + * "0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914", + * "0x1234567890123456789012345678901234567890123456789012345678901234", + * "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef" + * ]; + * const merkleTree = new MerkleTree(); + * const root = merkleTree.build(leaves); + * // root = "0x71d6f4b2f7a5aa46daa76f2e01ab44b0e7581a82b40cb1289b89b2353fc1b9e0" + * ``` */ private build(leaves: string[]): string { if (leaves.length === 1) { @@ -44,7 +55,18 @@ export class MerkleTree { /** * Create hash from ordered a and b, Pedersen hash default + * @param a BigNumberish value to be hashed + * @param b BigNumberish value to be hashed + * @param hashMethod Function to compute hash, default is Pedersen hash * @returns format: hex-string + * @example + * ```typescript + * const hash = MerkleTree.hash( + * "0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914", + * "0x1234567890123456789012345678901234567890123456789012345678901234", + * ); + * // hash = "0x71d6f4b2f7a5aa46daa76f2e01ab44b0e7581a82b40cb1289b89b2353fc1b9e0" + * ``` */ static hash( a: BigNumberish, @@ -57,10 +79,19 @@ export class MerkleTree { /** * Return path to leaf - * @param leaf hex-string - * @param branch hex-string array - * @param hashPath hex-string array - * @returns format: hex-string array + * @param leaf hex-string representing the leaf + * @param branch hex-string array representing the branch + * @param hashPath hex-string array representing the hash path + * @returns format: hex-string array representing the path to the leaf + * @example + * ```typescript + * const merkleTree = new MerkleTree(); + * const proof = merkleTree.getProof("0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914"); + * // proof = [ + * // "0x1234567890123456789012345678901234567890123456789012345678901234", + * // "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef" + * // ] + * ``` */ public getProof(leaf: string, branch = this.leaves, hashPath: string[] = []): string[] { const index = branch.indexOf(leaf); @@ -92,6 +123,18 @@ export class MerkleTree { * @param leaf hex-string * @param path hex-string array * @param hashMethod hash method override, Pedersen default + * @returns {boolean} True if the Merkle tree path is valid, false otherwise + * @example + * ```typescript + * const root = "0x71d6f4b2f7a5aa46daa76f2e01ab44b0e7581a82b40cb1289b89b2353fc1b9e0"; + * const leaf = "0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914"; + * const path = [ + * "0x1234567890123456789012345678901234567890123456789012345678901234", + * "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef" + * ]; + * const isValid = proofMerklePath(root, leaf, path); + * // isValid = true + * ``` */ export function proofMerklePath( root: string, diff --git a/src/utils/num.ts b/src/utils/num.ts index 544cb3bab..8e3f471a0 100644 --- a/src/utils/num.ts +++ b/src/utils/num.ts @@ -10,6 +10,17 @@ export type { BigNumberish }; /** * Test if string is hex-string * @param hex hex-string + * @returns {boolean} True if the input string is a hexadecimal string, false otherwise + * @example + * ```typescript + * const hexString1 = "0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914"; + * const result1 = isHex(hexString1); + * // result1 = true + * + * const hexString2 = "2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914"; + * const result2 = isHex(hexString2); + * // result2 = false + * ``` */ export function isHex(hex: string): boolean { return /^0x[0-9a-f]*$/i.test(hex); @@ -17,6 +28,14 @@ export function isHex(hex: string): boolean { /** * Convert BigNumberish to bigint + * @param value BigNumberish value to convert to bigint + * @returns {bigint} Converted bigint value + * @example + * ```typescript + * const bigNumberishValue1: BigNumberish = 1234567890; + * const result1 = toBigInt(bigNumberishValue1); + * // result1 = 1234567890n + * ``` */ export function toBigInt(value: BigNumberish): bigint { return BigInt(value); @@ -24,6 +43,14 @@ export function toBigInt(value: BigNumberish): bigint { /** * Test if value is bigint + * @param value Value to test + * @returns {boolean} True if the value is a bigint, false otherwise + * @example + * ```typescript + * const bigIntValue1: bigint = 1234567890n; + * const result1 = isBigint(bigIntValue1); + * // result1 = true + * ``` */ export function isBigInt(value: any): value is bigint { return typeof value === 'bigint'; @@ -31,14 +58,27 @@ export function isBigInt(value: any): value is bigint { /** * Convert BigNumberish to hex-string + * @param number BigNumberish value to convert to hex-string * @returns format: hex-string + * @example + * ```typescript + * const bigNumberishValue1: BigNumberish = 1234567890; + * const result1 = toHex(bigNumberishValue1); + * // result = "0x499602d2" + * ``` */ export function toHex(number: BigNumberish): string { return addHexPrefix(toBigInt(number).toString(16)); } /** - * Alias of ToHex + * Alias of toHex + * @returns format: hex-string + * @example + * ```typescript + * const result = toHexString(123); + * // result = "0x7b" + * ``` */ export const toHexString = toHex; @@ -49,7 +89,14 @@ export const toHexString = toHex; * * A storage key is represented as up to 62 hex digits, 3 bits, and 5 leading zeroes: * `0x0 + [0-7] + 62 hex = 0x + 64 hex` + * @param number BigNumberish value to convert to storage-key-string * @returns format: storage-key-string + * @example + * ```typescript + * const bigNumberishValue1: BigNumberish = 1234567890; + * const result = toStorageKey(bigNumberishValue1); + * // result = "0x000000000000000000000000000000000000000000000000000000000499602d2" + * ``` */ export function toStorageKey(number: BigNumberish): string { const res = addHexPrefix(toBigInt(number).toString(16).padStart(64, '0')); @@ -60,23 +107,48 @@ export function toStorageKey(number: BigNumberish): string { * Convert hexadecimal string to decimal string * @param hex hex-string * @returns format: decimal string + * @example + * ```typescript + * const hexString = "0x2fd23d9182193775423497fc0c472e156c57c69e4089a1967fb288a2d84e914"; + * const result = hexToDecimalString(hexString); + * // result = "32507161997631881240494522159444018041090212371621416251492750949915267618964"; + * ``` */ export function hexToDecimalString(hex: string): string { return BigInt(addHexPrefix(hex)).toString(10); } /** - * Remove hex string leading zero and lowercase it - * @example '0x01A...' -> '0x1a..' + * Remove hex string leading zero and lowercase it; * @param hex hex-string * @returns format: hex-string + * @example + * ```typescript + * const hexString = '0x01A2F3' + * const result = cleanHex(hexString); + * // result = '0x1a2f3' + * ``` */ export const cleanHex = (hex: string) => hex.toLowerCase().replace(/^(0x)0+/, '$1'); /** - * Asserts input is equal to or greater then lowerBound and lower then upperBound. + * Asserts input is equal to or greater than lowerBound and lower than upperBound. * * The `inputName` parameter is used in the assertion message. + * @param input Value to check + * @param lowerBound Lower bound value + * @param upperBound Upper bound value + * @param inputName Name of the input for error message + * @Throws Error if input is out of range + * @example + * ```typescript + * const input1:BigNumberish = 10; + * assertInRange(input1, 5, 20, 'value') + * + * const input2: BigNumberish = 25; + * assertInRange(input2, 5, 20, 'value'); + * // Throws Error: Message not signable, invalid value length. + * ``` */ export function assertInRange( input: BigNumberish, @@ -97,7 +169,14 @@ export function assertInRange( /** * Convert BigNumberish array to decimal string array + * @param rawCalldata Array of BigNumberish values * @returns format: decimal string array + * @example + * ```typescript + * const bigNumberishArray: BigNumberish[] = [123, "456", 789n]; + * const result = bigNumberishArrayToDecimalStringArray(bigNumberishArray); + * // result = ["123", "456", "789"] + * ``` */ export function bigNumberishArrayToDecimalStringArray(rawCalldata: BigNumberish[]): string[] { return rawCalldata.map((x) => toBigInt(x).toString(10)); @@ -105,7 +184,14 @@ export function bigNumberishArrayToDecimalStringArray(rawCalldata: BigNumberish[ /** * Convert BigNumberish array to hexadecimal string array + * @param rawCalldata Array of BigNumberish values * @returns format: hex-string array + * @example + * ```typescript + * const bigNumberishArray: BigNumberish[] = [123, "456", 789n]; + * const result = bigNumberishArrayToHexadecimalStringArray(bigNumberishArray); + * // result = ["0x7b", "0x1c8", "0x315"] + * ``` */ export function bigNumberishArrayToHexadecimalStringArray(rawCalldata: BigNumberish[]): string[] { return rawCalldata.map((x) => toHex(x)); @@ -113,12 +199,28 @@ export function bigNumberishArrayToHexadecimalStringArray(rawCalldata: BigNumber /** * Test if string is whole number (0, 1, 2, 3...) + * @param value The string to be tested. + * @returns {boolean} Returns true if the value is a number, otherwise returns false. + * @example + * ```typescript + * const result = isStringWholeNumber("123"); + * // result = true + * ``` */ export const isStringWholeNumber = (value: string) => /^\d+$/.test(value); /** * Convert string to decimal string + * @param value The string to be converted. * @returns format: decimal string + * @example + * ```typescript + * const result = getDecimalString("0x1a"); + * // result = "26" + * + * const result2 = getDecimalString("Hello"); + * // Throws Error: "Hello need to be hex-string or whole-number-string" + * ``` */ export function getDecimalString(value: string) { if (isHex(value)) { @@ -132,7 +234,16 @@ export function getDecimalString(value: string) { /** * Convert string to hexadecimal string + * @param value The string to be converted. * @returns format: hex-string + * @example + * ```typescript + * const result = getHexString("123"); + * // result = "0x7b" + * + * const result2 = getHexString("Hello"); + * // Throws Error: Hello need to be hex-string or whole-number-string + * ``` */ export function getHexString(value: string) { if (isHex(value)) { @@ -146,7 +257,14 @@ export function getHexString(value: string) { /** * Convert string array to hex-string array + * @param value The string array to be converted. * @returns format: hex-string array + * @example + * ```typescript + * const stringArray: string[] = ["123", "456", "789"]; + * const result = getHexStringArray(stringArray); + * // result = ["0x7b", "0x1c8", "0x315"] + * ``` */ export function getHexStringArray(value: Array) { return value.map((el) => getHexString(el)); @@ -154,12 +272,28 @@ export function getHexStringArray(value: Array) { /** * Convert boolean to "0" or "1" + * @param value The boolean value to be converted. + * @returns {boolean} Returns true if the value is a number, otherwise returns false. + * @example + * ```typescript + * const result = toCairoBool(true); + * // result ="1" + * + * const result2 = toCairoBool(false); + * // result2 = "0" + * ``` */ export const toCairoBool = (value: boolean): string => (+value).toString(); /** * Convert hex-string to an array of Bytes (Uint8Array) - * @param value hex-string + * @param value The hex-string to be converted. + * @returns The array of bytes (Uint8Array) corresponding to the hex-string. + * @example + * ```typescript + * const result = hexToBytes("0x123456"); + * // result = Uint8Array [ 18, 52, 86 ] + * ``` */ export function hexToBytes(value: string): Uint8Array { if (!isHex(value)) throw new Error(`${value} need to be a hex-string`); @@ -172,10 +306,15 @@ export function hexToBytes(value: string): Uint8Array { } /** - * - * @param number value to be increased + * Increase a give number by specified percentage + * @param number The value to be increased (BigInt or number). * @param percent integer as percent ex. 50 for 50% - * @returns increased value + * @returns The increased value as a BigInt. + * @example + * ```typescript + * const result = addPercent(100, 50); + * // result = 150n + * ``` */ export function addPercent(number: BigNumberish, percent: number) { const bigIntNum = BigInt(number); @@ -186,7 +325,15 @@ export function addPercent(number: BigNumberish, percent: number) { * Check if a value is a number. * * @param {unknown} value - The value to check. - * @return {boolean} Returns true if the value is a number, otherwise returns false. + * @returns {boolean} Returns true if the value is a number, otherwise returns false. + * @example + * ```typescript + * const result = isNumber(123); + * // result = true + * + * const result2 = isNumber("123"); + * // result2 = false + * ``` */ export function isNumber(value: unknown): value is number { return typeof value === 'number'; @@ -196,7 +343,15 @@ export function isNumber(value: unknown): value is number { * Checks if a given value is of boolean type. * * @param {unknown} value - The value to check. - * @return {boolean} - True if the value is of boolean type, false otherwise. + * @returns {boolean} - True if the value is of boolean type, false otherwise. + * @example + * ```typescript + * const result = isBoolean(true); + * // result = true + * + * const result2 = isBoolean(false); + * // result2 = false + * ``` */ export function isBoolean(value: unknown): value is boolean { return typeof value === 'boolean'; diff --git a/src/utils/responseParser/index.ts b/src/utils/responseParser/index.ts index 9161fc124..9605da691 100644 --- a/src/utils/responseParser/index.ts +++ b/src/utils/responseParser/index.ts @@ -1,4 +1,6 @@ import { + BlockWithTxHashes, + FeeEstimate, CallContractResponse, DeclareContractResponse, DeployContractResponse, @@ -11,13 +13,13 @@ import { import type { GetTransactionReceiptResponse } from '../transactionReceipt'; export abstract class ResponseParser { - abstract parseGetBlockResponse(res: any): GetBlockResponse; + abstract parseGetBlockResponse(res: BlockWithTxHashes): GetBlockResponse; abstract parseGetTransactionResponse(res: any): GetTransactionResponse; abstract parseGetTransactionReceiptResponse(res: any): GetTransactionReceiptResponse; - abstract parseFeeEstimateResponse(res: any): EstimateFeeResponse; + abstract parseFeeEstimateResponse(res: FeeEstimate[]): EstimateFeeResponse; abstract parseCallContractResponse(res: any): CallContractResponse; diff --git a/src/utils/selector.ts b/src/utils/selector.ts index 1a137a62b..c54029962 100644 --- a/src/utils/selector.ts +++ b/src/utils/selector.ts @@ -7,9 +7,13 @@ import { hexToBytes, isHex, isStringWholeNumber, toHex, toHexString } from './nu /** * Calculate hex-string keccak hash for a given BigNumberish - * - * BigNumberish -> hex-string keccak hash - * @returns format: hex-string + * @param value The value you want to get the keccak hash from. + * @returns format: hex-string keccak hash + * @example + * ```typescript + * const hash: string = keccakBn(123456789); + * // hash = "0x6c1eebcad9e5b7e0f13855f5e4b56e85ad24544b" + * ``` */ export function keccakBn(value: BigNumberish): string { const hexWithoutPrefix = removeHexPrefix(toHex(BigInt(value))); @@ -19,9 +23,14 @@ export function keccakBn(value: BigNumberish): string { /** * Calculate hex-string keccak hash for a given string - * + * @param str The value you want to get the keccak hash from. * String -> hex-string keccak hash * @returns format: hex-string + * @example + * ```typescript + * const hash: string = keccakHex("Hello, world!"); + * // hash = "0x3ad6fcbda8fc87e9fb42f7f0cd36d27da079ffafc6f0dcf36b6a6140e0f67c84" + * ``` */ function keccakHex(str: string): string { return addHexPrefix(keccak(utf8ToArray(str)).toString(16)); @@ -35,6 +44,10 @@ function keccakHex(str: string): string { * [Reference](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/public/abi.py#L17-L22) * @param str the value you want to get the keccak hash from * @returns starknet keccak hash as BigInt + * @example + * ```typescript + * const hash: bigint = starknetKeccak("Hello, world!"); + * // hash = "38418923196344919485056939258679159916n" */ export function starknetKeccak(str: string): bigint { const hash = BigInt(keccakHex(str)); @@ -48,8 +61,13 @@ export function starknetKeccak(str: string): bigint { * Abi-function-name -> hex-string selector * * [Reference](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/public/abi.py#L25-L26) - * @param funcName ascii-string of 'abi function name' - * @returns format: hex-string; selector for 'abi function name' + * @param funcName ascii-string of 'abi function name'. + * @returns format: hex-string; selector for 'abi function name'. + * @example + * ```typescript + * const selector: string = getSelectorFromName("myFunction"); + * // selector = "0x7e44baf0" + * ``` */ export function getSelectorFromName(funcName: string) { // sometimes BigInteger pads the hex string with zeros, which is not allowed in the starknet api @@ -63,6 +81,17 @@ export function getSelectorFromName(funcName: string) { * * @param value hex-string | dec-string | ascii-string * @returns format: hex-string + * @example + * ```typescript + * const selector: string = getSelector("myFunction"); + * // selector = "0x7e44bafo" + * + * const selector1: string = getSelector("0x123abc"); + * // selector1 = "0x123abc" + * + * const selector2: string = getSelector("123456"); + * // selector2 = "0x1e240" + * ``` */ export function getSelector(value: string) { if (isHex(value)) { diff --git a/www/docs/guides/define_call_message.md b/www/docs/guides/define_call_message.md index 8aa2965cd..990494c39 100644 --- a/www/docs/guides/define_call_message.md +++ b/www/docs/guides/define_call_message.md @@ -603,3 +603,13 @@ The result will be an object, with 2 strings: ```typescript { name: "Organic", description: "The best way to read a long string!!!" } ``` + +## Tool to learn how to encode/decode + +A DAPP has been created to learn how to encode/decode with Starknet.js : **Startnet-encode-decode**. +It's also a convenient tool for the exploration of any contract ABI. +![](./pictures/encodeFn2.png) + +Follow these links : +DAPP : https://starknet-encode-decode.vercel.app/ +Tuto : https://github.com/PhilippeR26/starknet-encode-decode/blob/main/tuto.md diff --git a/www/docs/guides/pictures/encodeFn2.png b/www/docs/guides/pictures/encodeFn2.png new file mode 100644 index 000000000..0135cf123 Binary files /dev/null and b/www/docs/guides/pictures/encodeFn2.png differ