├── .eslintrc.js ├── .github └── workflows │ └── pr-checks.yml ├── .gitignore ├── LICENSE ├── README.md ├── index.ts ├── jest.config.js ├── package-lock.json ├── package.json ├── tests └── index.test.ts ├── tsconfig.json ├── tsconfig.typecheck.json └── types └── blake2b └── index.d.ts /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | parserOptions: { 4 | ecmaVersion: 2017, 5 | project: './tsconfig.typecheck.json', 6 | sourceType: "module", 7 | }, 8 | env: { 9 | browser: true, 10 | mocha: true, 11 | node: true, 12 | 'jest/globals': true, 13 | webextensions: true, 14 | }, 15 | extends: [ 16 | 'airbnb-typescript/base', 17 | "plugin:@typescript-eslint/recommended", 18 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', 19 | 'plugin:jest/recommended', 20 | 'prettier', 21 | ], 22 | plugins: ['@typescript-eslint', 'import', 'prettier'], 23 | rules: { 24 | 'no-use-before-define': 'off', 25 | '@typescript-eslint/no-use-before-define': 'off', 26 | } 27 | }; -------------------------------------------------------------------------------- /.github/workflows/pr-checks.yml: -------------------------------------------------------------------------------- 1 | name: PR Checks 2 | 3 | on: 4 | pull_request_review: 5 | types: [submitted] 6 | 7 | jobs: 8 | lint-and-test: 9 | if: github.event.review && (github.event.review.state == 'approved' || contains(github.event.review.body, '/check')) 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: '14.15.5' 16 | - name: Cache node modules 17 | uses: actions/cache@v1 18 | with: 19 | path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS 20 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 21 | restore-keys: | 22 | ${{ runner.os }}-build-${{ env.cache-name }}- 23 | ${{ runner.os }}-build- 24 | ${{ runner.os }}- 25 | - name: install 26 | run: | 27 | npm install 28 | - name: run eslint 29 | run: | 30 | npm run eslint 31 | - name: run test 32 | run: | 33 | npm run test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 EMURGO 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CIP14-JS 2 | 3 | On the Cardano blockchain, native assets are uniquely identified by both their _policy id_ and _asset name_. Neither the policy id nor the asset name are intended to be human-readable data. [CIP14](https://github.com/cardano-foundation/CIPs/pull/64) introduces an _asset fingerprint_ which is a short(er) and human-readable identifier for assets that user can recognize and refer to when talking about assets. 4 | 5 | More specifically, CIP14 defines a user-facing asset fingerprint as a bech32-encoded blake2b-160 digest of the concatenation of the policy id and the asset name. 6 | 7 | This package is a Typescript implementation of CIP14 8 | 9 | ## Install 10 | 11 | ``` sh 12 | npm i @emurgo/cip14-js --save 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```js 18 | const AssetFingerprint = require('@emurgo/cip14-js'); 19 | 20 | // initialize class with policyId, assetName 21 | const assetFingerprint = AssetFingerprint.fromParts( 22 | Buffer.from('1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209', 'hex'), 23 | Buffer.from('504154415445', 'hex'), 24 | ); 25 | 26 | const fingerprintHash = assetFingerprint.hash(); 27 | const bech32Fingerprint = assetFingerprint.fingerprint(); 28 | ``` 29 | 30 | ```js 31 | // initialize class with bech32 32 | const assetFingerprint = AssetFingerprint.fromBech32('asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3'); 33 | 34 | const fingerprintHash = assetFingerprint.hash(); 35 | const prefix = assetFingerprint.prefix(); 36 | ``` 37 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import blake2b from "blake2b"; 2 | import { bech32 } from "bech32"; 3 | 4 | /// note: this function can't be inverted due to the hash 5 | 6 | const DATA = "asset"; 7 | 8 | export default class AssetFingerprint { 9 | readonly hashBuf: Uint8Array; 10 | 11 | private constructor(hashBuf: Uint8Array) { 12 | this.hashBuf = hashBuf; 13 | } 14 | 15 | static fromHash(hash: Uint8Array): AssetFingerprint { 16 | return new AssetFingerprint(hash); 17 | } 18 | 19 | static fromParts( 20 | policyId: Uint8Array, 21 | assetName: Uint8Array 22 | ): AssetFingerprint { 23 | // see https://github.com/cardano-foundation/CIPs/pull/64 24 | const hashBuf = blake2b(20) 25 | .update(new Uint8Array([...policyId, ...assetName])) 26 | .digest("binary"); 27 | 28 | return AssetFingerprint.fromHash(hashBuf); 29 | } 30 | 31 | static fromBech32(fingerprint: string): AssetFingerprint { 32 | const { prefix, words } = bech32.decode(fingerprint); 33 | if (prefix !== DATA) { 34 | throw new Error("Invalid asset fingerprint"); 35 | } 36 | 37 | const hashBuf = Buffer.from(bech32.fromWords(words)); 38 | return AssetFingerprint.fromHash(hashBuf); 39 | } 40 | 41 | fingerprint(): string { 42 | const words = bech32.toWords(this.hashBuf); 43 | return bech32.encode(DATA, words); 44 | } 45 | 46 | hash(): string { 47 | return Buffer.from(this.hashBuf).toString("hex"); 48 | } 49 | 50 | prefix(): string { 51 | return DATA; 52 | } 53 | 54 | // The last six characters of the data part form a checksum and contain no information 55 | checksum(): string { 56 | return this.fingerprint().slice(-6); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: {'^.+\\.ts?$': 'ts-jest'}, 3 | testEnvironment: 'node', 4 | testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$', 5 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'] 6 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@emurgo/cip14-js", 3 | "version": "3.0.1", 4 | "description": "A Javascript library reference implementation for CIP14", 5 | "main": "./index.js", 6 | "types": "./index.d.ts", 7 | "scripts": { 8 | "build": "npm run clean && tsc && npm run flowgen && npm run copy-misc", 9 | "clean": "rm -rf ./dist/", 10 | "copy-misc": "cp package.json dist/ && cp README.md dist/", 11 | "eslint": "eslint ./index.ts ./tests/index.test.ts", 12 | "flowgen": "flowgen ./dist/index.d.ts --no-inexact --add-flow-header -o dist/index.js.flow", 13 | "npm-publish": "npm run verify && npm run build && cd dist && npm publish --access public && cd ..", 14 | "test": "tsc --noEmit && jest", 15 | "verify": "npm run eslint && npm run test" 16 | }, 17 | "husky": { 18 | "hooks": { 19 | "pre-push": "npm run verify" 20 | } 21 | }, 22 | "license": "Apache-2.0 OR MIT", 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/Emurgo/cip14-js.git" 26 | }, 27 | "author": "EMURGO", 28 | "homepage": "https://github.com/Emurgo/cip14-js#readme", 29 | "dependencies": { 30 | "bech32": "2.0.0", 31 | "blake2b": "2.1.3" 32 | }, 33 | "devDependencies": { 34 | "@types/eslint-plugin-prettier": "^3.1.0", 35 | "@types/jest": "27.0.1", 36 | "@typescript-eslint/eslint-plugin": "^4.31.1", 37 | "@typescript-eslint/parser": "^4.31.1", 38 | "eslint": "^7.32.0", 39 | "eslint-config-airbnb-base": "^14.2.1", 40 | "eslint-config-airbnb-typescript": "^14.0.0", 41 | "eslint-config-prettier": "^8.3.0", 42 | "eslint-plugin-import": "^2.24.2", 43 | "eslint-plugin-jest": "^24.4.0", 44 | "eslint-plugin-prettier": "^4.0.0", 45 | "flowgen": "1.14.1", 46 | "husky": "5.1.1", 47 | "jest": "27.2.0", 48 | "prettier": "^2.4.0", 49 | "ts-jest": "27.0.5", 50 | "tslint": "6.1.3", 51 | "typescript": "4.4.3" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/index.test.ts: -------------------------------------------------------------------------------- 1 | import AssetFingerprint from "../index"; 2 | 3 | function createFingerprint(policyId: string, assetName: string): string { 4 | const fingerprint = AssetFingerprint.fromParts( 5 | Buffer.from(policyId, "hex"), 6 | Buffer.from(assetName, "hex") 7 | ); 8 | return fingerprint.fingerprint(); 9 | } 10 | test("Fingerprint is correctly generated", () => { 11 | expect( 12 | createFingerprint( 13 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 14 | "" 15 | ) 16 | ).toEqual("asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3"); 17 | 18 | expect( 19 | createFingerprint( 20 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc37e", 21 | "" 22 | ) 23 | ).toEqual("asset1nl0puwxmhas8fawxp8nx4e2q3wekg969n2auw3"); 24 | 25 | expect( 26 | createFingerprint( 27 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 28 | "" 29 | ) 30 | ).toEqual("asset1uyuxku60yqe57nusqzjx38aan3f2wq6s93f6ea"); 31 | 32 | expect( 33 | createFingerprint( 34 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 35 | "504154415445" 36 | ) 37 | ).toEqual("asset13n25uv0yaf5kus35fm2k86cqy60z58d9xmde92"); 38 | 39 | expect( 40 | createFingerprint( 41 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 42 | "504154415445" 43 | ) 44 | ).toEqual("asset1hv4p5tv2a837mzqrst04d0dcptdjmluqvdx9k3"); 45 | 46 | expect( 47 | createFingerprint( 48 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 49 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373" 50 | ) 51 | ).toEqual("asset1aqrdypg669jgazruv5ah07nuyqe0wxjhe2el6f"); 52 | 53 | expect( 54 | createFingerprint( 55 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 56 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209" 57 | ) 58 | ).toEqual("asset17jd78wukhtrnmjh3fngzasxm8rck0l2r4hhyyt"); 59 | 60 | expect( 61 | createFingerprint( 62 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 63 | "0000000000000000000000000000000000000000000000000000000000000000" 64 | ) 65 | ).toEqual("asset1pkpwyknlvul7az0xx8czhl60pyel45rpje4z8w"); 66 | }); 67 | 68 | function roundtripFromHash(policyId: string, assetName: string): string { 69 | const fingerprint = AssetFingerprint.fromParts( 70 | Buffer.from(policyId, "hex"), 71 | Buffer.from(assetName, "hex") 72 | ); 73 | 74 | const hash = Buffer.from(fingerprint.hash(), "hex"); 75 | 76 | const reconstructed = AssetFingerprint.fromHash(hash); 77 | return reconstructed.fingerprint(); 78 | } 79 | test("Can generate fingerprint with hash", () => { 80 | expect( 81 | roundtripFromHash( 82 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 83 | "" 84 | ) 85 | ).toEqual("asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3"); 86 | 87 | expect( 88 | roundtripFromHash( 89 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc37e", 90 | "" 91 | ) 92 | ).toEqual("asset1nl0puwxmhas8fawxp8nx4e2q3wekg969n2auw3"); 93 | 94 | expect( 95 | roundtripFromHash( 96 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 97 | "" 98 | ) 99 | ).toEqual("asset1uyuxku60yqe57nusqzjx38aan3f2wq6s93f6ea"); 100 | 101 | expect( 102 | roundtripFromHash( 103 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 104 | "504154415445" 105 | ) 106 | ).toEqual("asset13n25uv0yaf5kus35fm2k86cqy60z58d9xmde92"); 107 | 108 | expect( 109 | roundtripFromHash( 110 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 111 | "504154415445" 112 | ) 113 | ).toEqual("asset1hv4p5tv2a837mzqrst04d0dcptdjmluqvdx9k3"); 114 | 115 | expect( 116 | roundtripFromHash( 117 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 118 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373" 119 | ) 120 | ).toEqual("asset1aqrdypg669jgazruv5ah07nuyqe0wxjhe2el6f"); 121 | 122 | expect( 123 | roundtripFromHash( 124 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 125 | "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209" 126 | ) 127 | ).toEqual("asset17jd78wukhtrnmjh3fngzasxm8rck0l2r4hhyyt"); 128 | 129 | expect( 130 | roundtripFromHash( 131 | "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 132 | "0000000000000000000000000000000000000000000000000000000000000000" 133 | ) 134 | ).toEqual("asset1pkpwyknlvul7az0xx8czhl60pyel45rpje4z8w"); 135 | }); 136 | 137 | test("can get hash from bech32", () => { 138 | expect( 139 | AssetFingerprint.fromBech32( 140 | "asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3" 141 | ).hash() 142 | ).toEqual("1cadfc0e7068801d51d240d14a4085f2a3673cbb"); 143 | 144 | expect( 145 | AssetFingerprint.fromBech32( 146 | "asset1nl0puwxmhas8fawxp8nx4e2q3wekg969n2auw3" 147 | ).hash() 148 | ).toEqual("9fde1e38dbbf6074f5c609e66ae5408bb3641745"); 149 | 150 | expect( 151 | AssetFingerprint.fromBech32( 152 | "asset1uyuxku60yqe57nusqzjx38aan3f2wq6s93f6ea" 153 | ).hash() 154 | ).toEqual("e1386b734f20334f4f9000a4689fbd9c52a70350"); 155 | }); 156 | 157 | test("can get checksum from bech32", () => { 158 | expect( 159 | AssetFingerprint.fromBech32( 160 | "asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3" 161 | ).checksum() 162 | ).toEqual("lgvlc3"); 163 | 164 | expect( 165 | AssetFingerprint.fromBech32( 166 | "asset1nl0puwxmhas8fawxp8nx4e2q3wekg969n2auw3" 167 | ).checksum() 168 | ).toEqual("n2auw3"); 169 | 170 | expect( 171 | AssetFingerprint.fromBech32( 172 | "asset1uyuxku60yqe57nusqzjx38aan3f2wq6s93f6ea" 173 | ).checksum() 174 | ).toEqual("93f6ea"); 175 | }); 176 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": [], /* Specify library files to be included in the compilation. */ 7 | // "allowJs": true, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 12 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | "outDir": "dist", /* Redirect output structure to the directory. */ 15 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "composite": true, /* Enable project compilation */ 17 | // "removeComments": true, /* Do not emit comments to output. */ 18 | // "noEmit": true, /* Do not emit outputs. */ 19 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 20 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 21 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 22 | 23 | /* Strict Type-Checking Options */ 24 | "strict": true, /* Enable all strict type-checking options. */ 25 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 26 | "strictNullChecks": true, /* Enable strict null checks. */ 27 | "strictFunctionTypes": true, /* Enable strict checking of function types. */ 28 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 29 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 30 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 31 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 32 | 33 | /* Additional Checks */ 34 | "noUnusedLocals": true, /* Report errors on unused locals. */ 35 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 36 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 37 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 38 | 39 | /* Module Resolution Options */ 40 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 41 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 42 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 43 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 44 | "typeRoots": [ /* List of folders to include type definitions from. */ 45 | "./node_modules/@types", 46 | "./types" 47 | ], 48 | // "types": [], /* Type declaration files to be included in compilation. */ 49 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 50 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 51 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | }, 63 | "include": ["index.ts"], 64 | } 65 | -------------------------------------------------------------------------------- /tsconfig.typecheck.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | }, 6 | "include": [ 7 | "index.ts", 8 | "tests/**/*", 9 | ], 10 | } -------------------------------------------------------------------------------- /types/blake2b/index.d.ts: -------------------------------------------------------------------------------- 1 | declare class Blake2b { 2 | update(input: Uint8Array): this 3 | digest(out: "hex"): string 4 | digest(out: "binary" | Uint8Array): Uint8Array 5 | } 6 | type Ctx = { 7 | b: Uint8Array; 8 | h: Uint32Array; 9 | t: number; // input count 10 | c: number; // pointer within buffer 11 | outlen: number; // output length in bytes 12 | }; 13 | 14 | declare module 'blake2b' { 15 | export default function createHash( 16 | outlen?: number, 17 | key?: Uint8Array | undefined, 18 | salt?: Uint8Array | undefined, 19 | personal?: Uint8Array | undefined, 20 | noAssert?: boolean 21 | ): Blake2b; 22 | } 23 | --------------------------------------------------------------------------------