├── .circleci └── config.yml ├── .editorconfig ├── .github ├── CODEOWNERS ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature-request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── commit-changelog │ ├── commit-changelog.yml │ └── npmpublish.yml ├── .gitignore ├── .husky └── .gitignore ├── .npmignore ├── .prettierignore ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── developers-sdk-js.code-workspace ├── docs ├── README.md └── lbd-new-tx-result.md ├── examples ├── commonJsExample │ ├── .babelrc │ ├── index.js │ └── package.json └── es5Example │ ├── .idea │ ├── .gitignore │ ├── es5Example.iml │ ├── modules.xml │ └── vcs.xml │ ├── index.js │ ├── package.json │ └── sdkClient.js ├── integration-test └── api.spec.ts ├── lib ├── commonTypes.ts ├── constants.ts ├── exceptions.ts ├── http-client-base.ts ├── index.ts ├── logger-factory.ts ├── logger-wrapper.ts ├── request-body-flattener.ts ├── request-parameter-validator.ts ├── request.ts ├── response.ts ├── signature-generator.ts ├── string-util.ts ├── token-util.ts ├── transaction-message-parser.ts ├── transaction-messages.ts ├── tx-core-models.ts ├── tx-raw-models.ts ├── tx-result-adapters.ts ├── tx-result-codes.ts └── tx-result-util.ts ├── npmpublish.yml ├── package.json ├── scripts ├── generate-changelog.sh └── generate-changelog.ts ├── test ├── get-signer-addresses.spec.ts ├── http-client-base-v2-api.spec.ts ├── http-client-base.spec.ts ├── http-test-util.ts ├── lbd-tx-event-adapter.spec.ts ├── lbd-tx-result-adapter.spec.ts ├── lbd-tx-summary-adapter.spec.ts ├── raw-event-types-util.spec.ts ├── raw-transaction-event.spec.ts ├── raw-transaction-result.spc.ts ├── raw-tx-result-adapter.spec.ts ├── request-body-flattener.spec.ts ├── request-parameter-validator.spec.ts ├── request.spec.ts ├── sinature-generator.spec.ts ├── string-util.spec.ts ├── test-data-v2.ts ├── test-data.ts ├── tx-core-models.spec.ts ├── tx-event-adapter.spec.ts ├── tx-result-code-mappings-prvider.spec.ts ├── tx-result-message-parser-factory.spec.ts └── tx-result-util.spec.ts └── tsconfig.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | executors: 3 | node14-executor: 4 | docker: 5 | - image: node:14-alpine3.16 6 | 7 | jobs: 8 | build: 9 | executor: node14-executor 10 | steps: 11 | - checkout 12 | - run: | 13 | npm install 14 | npm build 15 | lint: 16 | executor: node14-executor 17 | steps: 18 | - checkout 19 | - run: | 20 | npm install 21 | npm run format:check 22 | test: 23 | executor: node14-executor 24 | steps: 25 | - checkout 26 | - run: | 27 | npm install 28 | npm run test 29 | 30 | workflows: 31 | push-workflow: 32 | jobs: 33 | - build 34 | - lint 35 | - test 36 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 120 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | line/lbd-sdk-js-admin -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Example Contributing Guidelines 2 | 3 | This is an example of GitHub's contributing guidelines file. Check out GitHub's [CONTRIBUTING.md help center article](https://help.github.com/articles/setting-guidelines-for-repository-contributors/) for more information. 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us squash bugs! 4 | 5 | --- 6 | 12 | 13 | ### Default information 14 | * lbd-sdk-js version: `e.g. 1.0.0` 15 | * nodeJs version: `e.g. v10.x.x.` 16 | * module-type(specify `type` value in `package.json`): `e.g. commonJs` 17 | 18 | 19 | ### Description of the bug 20 | Please add some summary or shrot description of the bug 21 | 22 | #### Example codes 23 | Please put the example code where you find the bug 24 | 25 | #### Error logs 26 | Please add error logs from the bug 27 | 28 | ### Anything else we need to know 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Create a proposal to request a feature 4 | 5 | --- 6 | 7 | ## Summary 8 | 9 | ## Problem Definition 10 | 11 | * Why do we need this feature? 12 | * What problems may be addressed by introducing this feature? 13 | * What benefits does lbd-sdk-js stand to gain by including this feature? 14 | * Are there any disadvantages of including this feature? 15 | 16 | ## Proposal 17 | Please add detailed description of requirements of implementation 18 | 19 | ## Check-list 20 | - [ ] Not duplicate issue 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What kind of change does this PR introduce? 2 | * [ ] bug fix 3 | * [ ] feature 4 | * [ ] docs 5 | * [ ] update 6 | 7 | ### What is the current behavior? 8 | You can also link to an open issue here 9 | 10 | ### What is the new behavior? 11 | if this is a feature change 12 | 13 | ### Other information 14 | -------------------------------------------------------------------------------- /.github/workflows/commit-changelog: -------------------------------------------------------------------------------- 1 | name: Changelog CI 2 | 3 | # Controls when the action will run. Triggers the workflow on a pull request 4 | on: 5 | pull_request: 6 | types: [opened, reopened] 7 | branches: 8 | - master 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | - name: Install Dependency 19 | run: npm i 20 | 21 | - name: Run Changelog CI 22 | run: ./scripts/generate-changelog.sh 23 | -------------------------------------------------------------------------------- /.github/workflows/commit-changelog.yml: -------------------------------------------------------------------------------- 1 | name: Changelog CI 2 | 3 | # Controls when the action will run. Triggers the workflow on a pull request 4 | on: 5 | pull_request: 6 | types: [ opened, reopened ] 7 | branches: 8 | - master 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | - name: Install Dependency 19 | run: npm i 20 | 21 | - name: Run Changelog CI 22 | run: ./scripts/generate-changelog.sh 23 | -------------------------------------------------------------------------------- /.github/workflows/npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-node@v3 13 | with: 14 | node-version: 12 15 | - run: npm install 16 | - run: npm run build 17 | # - run: npm test 18 | - uses: JS-DevTools/npm-publish@v1 19 | with: 20 | token: ${{ secrets.NPM_TOKEN }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | .nyc_output 3 | build 4 | node_modules 5 | src/**.js 6 | coverage 7 | *.log 8 | package-lock.json 9 | *.env 10 | dist 11 | *.tsbuildinfo 12 | .DS_Store 13 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | tsconfig.json 2 | src 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # package.json is formatted by package managers, so we ignore it here 2 | package.json 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "eamodio.gitlens", 6 | "streetsidesoftware.code-spell-checker" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | // To debug, make sure a *.spec.ts file is active in the editor, then run a configuration 5 | { 6 | "type": "node", 7 | "request": "launch", 8 | "name": "Debug Active Spec", 9 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava", 10 | "runtimeArgs": [ 11 | "debug", 12 | "--break", 13 | "--serial", 14 | "${file}" 15 | ], 16 | "port": 9229, 17 | "outputCapture": "std", 18 | "skipFiles": [ 19 | "/**/*.js" 20 | ], 21 | "preLaunchTask": "npm: build" 22 | // "smartStep": true 23 | }, 24 | { 25 | // Use this one if you're already running `yarn watch` 26 | "type": "node", 27 | "request": "launch", 28 | "name": "Debug Active Spec (no build)", 29 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava", 30 | "runtimeArgs": [ 31 | "debug", 32 | "--break", 33 | "--serial", 34 | "${file}" 35 | ], 36 | "port": 9229, 37 | "outputCapture": "std", 38 | "skipFiles": [ 39 | "/**/*.js" 40 | ] 41 | // "smartStep": true 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.userWords": [], 3 | // only use words from .cspell.json 4 | "cSpell.enabled": true, 5 | "editor.formatOnSave": true, 6 | "typescript.tsdk": "node_modules/typescript/lib", 7 | "typescript.enablePromptUseWorkspaceTsdk": true 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### Bug Fixes 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | dl_oss_dev@linecorp.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to `line-blochchain-developers-sdk-js` 2 | 3 | First of all, thank you so much for taking your time to contribute! 4 | It will be amazing if you could help us by doing any of the following: 5 | 6 | - File an issue in [the issue tracker](https://github.com/line/line-blockchain-developers-sdk-js/issues) to report bugs and propose new features and 7 | improvements. 8 | - Ask a question by creating a new issue in [the issue tracker](https://github.com/line/line-blockchain-developers-sdk-js/issues). 9 | - Browse [the list of previously answered questions](https://github.com/line/line-blockchain-developers-sdk-js/issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion). 10 | - Contribute your work by sending [a pull request](https://github.com/line/line-blockchain-developers-sdk-js/pulls). 11 | 12 | ## Contributor license agreement 13 | 14 | When you are sending a pull request and it's a non-trivial change beyond fixing typos, please sign 15 | the ICLA (individual contributor license agreement). Please 16 | [contact us](mailto:dl_oss_dev@linecorp.com) if you need the CCLA (corporate contributor license agreement). 17 | 18 | ## Code of conduct 19 | 20 | We expect contributors to follow [our code of conduct](CODE_OF_CONDUCT.md). 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | https://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (C) 2021 LINE Corp. 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 | https://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 | # LINE Blockchain Developers SDK for JavaScript 2 | 3 | [![License](https://img.shields.io/github/license/line/line-blockchain-developers-sdk-js)](https://github.com/line/line-blockchain-developers-sdk-js) 4 | [![NPM version](https://img.shields.io/npm/v/@line/lbd-sdk-js.svg)](https://www.npmjs.com/package/@line/lbd-sdk-js) 5 | [![NPM downloads](https://img.shields.io/npm/dm/@line/lbd-sdk-js.svg)](https://www.npmjs.com/package/@line/lbd-sdk-js) 6 | [![CircleCI](https://circleci.com/gh/line/line-blockchain-developers-sdk-js.svg?style=shield)](https://circleci.com/gh/line/line-blockchain-developers-sdk-js) 7 | 8 | 9 | ## Table of Contents 10 | * [Introduction](#introduction) 11 | * [Getting Started](#getting-Started) 12 | * [Key objects and usage](#key-objects-and-usage) 13 | 14 | ## Introduction 15 | The LINE Blockchain Developers SDK for JavaScript makes it easy to develop a service(dApp) using [LINE Blockchain Developers API](https://docs-blockchain.line.biz/api-guide/), and there are no worries about generating signature for each request. 16 | 17 | ### Documentation 18 | See the official LINE Blockchain Developers API documentation for more information. 19 | * English: https://docs-blockchain.line.biz/api-guide/ 20 | * Japanese: https://docs-blockchain.line.biz/ja/api-guide/ 21 | * Korean: https://docs-blockchain.line.biz/ko/api-guide/ 22 | 23 | ### Requirements 24 | * Node.js 10 or higher 25 | 26 | ### Installation 27 | Before getting started, you need to install the library to your project. 28 | To make installation easy, use package managers as follows: 29 | 30 | Using [npm](https://www.npmjs.com/?target=_blank): 31 | 32 | `npm install @line/lbd-sdk-js` 33 | 34 | Using [yarn](https://yarnpkg.com/?target=_blank) 35 | 36 | `yarn add @line/lbd-sdk-js` 37 | 38 | ### Versioning 39 | This project respects [semantic versioning](http://semver.org/?target=_blank). 40 | 41 | See http://semver.org/ 42 | 43 | ### Contributing 44 | Please check [CONTRIBUTING](https://github.com/line/line-blockchain-developers-sdk-js/blob/master/CONTRIBUTING.md) before making a contribution. 45 | 46 | ### License 47 | ``` 48 | Copyright (C) 2021 LINE Corp. 49 | 50 | Licensed under the Apache License, Version 2.0 (the "License"); 51 | you may not use this file except in compliance with the License. 52 | You may obtain a copy of the License at 53 | 54 | https://www.apache.org/licenses/LICENSE-2.0 55 | 56 | Unless required by applicable law or agreed to in writing, software 57 | distributed under the License is distributed on an "AS IS" BASIS, 58 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59 | See the License for the specific language governing permissions and 60 | limitations under the License. 61 | ``` 62 | 63 | ## Getting Started 64 | ### Requirements 65 | * Node.js >= 10 66 | * It uses ES2017. 67 | 68 | * [npm](https://www.npmjs.com/?target=_blank), preferably >=7 69 | 70 | Other dependencies are installed via npm(or yarn), and do not need to be pre-installed. 71 | 72 | ### Install 73 | All the dependencies can be install via [npm](https://www.npmjs.com/?target=_blank) or [yarn](https://yarnpkg.com/?target=_blank) 74 | 75 | * [npm](https://www.npmjs.com/?target=_blank) 76 | ``` 77 | npm install @line/lbd-sdk-js 78 | ``` 79 | 80 | * [yarn](https://yarnpkg.com/?target=_blank) 81 | ``` 82 | yarn add @line/lbd-sdk-js 83 | ``` 84 | 85 | Instead of using package managers, you can clone and build from source as well. Run the following scripts/commends. 86 | 87 | ``` 88 | $ git clone https://github.com/line/line-blockchain-developers-sdk-js.git 89 | $ cd line-blockchain-developers-sdk-js 90 | $ npm install 91 | $ npm run build 92 | ``` 93 | The built result will be placed in `build/`. 94 | 95 | #### Test 96 | You can run all the unit tests by following scripts. 97 | 98 | ``` 99 | npm run test 100 | ``` 101 | 102 | #### Integration tests 103 | You can **run** all the integration tests by following scripts. 104 | 105 | ``` 106 | npm run test:integration 107 | ``` 108 | 109 | > Note 110 | > 111 | > To run integration tests, `integration-test.env` is required with following properties. 112 | ``` 113 | HOST_URL=[api-url] 114 | SERVICE_ID=[your service-id] 115 | SERVICE_API_KEY=[your service-api-key] 116 | SERVICE_API_SECRET=[your service-api-secret] 117 | OWNER_ADDRESS=[your service wallet address] 118 | OWNER_SECRET=[your service wallet secret] 119 | OWNER_ADDRESS2=[your another service wallet address] 120 | SERVICE_TOKEN_CONTRACT_ID=[your service-token contract-id] 121 | ITEM_TOKEN_CONTRACT_ID=[your item-token contract-id] 122 | LINE_USER_ID=[your line user id] 123 | LINE_USER_WALLET_ADDRESS=[BitMax wallet address of the user] 124 | ``` 125 | 126 | ### Basic Usage 127 | It can be imported with [CommonJS](https://nodejs.org/docs/latest/api/modules.html?target=_blank), [ES2015 modules](https://babeljs.io/learn-es2015/#ecmascript-2015-features-modules?target=_blank), and preferably [TypeScript](https://www.typescriptlang.org/?target=_blank). 128 | 129 | The library is written in TypeScript and includes TypeScript definitions by default. Nevertheless, it can surely be used with plain JavaScript too. 130 | 131 | #### Create HttpClient 132 | ``` 133 | // CommonJS 134 | const devSdk = require('@line/lbd-sdk-js'); 135 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 136 | 137 | // ES2015 modules or TypeScript 138 | import * as devSdk from '@line/lbd-sdk-js'; 139 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 140 | 141 | ``` 142 | 143 | #### Example to get server time 144 | ##### Using promise 145 | ```JavaScript 146 | httpClient.time().then(response => { 147 | console.log("statusCode", response.statusCode); 148 | console.log("responseTime", response.responseTime); 149 | console.log("statusMessage", response.statusMessage); 150 | console.log("responseData", response.responseData); 151 | }) 152 | ``` 153 | 154 | ##### Using async function 155 | ```JavaScript 156 | async function checkServerTime() { 157 | var response = await httpClient.time(); 158 | console.log("statusCode", response.statusCode); 159 | console.log("responseTime", response.responseTime); 160 | console.log("statusMessage", response.statusMessage); 161 | console.log("responseData", response.responseData); 162 | } 163 | ``` 164 | 165 | ## Key objects and usage 166 | ### `HttpClient` 167 | This class represents an HTTP client to connect and interact with the LINE Blockchain Developers API server. It provides functions to call the endpoints of the API with mandatory and optional parameters. 168 | It's an entry point for this library, every dApp for LINE Blockchain Developers should have an instance of `HttpClient`. 169 | 170 | Create an instance with your connection and authentication information as follows: 171 | 172 | ```JavaScript 173 | // Directly import 174 | import { HttpClient } from './lib/http-client-base'; 175 | const httpClient = new HttpClient(baseUrl, apiKey, apiSecret); 176 | 177 | // CommonJS 178 | const devSdk = require('@line/lbd-sdk-js'); 179 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 180 | 181 | // ES2015 modules or TypeScript 182 | import * as devSdk from '@line/lbd-sdk-js'; 183 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 184 | ``` 185 | 186 | - `baseUrl` is the address of API server. Find one for the chain your service runs on in [API guide](https://docs-blockchain.line.biz/api-guide/). 187 | - `apiKey` is your service's API key. 188 | - `apiSecret` is your service's API secret. **Never** use the secret hard-coded in the source code. 189 | 190 | Now, you can call any endpoints via the functions of the instance. A simple example is to get the server time: 191 | 192 | ```JavaScript 193 | (async() => { 194 | const response = await httpClient.time(); 195 | console.log(response['statusCode']); 196 | })(); 197 | ``` 198 | 199 | Remember that you must handle it in an asynchronous way. 200 | 201 | ### Request and response 202 | When requesting, you can use predefined request data classes in `lib/request.ts`. Try to send a memo save request for example as follows: 203 | 204 | ```JavaScript 205 | //Directly import 206 | import { MemoRequest } from './lib/request'; 207 | 208 | (async() => { 209 | const request = new MemoRequest('my first memo', walletAddress, walletSecret); 210 | const response = await httpClient.createMemo(request); 211 | })(); 212 | ``` 213 | 214 | When you need to parse a JSON-formatted `responseData` in a response, find and use the proper response data class in `lib/response.ts`. To get the `txhash` or the above request for example: 215 | 216 | ```JavaScript 217 | import { GenericResponse, TxResultResponse } from './lib/response'; 218 | 219 | (async() => { 220 | const request = new MemoRequest('my first memo', walletAddress, walletSecret); 221 | let response: GenericResponse = await httpClient.createMemo(request); 222 | console.log(response.responseData.txhash); 223 | })(); 224 | ``` 225 | 226 | ### `SignatureGenerator` 227 | This class provides a functionality to [generate signatures](https://docs-blockchain.line.biz/api-guide/Authentication#generating-signature) for a request. 228 | 229 | All API requests, except for the endpoint to retrieve the server time, must pass authentication information and be signed. Signing is a bit annoying, but never mind, fortunately, `HttpClient` itself will import this and generate signatures before sending a request. 230 | 231 | If you do want to study how LINE Blockchain signature created, it's okay to dive into the source code. 232 | 233 | 234 | ### New transaction result 235 | Please refer to [New transaction result](./docs/README.md) 236 | -------------------------------------------------------------------------------- /developers-sdk-js.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | ### Requirements 3 | * Node.js >= 10 4 | * It uses ES2017. 5 | 6 | * [npm](https://www.npmjs.com/?target=_blank), preferably >=7 7 | 8 | Other dependencies are installed via npm(or yarn), and do not need to be pre-installed. 9 | 10 | ### Install 11 | All the dependencies can be installed via [npm](https://www.npmjs.com/?target=_blank) or [yarn](https://yarnpkg.com/?target=_blank) 12 | 13 | * [npm](https://www.npmjs.com/?target=_blank) 14 | ``` 15 | npm install @line/lbd-sdk-js 16 | ``` 17 | 18 | * [yarn](https://yarnpkg.com/?target=_blank) 19 | ``` 20 | yarn add @line/lbd-sdk-js 21 | ``` 22 | 23 | Instead of using package managers, you can clone and build from source as well. Run the following scripts/commends. 24 | 25 | ``` 26 | $ git clone https://github.com/line/line-blockchain-developers-sdk-js.git 27 | $ cd line-blockchain-developers-sdk-js 28 | $ npm install 29 | $ npm run build 30 | ``` 31 | The built result will be placed in `build/`. 32 | 33 | #### Test 34 | You can run all the unit tests by following scripts. 35 | 36 | ``` 37 | npm run test 38 | ``` 39 | 40 | #### Integration tests 41 | You can **run** all the integration tests by following scripts. 42 | 43 | ``` 44 | npm run test:integration 45 | ``` 46 | 47 | > Note 48 | > 49 | > To run integration tests, `integration-test.env` is required with following properties. 50 | ``` 51 | HOST_URL=[api-url] 52 | SERVICE_ID=[your service-id] 53 | SERVICE_API_KEY=[your service-api-key] 54 | SERVICE_API_SECRET=[your service-api-secret] 55 | OWNER_ADDRESS=[your service wallet address] 56 | OWNER_SECRET=[your service wallet secret] 57 | OWNER_ADDRESS2=[your another service wallet address] 58 | SERVICE_TOKEN_CONTRACT_ID=[your service-token contract-id] 59 | ITEM_TOKEN_CONTRACT_ID=[your item-token contract-id] 60 | LINE_USER_ID=[your line user id] 61 | LINE_USER_WALLET_ADDRESS=[BitMax wallet address of the user] 62 | ``` 63 | 64 | ### Basic Usage 65 | It can be imported with [CommonJS](https://nodejs.org/docs/latest/api/modules.html?target=_blank), [ES2015 modules](https://babeljs.io/learn-es2015/#ecmascript-2015-features-modules?target=_blank), and preferably [TypeScript](https://www.typescriptlang.org/?target=_blank). 66 | 67 | The library is written in TypeScript and includes TypeScript definitions by default. Nevertheless, it can surely be used with plain JavaScript too. 68 | 69 | #### Create HttpClient 70 | ``` 71 | // CommonJS 72 | const devSdk = require('@line/lbd-sdk-js'); 73 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 74 | 75 | // ES2015 modules or TypeScript 76 | import * as devSdk from '@line/lbd-sdk-js'; 77 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 78 | 79 | ``` 80 | 81 | #### Example to get server time 82 | ##### Using promise 83 | ```JavaScript 84 | httpClient.time().then(response => { 85 | console.log("statusCode", response.statusCode); 86 | console.log("responseTime", response.responseTime); 87 | console.log("statusMessage", response.statusMessage); 88 | console.log("responseData", response.responseData); 89 | }) 90 | ``` 91 | 92 | ##### Using async function 93 | ```JavaScript 94 | async function checkServerTime() { 95 | var response = await httpClient.time(); 96 | console.log("statusCode", response.statusCode); 97 | console.log("responseTime", response.responseTime); 98 | console.log("statusMessage", response.statusMessage); 99 | console.log("responseData", response.responseData); 100 | } 101 | ``` 102 | 103 | ## Key objects and usage 104 | ### `HttpClient` 105 | This class represents an HTTP client to connect and interact with the LINE Blockchain Developers API server. It provides functions to call the endpoints of the API with mandatory and optional parameters. 106 | It's an entry point for this library, every dApp for LINE Blockchain Developers should have an instance of `HttpClient`. 107 | 108 | Create an instance with your connection and authentication information as follows: 109 | 110 | ```JavaScript 111 | // Directly import 112 | import { HttpClient } from './lib/http-client-base'; 113 | const httpClient = new HttpClient(baseUrl, apiKey, apiSecret); 114 | 115 | // CommonJS 116 | const devSdk = require('@line/lbd-sdk-js'); 117 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 118 | 119 | // ES2015 modules or TypeScript 120 | import * as devSdk from '@line/lbd-sdk-js'; 121 | const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET) 122 | ``` 123 | 124 | - `baseUrl` is the address of API server. Find one for the chain your service runs on in [API guide](https://docs-blockchain.line.biz/api-guide/). 125 | - `apiKey` is your service's API key. 126 | - `apiSecret` is your service's API secret. **Never** use the secret hard-coded in the source code. 127 | 128 | Now, you can call any endpoints via the functions of the instance. A simple example is to get the server time: 129 | 130 | ```JavaScript 131 | (async() => { 132 | const response = await httpClient.time(); 133 | console.log(response['statusCode']); 134 | })(); 135 | ``` 136 | 137 | Remember that you must handle it in an asynchronous way. 138 | 139 | ### Request and response 140 | When requesting, you can use predefined request data classes in `lib/request.ts`. Try to send a memo save request for example as follows: 141 | 142 | ```JavaScript 143 | //Directly import 144 | import { MemoRequest } from './lib/request'; 145 | 146 | (async() => { 147 | const request = new MemoRequest('my first memo', walletAddress, walletSecret); 148 | const response = await httpClient.createMemo(request); 149 | })(); 150 | ``` 151 | 152 | When you need to parse a JSON-formatted `responseData` in a response, find and use the proper response data class in `lib/response.ts`. To get the `txhash` or the above request for example: 153 | 154 | ```JavaScript 155 | import { GenericResponse, TxResultResponse } from './lib/response'; 156 | 157 | (async() => { 158 | const request = new MemoRequest('my first memo', walletAddress, walletSecret); 159 | let response: GenericResponse = await httpClient.createMemo(request); 160 | console.log(response.responseData.txhash); 161 | })(); 162 | ``` 163 | 164 | ### `SignatureGenerator` 165 | This class provides a functionality to [generate signatures](https://docs-blockchain.line.biz/api-guide/Authentication#generating-signature) for a request. 166 | 167 | All API requests, except for the endpoint to retrieve the server time, must pass authentication information and be signed. Signing is a bit annoying, but never mind, fortunately, `HttpClient` itself will import this and generate signatures before sending a request. 168 | 169 | If you do want to study how LINE Blockchain signature created, it's okay to dive into the source code. 170 | 171 | 172 | ### New transaction result 173 | LINE Blockchain Developers provide custom transaction result that is independent from on-chain transaction result, and it is more simple and understand. The new transaction result has summary, messages and events in following structure. For more details, please visit [LINE Blockchain Docs](https://docs-blockchain.line.biz/api-guide/Callback-Response) 174 | 175 | ``` 176 | { 177 | "summary": { 178 | "height": number, 179 | "txIndex" : number, 180 | "txHash"": string, 181 | "signers": Array, 182 | "result: { 183 | "code": number, 184 | "codeSpace": string, 185 | "result": string ("SUCCEEDED", or "FAILED") 186 | } 187 | }, 188 | "txMessages": [ 189 | { 190 | "msgIndex": number, 191 | "requestType": string, 192 | "details": any (* object) 193 | } 194 | ], 195 | "txEvents": [ 196 | "eventName": string, 197 | "msgIndex": number, 198 | ... // more properties depending on each concrete event 199 | ], 200 | } 201 | ``` 202 | 203 | #### Summary 204 | "summary" has `height`, `txIndex`, `txHash`, `signers` and `result`. More details on each property are as followings. 205 | * height: block height 206 | * txIndex: this means n-th transaction in a block 207 | * txHash: hash string for a transaction 208 | * signers: wallet addresses of those who signs a transaction 209 | * result: this has `code`, `codeSpace` and `result`. 210 | * code: this is a sort of error code, and if it is not `0`, then it means the transaction has been failed. 211 | * codeSpace: Namespace of `code` 212 | * Status of the transaction confirmation displayed as either of the following. 213 | * SUCCEEDED: Confirmation successful 214 | * FAILED: Confirmation failed 215 | 216 | 217 | ### txMessages 218 | There could be messages more than one in a transaction, and a message is what a client wants to mutate such as transfer coin or token, mint, burn and so on. 219 | A message has `msgIndex`, `requestType` and `details`. More details on each property are as followings. 220 | * msgIndex: Index number of the message in a transaction 221 | * requestType: Type of the message. For example, "collection/MsgTransferNFT" 222 | * details: Value included in the message. Properties vary, depending on the type of the message. 223 | 224 | > Note 225 | > 226 | > `details` in each message isn't a fixed object, since it's hard to provide a concrete type of data when we support smart contract. With smart contracts, developers or owners of the smart contract can define their own messages with custom properties, which are not known to LINE Blockchain Developers. 227 | 228 | ### txEvents 229 | Event refers to a change in status, triggered by a confirmed transaction. Events are distinguished as base coin related events, service token related events and item token related events. Refer to [LINE Blockchain Docs](https://lbddocs-alpha.website.line-apps-dev.com/api-guide/Callback-Response#event) for event names and their properties for each type. 230 | 231 | By they way, all events basically have `msgIndex` and `eventName` properties. 232 | * msgIndex: Index number of the message caused events. 233 | * eventName: Name of an event such as `EventCoinTransferred`, `EventTokenIssued` and so on. 234 | 235 | ### Adapting to new transaction result 236 | We need a way to adapt(convert) old transaction result in sort of raw format, which is very dependent on the chain's to new structured transaction result. 237 | 238 | #### Basic adapting flow 239 | Adapting flow is simple as below. 240 | ``` 241 | Old(current) transaction result ---> raw-transaction result ---> new structured transaction result. 242 | ``` 243 | 244 | #### How to adapt old one to new one. 245 | ##### Adapting(converting) to raw-transaction result 246 | 247 | ``` 248 | ... 249 | const rawTransactionResultAdapter: TxResultAdapter = new RawTransactionResultAdapter(); 250 | // using default adapters for summary, messages and events 251 | const lbdTxResultAdapter: TxResultAdapter = new LbdTxEventsAdapterV1(HrpPrefix.TEST_NET); 252 | 253 | /* 254 | We can use custom adapters for summary, messages and events 255 | const customTxResultSummaryAdapter: TxResultAdapter = new CustomTxSummaryAdapterV1(); 256 | const customTxMessagesAdapter: TxResultAdapter> = new CustomTxMessageAdapterV1(); 257 | const customTxEventsAdapter: TxResultAdapter> = new CustomTxMessageAdapterV1(); 258 | 259 | const lbdTxResultAdapter: TxResultAdapter = new LbdTxEventsAdapterV1( 260 | HrpPrefix.TEST_NET, 261 | customTxResultSummaryAdapter , 262 | customTxMessagesAdapter, 263 | customTxEventsAdapter 264 | ); 265 | */ 266 | 267 | let txResultResponse = lbdHttpClient.transactionResult(txHash); 268 | let rawTransactionResult = rawTransactionResultAdapter.adapt(txResultResponse.responseData); 269 | let newTransactionResult = lbdTxResultAdapter.adapt(rawTransactionResult); 270 | ... 271 | ``` 272 | -------------------------------------------------------------------------------- /docs/lbd-new-tx-result.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/line/line-blockchain-developers-sdk-js/9fe01dbda203820eaa72b1ade974967fabe15a1d/docs/lbd-new-tx-result.md -------------------------------------------------------------------------------- /examples/commonJsExample/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /examples/commonJsExample/index.js: -------------------------------------------------------------------------------- 1 | const sdk = require("@line/lbd-sdk-js"); 2 | const load = require("ts-dotenv").load; 3 | 4 | const env = load( 5 | { 6 | "HOST_URL": String, 7 | "SERVICE_ID": String, 8 | "SERVICE_API_KEY": String, 9 | "SERVICE_API_SECRET": String 10 | }, { 11 | "path": "./sdk.env" 12 | } 13 | ); 14 | 15 | const client = new sdk.HttpClient(env.HOST_URL, env.SERVICE_API_KEY, env.SERVICE_API_SECRET); 16 | 17 | // promise function example 18 | client.time().then(response => { 19 | console.log("statusCode", response.statusCode); 20 | console.log("responseTime", response.responseTime); 21 | console.log("statusMessage", response.statusMessage); 22 | console.log("responseData", response.responseData); 23 | }); 24 | 25 | // async function example 26 | async function checkServerTime() { 27 | var response = await client.time(); 28 | console.log("statusCode", response.statusCode); 29 | console.log("responseTime", response.responseTime); 30 | console.log("statusMessage", response.statusMessage); 31 | console.log("responseData", response.responseData); 32 | } 33 | 34 | checkServerTime(); 35 | -------------------------------------------------------------------------------- /examples/commonJsExample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commonJsExample", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "Apache-2.0", 11 | "type": "commonjs", 12 | "dependencies": { 13 | "@line/lbd-sdk-js": "^1.4.8", 14 | "ts-dotenv": "^0.8.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/es5Example/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /examples/es5Example/.idea/es5Example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/es5Example/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/es5Example/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/es5Example/index.js: -------------------------------------------------------------------------------- 1 | import {sdkClient} from "./sdkClient.js" 2 | 3 | // promise function example 4 | sdkClient.time().then(response => { 5 | console.log("statusCode", response.statusCode); 6 | console.log("responseTime", response.responseTime); 7 | console.log("statusMessage", response.statusMessage); 8 | console.log("responseData", response.responseData); 9 | }) 10 | 11 | // async function example 12 | async function getTime() { 13 | const response = await sdkClient.time() 14 | console.log("statusCode", response.statusCode); 15 | console.log("responseTime", response.responseTime); 16 | console.log("statusMessage", response.statusMessage); 17 | console.log("responseData", response.responseData); 18 | } 19 | 20 | getTime() 21 | -------------------------------------------------------------------------------- /examples/es5Example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es5Example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "Apache-2.0", 11 | "type": "module", 12 | "dependencies": { 13 | "@line/lbd-sdk-js": "^1.4.8", 14 | "ts-dotenv": "^0.8.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/es5Example/sdkClient.js: -------------------------------------------------------------------------------- 1 | import * as Sdk from '@line/lbd-sdk-js'; 2 | import {load} from 'ts-dotenv'; 3 | 4 | const env = load( 5 | { 6 | "HOST_URL": String, 7 | "SERVICE_ID": String, 8 | "SERVICE_API_KEY": String, 9 | "SERVICE_API_SECRET": String 10 | }, { 11 | "path": "./sdk.env" 12 | } 13 | ); 14 | 15 | class SdkClient { 16 | constructor() { 17 | this.httpClient = new Sdk.HttpClient(env.HOST_URL, env.SERVICE_API_KEY, env.SERVICE_API_SECRET); 18 | } 19 | 20 | time() { 21 | return this.httpClient.time(); 22 | } 23 | } 24 | 25 | const sdkClient = new SdkClient(); 26 | export {sdkClient}; 27 | -------------------------------------------------------------------------------- /lib/commonTypes.ts: -------------------------------------------------------------------------------- 1 | export class DenomAmount { 2 | constructor(readonly amount: string, readonly denomination: string) {} 3 | 4 | public static create(obj: any): DenomAmount { 5 | return new DenomAmount(obj["amount"], obj["denom"] ?? obj["denomination"]); 6 | } 7 | } 8 | 9 | export class TokenIdAmount { 10 | constructor(readonly amount: string, readonly tokenId: string) {} 11 | 12 | public static create(obj: any): TokenIdAmount { 13 | return new TokenIdAmount(obj["amount"], obj["tokenId"]); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/constants.ts: -------------------------------------------------------------------------------- 1 | export class Constant { 2 | static SERVICE_API_KEY_HEADER = "service-api-key"; 3 | static SIGNATURE_HEADER = "Signature"; 4 | static TIMESTAMP_HEADER = "Timestamp"; 5 | static NONCE_HEADER = "Nonce"; 6 | } 7 | 8 | export class TransactionMsgTypes { 9 | static COIN_MSGSEND = "coin/MsgSend"; 10 | static TOKEN_MSGISSUE = "token/MsgIssue"; 11 | static TOKEN_MSGMINT = "token/MsgMint"; 12 | static TOKEN_MSGBURN = "token/MsgBurn"; 13 | static TOKEN_MSGBURNFROM = "token/MsgBurnFrom"; 14 | static TOKEN_MSGTRANSFER = "token/MsgTransfer"; 15 | static TOKEN_MSGTRANSFERFROM = "token/MsgTransferFrom"; 16 | static TOKEN_MSGMODIFY = "token/MsgModify"; 17 | static TOKEN_MSGAPPROVE = "token/MsgApprove"; 18 | static COLLECTION_MSGCREATECOLLECTION = "collection/MsgCreateCollection"; 19 | static COLLECTION_MSGISSUEFT = "collection/MsgIssueFT"; 20 | static COLLECTION_MSGISSUENFT = "collection/MsgIssueNFT"; 21 | static COLLECTION_MSGMINTFT = "collection/MsgMintFT"; 22 | static COLLECTION_MSGMINTNFT = "collection/MsgMintNFT"; 23 | static COLLECTION_MSGBURNFT = "collection/MsgBurnFT"; 24 | static COLLECTION_MSGBURNFTFROM = "collection/MsgBurnFTFrom"; 25 | static COLLECTION_MSGBURNNFT = "collection/MsgBurnNFT"; 26 | static COLLECTION_MSGBURNNFTFROM = "collection/MsgBurnNFTFrom"; 27 | static COLLECTION_MSGTRANSFERFT = "collection/MsgTransferFT"; 28 | static COLLECTION_MSGTRANSFERFTFROM = "collection/MsgTransferFTFrom"; 29 | static COLLECTION_MSGTRANSFERNFT = "collection/MsgTransferNFT"; 30 | static COLLECTION_MSGTRANSFERNFTFROM = "collection/MsgTransferNFTFrom"; 31 | static COLLECTION_MSGATTACH = "collection/MsgAttach"; 32 | static COLLECTION_MSGATTACHFROM = "collection/MsgAttachFrom"; 33 | static COLLECTION_MSGDETACH = "collection/MsgDetach"; 34 | static COLLECTION_MSGDETACHFROM = "collection/MsgDetachFrom"; 35 | static COLLECTION_MSGAPPROVE = "collection/MsgApprove"; 36 | static COLLECTION_MSGMODIFY = "collection/MsgModify"; 37 | static ACCOUNT_MSGEMPTY = "account/MsgEmpty"; 38 | } 39 | 40 | export class Validations { 41 | static WALLET_ADDRESS_REGEX = /^t?link[a-zA-Z0-9]{39}$/; 42 | static TOKEN_NAME_REGEX = /^[a-zA-Z0-9]{3,20}$/; 43 | static SYMBOL_NAME_REGEX = /^[A-Z][A-Z0-9]{1,4}$/; 44 | static NUMBER_FORMAT_REGEX = /^\d+$/; 45 | 46 | static PATTERN_URI_PATH = "[\\w\\.\\-\\~\\/]+"; 47 | static PATTERN_BASE_URI = `^(https:\\/\\/)${Validations.PATTERN_URI_PATH}(:[0-9]{1,5})?\\/$`; 48 | static BASE_URI_OR_EMPTY_REGEX = new RegExp(`^(${Validations.PATTERN_BASE_URI})?$`); 49 | } 50 | 51 | export enum HrpPrefix { 52 | MAIN_NET = "link", 53 | TEST_NET = "tlink", 54 | } 55 | 56 | export const EMPTY_SET: Set = new Set(); 57 | 58 | export const EMPTY_STRING_ARRAY: Array = []; 59 | -------------------------------------------------------------------------------- /lib/exceptions.ts: -------------------------------------------------------------------------------- 1 | export class JSONParseError extends Error { 2 | constructor(message: string, public raw: any) { 3 | super(message); 4 | } 5 | } 6 | 7 | export class RequestError extends Error { 8 | constructor(message: string, public code: string, public detailErrorMessage: string, private originalError: Error) { 9 | super(message); 10 | } 11 | 12 | public toString = (): string => { 13 | return `RequestError - message: ${this.message}, code: ${this.code}, detailErrorMessage: ${this.detailErrorMessage}`; 14 | }; 15 | } 16 | 17 | export class ReadError extends Error { 18 | constructor(private originalError: Error) { 19 | super(originalError.message); 20 | } 21 | 22 | public toString = (): string => { 23 | return `ReadError - error: ${this.originalError}`; 24 | }; 25 | } 26 | 27 | export class HTTPError extends Error { 28 | constructor( 29 | message: string, 30 | public statusCode: number, 31 | public statusMessage: string, 32 | public detailErrorMessage: string, 33 | public originalError: any, 34 | ) { 35 | super(message); 36 | } 37 | 38 | public toString = (): string => { 39 | return `HTTPError - message: ${this.message}, statusCode: ${this.statusCode}, statusMessage: ${this.statusMessage}, detailErrorMessage: ${this.detailErrorMessage}`; 40 | }; 41 | } 42 | 43 | export class IllegalArgumentException extends Error { 44 | constructor(message: string) { 45 | super(message); 46 | } 47 | } 48 | 49 | export class InvalidTokenIdException extends IllegalArgumentException { 50 | constructor(readonly invalidTokenId: string) { 51 | super(`Invalid token id, given token id is ${invalidTokenId}`); 52 | } 53 | } 54 | 55 | export class InvalidTokenTypeException extends IllegalArgumentException { 56 | constructor(readonly invalidTokenType: string) { 57 | super(`Invalid token type, given token type is ${invalidTokenType}`); 58 | } 59 | } 60 | 61 | export class InvalidTxResultException extends IllegalArgumentException { 62 | constructor(message: string) { 63 | super(message); 64 | } 65 | } 66 | 67 | class TxResultAdaptFailedException extends Error { 68 | constructor(message: string, readonly cause?: Error) { 69 | super(message); 70 | } 71 | } 72 | 73 | class InvalidTxResultJsonFormatException extends Error { 74 | constructor(input: string, readonly cause?: Error) { 75 | super(`Invalid tx-result json format, input: ${input}, cause: ${cause}`); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./http-client-base"; 2 | export * from "./request"; 3 | export * from "./response"; 4 | export * from "./signature-generator"; 5 | export * from "./request-body-flattener"; 6 | export * from "./commonTypes"; 7 | export * from "./constants"; 8 | export * from "./exceptions"; 9 | export * from "./http-client-base"; 10 | export * from "./string-util"; 11 | export * from "./token-util"; 12 | export * from "./transaction-message-parser"; 13 | export * from "./transaction-messages"; 14 | export * from "./tx-core-models"; 15 | export * from "./tx-raw-models"; 16 | export * from "./tx-result-adapters"; 17 | export * from "./tx-result-codes"; 18 | export * from "./tx-result-util"; 19 | -------------------------------------------------------------------------------- /lib/logger-factory.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from "tslog"; 2 | import _ from "lodash"; 3 | import { LoggerWrapper } from "./logger-wrapper"; 4 | 5 | const DEFAULT_LOG_LEVEL = process.env.log_level || "debug"; 6 | 7 | export class LoggerFactory { 8 | static logger(name: string, config: { [key: string]: any } = {}): LoggerWrapper { 9 | const loggerConfig = config 10 | ? _.cloneDeep(config) 11 | : { 12 | name: name, 13 | exposeErrorCodeFrame: false, 14 | displayFilePath: "hidden", 15 | minLevel: DEFAULT_LOG_LEVEL, 16 | }; 17 | loggerConfig["name"] = name; 18 | return new LoggerWrapper(new Logger(loggerConfig)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/logger-wrapper.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from "tslog"; 2 | 3 | export class LoggerWrapper { 4 | private logger: Logger; 5 | private on: boolean = true; 6 | 7 | constructor(logger: Logger) { 8 | this.logger = logger; 9 | } 10 | 11 | public logOn(): LoggerWrapper { 12 | this.on = true; 13 | return this; 14 | } 15 | 16 | public logOff(): LoggerWrapper { 17 | this.on = false; 18 | return this; 19 | } 20 | 21 | public silly(...args: unknown[]): void { 22 | this.on ? this.logger.silly(...args) : null; 23 | } 24 | 25 | public trace(...args: unknown[]): void { 26 | this.on ? this.logger.trace(...args) : null; 27 | } 28 | 29 | public debug(...args: unknown[]): void { 30 | this.on ? this.logger.debug(...args) : null; 31 | } 32 | 33 | public info(...args: unknown[]): void { 34 | this.on ? this.logger.info(...args) : null; 35 | } 36 | 37 | public warn(...args: unknown[]): void { 38 | this.on ? this.logger.warn(...args) : null; 39 | } 40 | 41 | public error(...args: unknown[]): void { 42 | this.on ? this.logger.error(...args) : null; 43 | } 44 | 45 | public fatal(...args: unknown[]): void { 46 | this.on ? this.logger.fatal(...args) : null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/request-body-flattener.ts: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | const EMPTY = ""; 4 | 5 | export class RequestBodyFlattener { 6 | static flatten(requestBody: { [key: string]: any }) { 7 | const objBody = _.cloneDeep(requestBody); 8 | const flatPair: { [key: string]: any } = {}; // we're going to convert objBody to flatPair 9 | Object.keys(objBody).forEach(key => { 10 | const value = objBody[key]; 11 | if (Array.isArray(value)) { 12 | // scan for all sub-keys 13 | let allSubKeys: string[] = []; 14 | value.forEach(elem => { 15 | allSubKeys = _.union(allSubKeys, Object.keys(elem)); 16 | }); 17 | 18 | // now we have keys for elements. fill-in flatPair 19 | value.forEach(elem => { 20 | // for each element on the array 21 | allSubKeys.forEach(subKey => { 22 | const flatKey = `${key}.${subKey}`; 23 | const flatRawValue = elem[subKey] ? elem[subKey] : EMPTY; 24 | const prevFlatValue = flatPair[flatKey]; 25 | if (_.isUndefined(prevFlatValue)) { 26 | flatPair[flatKey] = flatRawValue; 27 | } else { 28 | flatPair[flatKey] = `${prevFlatValue},${flatRawValue}`; 29 | } 30 | }); 31 | }); 32 | } else { 33 | flatPair[key] = objBody[key]; 34 | } 35 | }); 36 | 37 | return Object.keys(flatPair) 38 | .sort() 39 | .map(key => `${key}=${flatPair[key]}`) 40 | .join("&"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/request-parameter-validator.ts: -------------------------------------------------------------------------------- 1 | import { Validations } from "./constants"; 2 | 3 | export class RequestParameterValidator { 4 | private constructor() {} 5 | 6 | static isValidTokenName(name: string): boolean { 7 | return Validations.TOKEN_NAME_REGEX.test(name); 8 | } 9 | 10 | static validTokenNamePattern(): string { 11 | return Validations.TOKEN_NAME_REGEX.source; 12 | } 13 | 14 | static isValidSymbol(symbol: string): boolean { 15 | return Validations.SYMBOL_NAME_REGEX.test(symbol); 16 | } 17 | 18 | static validTokenSymbolPattern(): string { 19 | return Validations.SYMBOL_NAME_REGEX.source; 20 | } 21 | 22 | static isValidInitialSupply(initialSupply: string): boolean { 23 | return Validations.NUMBER_FORMAT_REGEX.test(initialSupply); 24 | } 25 | 26 | static validTokenInitialSupplyPattern(): string { 27 | return Validations.NUMBER_FORMAT_REGEX.source; 28 | } 29 | 30 | static isValidWalletAddress(walletAddress: string): boolean { 31 | return Validations.WALLET_ADDRESS_REGEX.test(walletAddress); 32 | } 33 | 34 | static validWalletAddressPattern(): string { 35 | return Validations.WALLET_ADDRESS_REGEX.source; 36 | } 37 | 38 | static isValidBaseUri(baseUri: string): boolean { 39 | return Validations.BASE_URI_OR_EMPTY_REGEX.test(baseUri); 40 | } 41 | 42 | static validBaseUriPattern(): string { 43 | return Validations.BASE_URI_OR_EMPTY_REGEX.source; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/request.ts: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import { RequestParameterValidator } from "./request-parameter-validator"; 3 | 4 | export class AbstractTokenBurnTransactionRequest { 5 | constructor(readonly fromUserId?: string, readonly fromAddress?: string) { 6 | if (!fromUserId && !fromAddress) { 7 | throw new Error("fromAddress or fromUserId, one of them is required"); 8 | } 9 | } 10 | } 11 | 12 | export class AbstractTransactionRequest { 13 | constructor(readonly toAddress?: string, readonly toUserId?: string) { 14 | if (!toUserId && !toAddress) { 15 | throw new Error("toAddress or toUserId, one of them is required"); 16 | } 17 | } 18 | } 19 | 20 | export class IssueServiceTokenRequest { 21 | constructor( 22 | readonly serviceWalletAddress: string, 23 | readonly serviceWalletSecret: string, 24 | readonly name: string, 25 | readonly symbol: string, 26 | readonly initialSupply: string, 27 | readonly recipientWalletAddress: string, 28 | ) { 29 | if (!RequestParameterValidator.isValidWalletAddress(serviceWalletAddress)) { 30 | throw new Error( 31 | `Invalid serviceWalletAddress - valid pattern: ${RequestParameterValidator.validWalletAddressPattern()}`, 32 | ); 33 | } 34 | 35 | if (_.isEmpty(serviceWalletSecret)) { 36 | throw new Error("Empty serviceWalletSecret is not allowed"); 37 | } 38 | 39 | if (!RequestParameterValidator.isValidTokenName(name)) { 40 | throw new Error( 41 | `Invalid name of service token - valid pattern: ${RequestParameterValidator.validTokenNamePattern()}`, 42 | ); 43 | } 44 | 45 | if (!RequestParameterValidator.isValidSymbol(symbol)) { 46 | throw new Error( 47 | `Invalid symbol of service token - valid pattern: ${RequestParameterValidator.validTokenSymbolPattern()}`, 48 | ); 49 | } 50 | 51 | if (!RequestParameterValidator.isValidInitialSupply(initialSupply)) { 52 | throw new Error( 53 | `Invalid initialSupply of service token - valid pattern: ${RequestParameterValidator.validTokenInitialSupplyPattern()}`, 54 | ); 55 | } 56 | 57 | if (!RequestParameterValidator.isValidWalletAddress(recipientWalletAddress)) { 58 | throw new Error( 59 | `Invalid recipientWalletAddress of service token - valid pattern: ${RequestParameterValidator.validWalletAddressPattern()}`, 60 | ); 61 | } 62 | } 63 | } 64 | 65 | export class UpdateServiceTokenRequest { 66 | constructor( 67 | readonly ownerAddress: string, 68 | readonly ownerSecret: string, 69 | readonly name: string, 70 | readonly meta?: string, 71 | ) {} 72 | } 73 | 74 | export class BurnFromServiceTokenRequest extends AbstractTokenBurnTransactionRequest { 75 | constructor( 76 | readonly ownerAddress: string, 77 | readonly ownerSecret: string, 78 | readonly amount: string, 79 | fromUserId?: string, 80 | fromAddress?: string, 81 | ) { 82 | super(fromUserId, fromAddress); 83 | } 84 | } 85 | 86 | export class MintServiceTokenRequest extends AbstractTransactionRequest { 87 | constructor( 88 | readonly ownerAddress: string, 89 | readonly ownerSecret: string, 90 | readonly amount: string, 91 | toAddress?: string, 92 | toUserId?: string, 93 | ) { 94 | super(toAddress, toUserId); 95 | } 96 | } 97 | 98 | export class MemoRequest { 99 | constructor(readonly memo: string, readonly walletAddress: string, readonly walletSecret: string) {} 100 | } 101 | 102 | export class TransferBaseCoinRequest extends AbstractTransactionRequest { 103 | constructor(readonly walletSecret: string, readonly amount: string, toAddress?: string, toUserId?: string) { 104 | super(toAddress, toUserId); 105 | } 106 | } 107 | 108 | export class TransferServiceTokenRequest extends AbstractTransactionRequest { 109 | constructor(readonly walletSecret: string, readonly amount: string, toAddress?: string, toUserId?: string) { 110 | super(toAddress, toUserId); 111 | } 112 | } 113 | 114 | export class TransferServiceTokenProxyRequest extends AbstractTransactionRequest { 115 | constructor( 116 | readonly ownerAddress: string, 117 | readonly ownerSecret: string, 118 | readonly amount: string, 119 | toAddress?: string, 120 | toUserId?: string, 121 | ) { 122 | super(toAddress, toUserId); 123 | } 124 | } 125 | 126 | export class TransferFungibleTokenRequest extends AbstractTransactionRequest { 127 | constructor(readonly walletSecret: string, readonly amount: string, toAddress?: string, toUserId?: string) { 128 | super(toAddress, toUserId); 129 | } 130 | } 131 | 132 | export class TransferFungibleTokenProxyRequest extends AbstractTransactionRequest { 133 | constructor( 134 | readonly ownerAddress: string, 135 | readonly ownerSecret: string, 136 | readonly amount: string, 137 | toAddress?: string, 138 | toUserId?: string, 139 | ) { 140 | super(toAddress, toUserId); 141 | } 142 | } 143 | 144 | export class TransferNonFungibleTokenRequest extends AbstractTransactionRequest { 145 | constructor(readonly walletSecret: string, toAddress?: string, toUserId?: string) { 146 | super(toAddress, toUserId); 147 | } 148 | } 149 | 150 | export class TransferNonFungibleTokenProxyRequest extends AbstractTransactionRequest { 151 | constructor(readonly ownerAddress: string, readonly ownerSecret: string, toAddress?: string, toUserId?: string) { 152 | super(toAddress, toUserId); 153 | } 154 | } 155 | 156 | export class BatchTransferNonFungibleTokenRequest extends AbstractTransactionRequest { 157 | constructor( 158 | readonly walletSecret: string, 159 | readonly transferList: Array, 160 | toAddress?: string, 161 | toUserId?: string, 162 | ) { 163 | super(toAddress, toUserId); 164 | } 165 | } 166 | 167 | export class BatchTransferNonFungibleTokenProxyRequest extends AbstractTransactionRequest { 168 | constructor( 169 | readonly ownerAddress: string, 170 | readonly ownerSecret: string, 171 | readonly transferList: Array, 172 | toAddress?: string, 173 | toUserId?: string, 174 | ) { 175 | super(toAddress, toUserId); 176 | } 177 | } 178 | 179 | export class MultiFungibleTokenMediaResourcesUpdateRequest { 180 | constructor(readonly updateList: Array) {} 181 | } 182 | 183 | export class MultiNonFungibleTokenMediaResourcesUpdateRequest { 184 | constructor(readonly updateList: Array) {} 185 | } 186 | 187 | export class MultiNonFungibleTokenTypeMediaResourcesUpdateRequest { 188 | constructor(readonly updateList: Array) {} 189 | } 190 | 191 | export class TokenType { 192 | private constructor(readonly tokenType: string) {} 193 | 194 | static readonly tokenTypeFormat = new RegExp("\\w{8}"); 195 | static readonly tokenTypeLength = 8; 196 | 197 | static from(value: string): TokenType { 198 | if (value.length != TokenType.tokenTypeLength) { 199 | throw new Error(`Invalid tokenType: length of token-type has to be ${TokenType.tokenTypeLength}`); 200 | } 201 | if (!TokenType.tokenTypeFormat.test(value)) { 202 | throw new Error(`Invalid tokenType: invalid format of tokenId, valid format is ${TokenType.tokenTypeFormat}`); 203 | } 204 | return new TokenType(value); 205 | } 206 | 207 | static fromMulti(values: Array): Array { 208 | return _.map(values, value => TokenType.from(value)); 209 | } 210 | } 211 | 212 | export class TokenId { 213 | private constructor(readonly tokenId: string) {} 214 | 215 | static readonly tokenIdFormat = new RegExp("\\w{8}\\w{8}"); 216 | static readonly tokenIdLength = 16; 217 | 218 | static from(value: string): TokenId { 219 | if (value.length != TokenId.tokenIdLength) { 220 | throw new Error(`Invalid tokenId: length of token-id has to be ${TokenId.tokenIdLength}`); 221 | } 222 | if (!TokenId.tokenIdFormat.test(value)) { 223 | throw new Error(`Invalid tokenId: invalid format of tokenId, valid format is ${TokenId.tokenIdFormat}`); 224 | } 225 | return new TokenId(value); 226 | } 227 | 228 | static fromMulti(values: Array): Array { 229 | return _.map(values, value => TokenId.from(value)); 230 | } 231 | 232 | toTokenTypeAndIndex(): TokenTypeAndIndex { 233 | const tokenType = this.tokenId.substring(0, 8); 234 | const tokenIndex = this.tokenId.substring(8, 16); 235 | return new TokenTypeAndIndex(tokenType, tokenIndex); 236 | } 237 | } 238 | 239 | export class TokenTypeAndIndex { 240 | constructor(readonly tokenType: string, readonly tokenIndex: string) {} 241 | 242 | static from(value: string): TokenTypeAndIndex { 243 | if (value.length != TokenId.tokenIdLength) { 244 | throw new Error("Invalid TokenTypeAndIndex: length has to be 16"); 245 | } 246 | if (!TokenId.tokenIdFormat.test(value)) { 247 | throw new Error(`Invalid tokenId: invalid format of TokenTypeAndIndex, valid format is ${TokenId.tokenIdFormat}`); 248 | } 249 | const tokenType = value.substring(0, 8); 250 | const tokenIndex = value.substring(8, 16); 251 | return new TokenTypeAndIndex(tokenType, tokenIndex); 252 | } 253 | 254 | static fromMulti(values: Array): Array { 255 | return _.map(values, value => TokenTypeAndIndex.from(value)); 256 | } 257 | } 258 | 259 | export class CreateItemTokenContractRequest { 260 | constructor( 261 | readonly name: string, 262 | readonly serviceWalletAddress: string, 263 | readonly serviceWalletSecret: string, 264 | readonly baseImgUri: string, 265 | ) {} 266 | } 267 | 268 | export class FungibleTokenCreateUpdateRequest { 269 | constructor( 270 | readonly ownerAddress: string, 271 | readonly ownerSecret: string, 272 | readonly name: string, 273 | readonly meta?: string, 274 | ) {} 275 | } 276 | 277 | export class FungibleTokenMintRequest extends AbstractTransactionRequest { 278 | constructor( 279 | readonly ownerAddress: string, 280 | readonly ownerSecret: string, 281 | readonly amount: string, 282 | toAddress?: string, 283 | toUserId?: string, 284 | ) { 285 | super(toAddress, toUserId); 286 | } 287 | } 288 | 289 | export class FungibleTokenBurnRequest extends AbstractTokenBurnTransactionRequest { 290 | constructor( 291 | readonly ownerAddress: string, 292 | readonly ownerSecret: string, 293 | readonly amount: string, 294 | readonly fromUserId?: string, 295 | readonly fromAddress?: string, 296 | ) { 297 | super(fromUserId, fromAddress); 298 | } 299 | } 300 | 301 | export class NonFungibleTokenCreateUpdateRequest { 302 | constructor( 303 | readonly ownerAddress: string, 304 | readonly ownerSecret: string, 305 | readonly name: string, 306 | readonly meta?: string, 307 | ) {} 308 | } 309 | 310 | export class NonFungibleTokenMintRequest extends AbstractTransactionRequest { 311 | constructor( 312 | readonly ownerAddress: string, 313 | readonly ownerSecret: string, 314 | readonly name: string, 315 | readonly meta?: string, 316 | toAddress?: string, 317 | toUserId?: string, 318 | ) { 319 | super(toAddress, toUserId); 320 | } 321 | } 322 | 323 | export class NonFungibleTokenMultiMintRequest extends AbstractTransactionRequest { 324 | constructor( 325 | readonly ownerAddress: string, 326 | readonly ownerSecret: string, 327 | readonly mintList: Array, 328 | toAddress?: string, 329 | toUserId?: string, 330 | ) { 331 | super(toAddress, toUserId); 332 | } 333 | } 334 | 335 | export class MultiMintNonFungible { 336 | constructor(readonly tokenType: string, readonly name: string, readonly meta?: string) {} 337 | } 338 | 339 | export class NonFungibleTokenMultiMintMultiReceiversRequest { 340 | constructor( 341 | readonly ownerAddress: string, 342 | readonly ownerSecret: string, 343 | readonly mintList: Array, 344 | ) {} 345 | } 346 | 347 | export class MultiMintNonFungibleWithReceiver { 348 | constructor( 349 | readonly tokenType: string, 350 | readonly name: string, 351 | readonly meta?: string, 352 | readonly toAddress?: string, 353 | readonly toUserId?: string, 354 | ) { 355 | if (!toUserId && !toAddress) { 356 | throw new Error("toAddress or toUserId, one of them is required"); 357 | } 358 | } 359 | } 360 | 361 | export class NonFungibleTokenBurnRequest extends AbstractTokenBurnTransactionRequest { 362 | constructor( 363 | readonly ownerAddress: string, 364 | readonly ownerSecret: string, 365 | readonly fromUserId?: string, 366 | readonly fromAddress?: string, 367 | ) { 368 | super(fromUserId, fromAddress); 369 | } 370 | } 371 | 372 | export class NonFungibleTokenAttachRequest { 373 | constructor( 374 | readonly parentTokenId: string, 375 | readonly serviceWalletAddress: string, 376 | readonly serviceWalletSecret: string, 377 | readonly tokenHolderAddress?: string, 378 | readonly tokenHolderUserId?: string, 379 | ) { 380 | if (!tokenHolderAddress && !tokenHolderUserId) { 381 | throw new Error("tokenHolderAddress or tokenHolderUserId, one of them is required"); 382 | } 383 | } 384 | } 385 | 386 | export class NonFungibleTokenDetachRequest { 387 | constructor( 388 | readonly serviceWalletAddress: string, 389 | readonly serviceWalletSecret: string, 390 | readonly tokenHolderAddress?: string, 391 | readonly tokenHolderUserId?: string, 392 | ) { 393 | if (!tokenHolderAddress && !tokenHolderUserId) { 394 | throw new Error("tokenHolderAddress or tokenHolderUserId, one of them is required"); 395 | } 396 | } 397 | } 398 | 399 | export class IssueTransferSessionTokenRequest extends AbstractTransactionRequest { 400 | constructor(readonly amount: string, readonly landingUri: string, toAddress?: string, toUserId?: string) { 401 | super(toAddress, toUserId); 402 | if (Number(amount) <= 0) { 403 | throw new Error("Invalid amount - $amount is less than zero "); 404 | } 405 | } 406 | } 407 | 408 | export class UserProxyRequest { 409 | constructor(readonly ownerAddress: string, readonly landingUri: string) {} 410 | } 411 | 412 | export enum OrderBy { 413 | ASC = "asc", 414 | DESC = "desc", 415 | } 416 | 417 | export enum RequestType { 418 | REDIRECT_URI = "redirect_uri", 419 | AOA = "aoa", 420 | } 421 | 422 | export class PageRequest { 423 | constructor(readonly page: number = 0, readonly limit: number = 10, readonly orderBy: OrderBy = OrderBy.DESC) {} 424 | } 425 | 426 | export class CursorPageRequest { 427 | constructor(readonly pageToken: string = "", readonly limit: number = 10, readonly orderBy: OrderBy = OrderBy.ASC) {} 428 | } 429 | 430 | export const DEFAULT_PAGE_REQUEST: PageRequest = new PageRequest(0, 10, OrderBy.DESC); 431 | 432 | /* 433 | This is for query-parameters to search transactions of a wallet and a user. 434 | * after and before is time-stampe values 435 | * available msgType can be found at constants.TransactionMsgTypes 436 | */ 437 | export class OptionalTransactionSearchParameters { 438 | constructor(readonly after?: number, readonly before?: number, readonly msgType?: string) {} 439 | } 440 | -------------------------------------------------------------------------------- /lib/response.ts: -------------------------------------------------------------------------------- 1 | export class GenericResponse { 2 | constructor( 3 | readonly responseTime: number, 4 | readonly statusCode: number, 5 | readonly statusMessage: string, 6 | readonly responseData: T, 7 | ) {} 8 | } 9 | 10 | export class ServiceDetail { 11 | constructor( 12 | readonly serviceId: string, 13 | readonly name: string, 14 | readonly category: string, 15 | readonly description?: string, 16 | ) {} 17 | } 18 | 19 | export class UserRequestStatus { 20 | constructor(readonly status: RequestSessionTokenStatus) {} 21 | } 22 | 23 | export enum RequestSessionTokenStatus { 24 | Authorized, 25 | Unauthorized, 26 | } 27 | 28 | export class IssuedServiceToken { 29 | constructor( 30 | readonly contractId: string, 31 | readonly ownerAddress?: string, 32 | readonly createdAt?: number, 33 | readonly serviceId?: string, 34 | readonly decimals?: number, 35 | readonly name?: string, 36 | readonly symbol?: string, 37 | readonly meta?: string, 38 | readonly imgUri?: string, 39 | ) {} 40 | } 41 | 42 | export class ServiceToken { 43 | constructor( 44 | readonly contractId: string, 45 | readonly ownerAddress: string, 46 | readonly createdAt: number, 47 | readonly serviceId: string, 48 | readonly decimals: number, 49 | readonly name: string, 50 | readonly symbol: string, 51 | readonly meta: string, 52 | readonly imgUri: string, 53 | readonly totalSupply: string, 54 | readonly totalMint: string, 55 | readonly totalBurn: string, 56 | ) {} 57 | } 58 | 59 | export class ServiceTokenHolder { 60 | constructor(readonly address: string, readonly amount: string, readonly userId?: string) {} 61 | } 62 | 63 | export class TransactionResponse { 64 | constructor(readonly txHash: string) {} 65 | } 66 | 67 | export class TokenMediaResourceUpdateResponse { 68 | constructor(readonly requestId: string) {} 69 | } 70 | 71 | export class FungibleTokenMediaResourceUpdateStatusResponse { 72 | constructor( 73 | readonly tokenType: string, 74 | readonly status: TokenMediaResourceUpdateStatus, 75 | readonly url?: string, 76 | readonly detailStatus?: string, 77 | ) {} 78 | } 79 | 80 | export class NonFungibleTokenMediaResourceUpdateStatusResponse { 81 | constructor( 82 | readonly tokenType: string, 83 | readonly tokenIndex: string, 84 | readonly status: TokenMediaResourceUpdateStatus, 85 | readonly url?: string, 86 | readonly detailStatus?: string, 87 | ) {} 88 | } 89 | 90 | export enum TokenMediaResourceUpdateStatus { 91 | COMPLETED, 92 | INCOMPLETE, 93 | ERROR, 94 | NONE, 95 | } 96 | 97 | export class TxHashResponse { 98 | constructor(readonly txHash: string) {} 99 | } 100 | 101 | export class TxResultResponse { 102 | constructor( 103 | readonly height: number, 104 | readonly txhash: string, 105 | readonly code: number, 106 | readonly index: number, 107 | readonly gasUsed: number, 108 | readonly tx: TypedValueResponse, 109 | readonly timestamp: number, 110 | readonly codespace?: string | null, 111 | readonly data?: string | null, 112 | readonly logs?: Array | null, 113 | readonly info?: string | null, 114 | readonly gasWanted?: number | null, 115 | ) {} 116 | } 117 | 118 | export class LogResponse { 119 | constructor(readonly msgIndex: number, readonly log: string, readonly events?: Array) {} 120 | } 121 | 122 | export class EventResponse { 123 | constructor(readonly type: string, readonly attributes: Array>) {} 124 | } 125 | 126 | export class KeyValueResponse { 127 | constructor(readonly key: string, readonly value: T) {} 128 | } 129 | 130 | export class TypedValueResponse { 131 | constructor(readonly type: string, readonly value: T) {} 132 | } 133 | 134 | export class StdTxResponse { 135 | constructor( 136 | readonly msg: Array>, 137 | readonly fee: FeeResponse, 138 | readonly memo: string, 139 | readonly signatures: Array, 140 | ) {} 141 | } 142 | 143 | export class FeeResponse { 144 | constructor(readonly gas: number, readonly amount: Array) {} 145 | } 146 | 147 | export class SignatureResponse { 148 | constructor(readonly signature: string, readonly pubKey: TypedValueResponse) {} 149 | } 150 | 151 | export class BaseCoinBalance { 152 | constructor(readonly symbol: string, readonly decimals: number, readonly amount: string) {} 153 | } 154 | 155 | export class CoinResponse { 156 | constructor(readonly denom: string, readonly amount: number) {} 157 | 158 | toString(): string { 159 | return this.amount.toString() + this.denom; 160 | } 161 | } 162 | 163 | export class Memo { 164 | constructor(readonly memo: string) {} 165 | } 166 | 167 | export class WalletResponse { 168 | constructor(readonly name: string, readonly walletAddress: string, readonly createdAt: number) {} 169 | } 170 | 171 | export class ServiceTokenBalance { 172 | constructor( 173 | readonly contractId: string, 174 | readonly name: string, 175 | readonly symbol: string, 176 | readonly imgUri: string, 177 | readonly decimals: number, 178 | readonly amount: string, 179 | ) {} 180 | } 181 | 182 | export class FungibleBalance { 183 | constructor(readonly tokenType: string, readonly name: string, readonly meta: string, readonly amount: string) {} 184 | } 185 | 186 | export class NonFungibleBalance { 187 | constructor( 188 | readonly tokenType: string, 189 | readonly name: string, 190 | readonly meta: string, 191 | readonly numberOfIndex: string, 192 | ) {} 193 | } 194 | 195 | export class NonFungibleTokenOfType { 196 | constructor(readonly tokenIndex: string, readonly name: string, readonly meta: string) {} 197 | } 198 | 199 | export class CursorPaginatedNonFungibleBalanceWithTypes { 200 | constructor( 201 | readonly list: Array, 202 | readonly prePageToken?: string, 203 | readonly nextPageToken?: string, 204 | ) {} 205 | } 206 | 207 | export class NonFungibleBalanceWithType { 208 | constructor(readonly type: NonFungibleType, readonly token: NonFungibleToken) {} 209 | } 210 | 211 | export class NonFungibleType { 212 | constructor( 213 | readonly tokenType: string, 214 | readonly name: string, 215 | readonly meta: string, 216 | readonly totalSupply: string, 217 | readonly totalMint: string, 218 | readonly totalBurn: string, 219 | ) {} 220 | } 221 | 222 | export class NonFungibleToken { 223 | constructor( 224 | readonly name: string, 225 | readonly tokenId: string, 226 | readonly meta: string, 227 | readonly createdAt: number, 228 | readonly burnedAt?: number, 229 | ) {} 230 | } 231 | 232 | export class TokenIndex { 233 | constructor(readonly tokenIndex: string, readonly name: string, readonly meta: string) {} 234 | } 235 | 236 | export class ItemToken { 237 | constructor( 238 | readonly contractId: string, 239 | readonly baseImgUri: string, 240 | readonly ownerAddress: string, 241 | readonly serviceId: string, 242 | readonly createdAt: number, 243 | ) {} 244 | } 245 | 246 | export class CreatedItemToken { 247 | constructor( 248 | readonly contractId: string, 249 | readonly baseImgUri?: string, 250 | readonly ownerAddress?: string, 251 | readonly serviceId?: string, 252 | readonly createdAt?: number, 253 | ) {} 254 | } 255 | 256 | export class FungibleToken { 257 | constructor( 258 | readonly name: string, 259 | readonly meta: string, 260 | readonly tokenType: string, 261 | readonly totalSupply: string, 262 | readonly totalMint: string, 263 | readonly totalBurn: string, 264 | readonly createdAt: number, 265 | ) {} 266 | } 267 | 268 | export class FungibleTokenHolder { 269 | constructor(readonly walletAddress: string, readonly amount: string, readonly userId?: string) {} 270 | } 271 | 272 | export class ItemTokenType { 273 | constructor( 274 | readonly name: string, 275 | readonly meta: string, 276 | readonly tokenType: string, 277 | readonly totalSupply: string, 278 | readonly totalMint: string, 279 | readonly totalBurn: string, 280 | readonly createdAt: number, 281 | ) {} 282 | } 283 | 284 | export class NonFungibleTokenType { 285 | constructor( 286 | readonly name: string, 287 | readonly meta: string, 288 | readonly tokenType: string, 289 | readonly totalSupply: number, 290 | readonly totalMint: number, 291 | readonly totalBurn: number, 292 | readonly createdAt: number, 293 | readonly token: Array, 294 | ) {} 295 | } 296 | 297 | export class NonFungibleIndex { 298 | constructor( 299 | readonly tokenIndex: string, 300 | readonly name: string, 301 | readonly meta: string, 302 | readonly createdAt: number, 303 | readonly burnedAt?: number, 304 | ) {} 305 | } 306 | 307 | export class NonFungibleId { 308 | constructor( 309 | readonly tokenId: string, 310 | readonly name: string, 311 | readonly meta: string, 312 | readonly createdAt: number, 313 | readonly burnedAt?: number, 314 | ) {} 315 | } 316 | 317 | export class NonFungibleTokenTypeHolder { 318 | constructor(readonly walletAddress: string, readonly numberOfIndex: string, readonly userId?: string) {} 319 | } 320 | 321 | export class NonFungibleTokenTypeHolderList { 322 | constructor( 323 | readonly list: Array, 324 | readonly prePageToken: string, 325 | readonly nextPageToken: string, 326 | ) {} 327 | } 328 | 329 | export class NonFungibleTokenHolder { 330 | constructor( 331 | readonly tokenId: string, 332 | readonly walletAddress: string, 333 | readonly amount: string, 334 | readonly userId?: string, 335 | readonly meta?: string, 336 | ) {} 337 | } 338 | 339 | export class UserIdAddress { 340 | constructor(readonly userId: string, readonly walletAddress: string) {} 341 | } 342 | 343 | export class SessionTokenResponse { 344 | constructor(readonly requestSessionToken: string, readonly redirectUri: string) {} 345 | } 346 | 347 | export class RequestSessionStatus { 348 | constructor(readonly status: RequestSessionTokenStatus) {} 349 | } 350 | 351 | export class ProxyApprovedResponse { 352 | constructor(readonly isApproved: boolean) {} 353 | } 354 | 355 | export class IssueProxyResponse { 356 | constructor(readonly requestSessionToken: string, readonly redirectUri?: string) {} 357 | } 358 | 359 | export class TxMessageWithDetailResponse { 360 | constructor(readonly msgIndex: number, readonly requestType: string, readonly details: any) {} 361 | } 362 | 363 | export class TxMessageListResponse { 364 | constructor( 365 | readonly messages: Array, 366 | readonly prePageToken: string = "", 367 | readonly nextPageToken: string = "", 368 | ) {} 369 | } 370 | -------------------------------------------------------------------------------- /lib/signature-generator.ts: -------------------------------------------------------------------------------- 1 | import { LoggerFactory } from "./logger-factory"; 2 | import CryptoJS from "crypto-js"; 3 | import _ from "lodash"; 4 | import { RequestBodyFlattener } from "./request-body-flattener"; 5 | 6 | /** 7 | reference site: https://jokecamp.wordpress.com/2012/10/21/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/#js 8 | */ 9 | export class SignatureGenerator { 10 | static signature( 11 | apiSecret: string, 12 | method: string, 13 | path: string, 14 | timestamp: number, 15 | nonce: string, 16 | parameters: object = {}, // query string 17 | body: object = {}, 18 | ): string { 19 | let signTarget = SignatureGenerator.createSignTarget(method, path, timestamp, nonce, parameters, body); 20 | let hasQueryParam = _.size(parameters) > 0; 21 | if (parameters && hasQueryParam) { 22 | signTarget += RequestBodyFlattener.flatten(parameters); 23 | } 24 | if (body && _.size(body) > 0) { 25 | if (hasQueryParam) { 26 | signTarget += "&" + RequestBodyFlattener.flatten(body); 27 | } else { 28 | signTarget += RequestBodyFlattener.flatten(body); 29 | } 30 | } 31 | let hash = CryptoJS.HmacSHA512(signTarget, apiSecret); 32 | return CryptoJS.enc.Base64.stringify(hash); 33 | } 34 | 35 | private static createSignTarget( 36 | method: string, 37 | path: string, 38 | timestamp: number, 39 | nonce: string, 40 | parameters: object = {}, // query string 41 | body: object = {}, 42 | ) { 43 | let signTarget = `${nonce}${timestamp}${method}${path}`; 44 | if ((parameters && _.size(parameters) > 0) || (body && _.size(body) > 0)) { 45 | if (signTarget.indexOf("?") < 0) { 46 | signTarget += "?"; 47 | } else { 48 | signTarget += "&"; 49 | } 50 | } 51 | return signTarget; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/string-util.ts: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import { DenomAmount, TokenIdAmount } from "./commonTypes"; 3 | 4 | export class StringUtil { 5 | private constructor() {} 6 | 7 | public static parseAmount(amountWithDenom: string): DenomAmount { 8 | const regex = /(\d+):?(\w+)/; 9 | const match = amountWithDenom.match(regex); 10 | 11 | if (match) { 12 | return DenomAmount.create({ 13 | amount: match[1], 14 | denom: match[2], 15 | }); 16 | } else { 17 | throw new Error(`Invalid amountWithDenom - ${amountWithDenom}`); 18 | } 19 | } 20 | 21 | public static parseTokenIdAmount(amountWithTokenId: string): TokenIdAmount { 22 | const regex = /(\d+):?(\d+)/; 23 | const match = amountWithTokenId.match(regex); 24 | 25 | if (match) { 26 | return TokenIdAmount.create({ 27 | amount: match[1], 28 | tokenId: match[2], 29 | }); 30 | } else { 31 | throw new Error(`Invalid amountWithTokenId - ${amountWithTokenId}`); 32 | } 33 | } 34 | 35 | public static isBlank(value: string): boolean { 36 | return (_.isEmpty(value) && !_.isNumber(value)) || _.isNaN(value); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/token-util.ts: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export class TokenUtil { 4 | private static FUNGIBLE_TOKEN_INDEX = "00000000"; 5 | 6 | private constructor() {} 7 | 8 | static tokenIndexFrom(tokenId: string): string { 9 | let tokenIndex = ""; 10 | if (tokenId && tokenId.length == 16) { 11 | tokenIndex = tokenId.substring(8, 16); 12 | } 13 | return tokenIndex; 14 | } 15 | 16 | static tokenTypeFrom(tokenId: string): string { 17 | let tokenType = ""; 18 | if (tokenId && tokenId.length >= 8) { 19 | tokenType = tokenId.substring(0, 8); 20 | } 21 | return tokenType; 22 | } 23 | 24 | static isFungible(tokenType: string): boolean { 25 | return tokenType.startsWith("0"); 26 | } 27 | 28 | static tokenTypes(tokenIds: Array): Array { 29 | return _.map(tokenIds, it => { 30 | return TokenUtil.tokenTypeFrom(it.toString()); 31 | }); 32 | } 33 | 34 | static tokenIndices(tokenIds: Array): Array { 35 | return _.map(tokenIds, it => { 36 | return TokenUtil.tokenIndexFrom(it.toString()); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/transaction-messages.ts: -------------------------------------------------------------------------------- 1 | import { TxResultCode } from "./tx-result-codes"; 2 | 3 | export enum MessageType { 4 | // SERVICE TOKEN MESSAGE TYPES 5 | SERVICE_TOKEN_ISSUE = "token/MsgIssue", 6 | SERVICE_TOKEN_MODIFY = "token/MsgModify", 7 | SERVICE_TOKEN_MINT = "token/MsgMint", 8 | SERVICE_TOKEN_BURN = "token/MsgBurn", 9 | SERVICE_TOKEN_BURN_FROM = "token/MsgBurnFrom", 10 | SERVICE_TOKEN_TRANSFER = "token/MsgTransfer", 11 | SERVICE_TOKEN_TRANSFER_FROM = "token/MsgTransferFrom", 12 | SERVICE_TOKEN_PROXY_APPROVED = "token/MsgApprove", 13 | 14 | // ITEM TOKEN MESSAGE TYPES 15 | ITEM_TOKEN_CREATE = "collection/MsgCreate", 16 | ITEM_TOKEN_MODIFY = "collection/MsgModify", 17 | ITEM_TOKEN_APPROVE = "collection/MsgApprove", 18 | ITEM_TOKEN_DISAPPROVE = "collection/MsgDisapprove", 19 | ITEM_TOKEN_GRANT_PERMISSION = "collection/MsgGrantPermission", 20 | ITEM_TOKEN_REVOKE_PERMISSION = "collection/MsgRevokePermission", 21 | ITEM_TOKEN_ISSUE_FT = "collection/MsgIssueFT", 22 | ITEM_TOKEN_MINT_FT = "collection/MsgMintFT", 23 | ITEM_TOKEN_BURN_FT = "collection/MsgBurnFT", 24 | ITEM_TOKEN_BURN_FROM_FT = "collection/MsgBurnFromFT", 25 | ITEM_TOKEN_TRANSFER_FT = "collection/MsgTransferFT", 26 | ITEM_TOKEN_TRANSFER_FROM_FT = "collection/MsgTransferFTFrom", 27 | ITEM_TOKEN_ISSUE_NFT = "collection/MsgIssueNFT", 28 | ITEM_TOKEN_MINT_NFT = "collection/MsgMintNFT", 29 | ITEM_TOKEN_BURN_NFT = "collection/MsgBurnNFT", 30 | ITEM_TOKEN_BURN_FROM_NFT = "collection/MsgBurnNFTFrom", 31 | ITEM_TOKEN_TRANSFER_NFT = "collection/MsgTransferNFT", 32 | ITEM_TOKEN_TRANSFER_FROM_NFT = "collection/MsgTransferNFTFrom", 33 | ITEM_TOKEN_ATTACH = "collection/MsgAttach", 34 | ITEM_TOKEN_ATTACH_FROM = "collection/MsgAttachFrom", 35 | ITEM_TOKEN_DETACH = "collection/MsgDetach", 36 | ITEM_TOKEN_DETACH_FROM = "collection/MsgDetachFrom", 37 | 38 | //BASE COIN - CASHEW ONLY 39 | COIN_SEND = "coin/MsgSend", 40 | 41 | // Account 42 | ACCOUNT_MSG_EMPTY = "account/MsgEmpty", 43 | } 44 | 45 | // data classes(value objects) from tx-results 46 | 47 | export abstract class TxResultMessage { 48 | constructor( 49 | readonly txResultCode: TxResultCode, 50 | readonly height: number, 51 | readonly txHash: string, 52 | readonly from: string, 53 | readonly proxy?: string, // transaction come from proxy wallet 54 | ) {} 55 | 56 | isProxyTransaction(): boolean { 57 | return !!this.proxy; 58 | } 59 | } 60 | 61 | export class IssuedServiceTokenMessage { 62 | constructor( 63 | readonly contractId: string, 64 | readonly name: string, 65 | readonly symbol: string, 66 | readonly meta: string, 67 | readonly imUri: string, 68 | readonly decimal: number, 69 | ) {} 70 | } 71 | 72 | export class CreatedItemTokenMessage { 73 | constructor( 74 | readonly contractId: string, 75 | readonly owner: string, 76 | readonly name: string, 77 | readonly meta: string, 78 | readonly baseImgUri: string, 79 | ) {} 80 | } 81 | 82 | export class FungibleTokenMessage { 83 | constructor(readonly contractId: string, readonly tokenType: string) {} 84 | } 85 | 86 | export class IssuedFungibleTokenMessage extends FungibleTokenMessage { 87 | constructor( 88 | contractId: string, 89 | tokenType: string, 90 | readonly name: string, 91 | readonly meta: string, 92 | readonly decimal: number, 93 | ) { 94 | super(contractId, tokenType); 95 | } 96 | } 97 | 98 | export class MintedFungibleTokenMessage extends FungibleTokenMessage { 99 | constructor(contractId: string, tokenType: string, readonly amount: string) { 100 | super(contractId, tokenType); 101 | } 102 | } 103 | 104 | export class BurnedFungibleTokenMessage extends FungibleTokenMessage { 105 | constructor(contractId: string, tokenType: string, readonly amount: string) { 106 | super(contractId, tokenType); 107 | } 108 | } 109 | 110 | export class TransferredFungibleTokenAmountMessage extends FungibleTokenMessage { 111 | constructor(contractId: string, tokenType: string, readonly amount: string) { 112 | super(contractId, tokenType); 113 | } 114 | } 115 | 116 | export class NonFungibleTokenMessage { 117 | constructor(readonly contractId: string, readonly tokenType: string, readonly tokenIndex?: string) {} 118 | } 119 | 120 | export class BaseCoinAmountMessage { 121 | constructor(readonly contractId: string, readonly amount: string) {} 122 | } 123 | 124 | export class IssuedNonFungibleTokenMessage extends NonFungibleTokenMessage { 125 | constructor(readonly contractId: string, readonly tokenType: string, readonly name: string, readonly meta: string) { 126 | super(contractId, tokenType); 127 | } 128 | } 129 | 130 | export class MintedNonFungibleTokenMessage extends NonFungibleTokenMessage { 131 | constructor( 132 | readonly from: string, 133 | readonly sender: string, 134 | readonly to: string, 135 | readonly contractId: string, 136 | readonly tokenType: string, 137 | readonly tokenIndex: string, 138 | readonly name: string, 139 | readonly meta: string, 140 | ) { 141 | super(contractId, tokenType, tokenIndex); 142 | } 143 | } 144 | 145 | export class TransferredNonFungibleTokenMessage extends NonFungibleTokenMessage { 146 | constructor(readonly contractId: string, readonly tokenType: string, readonly tokenIndex: string) { 147 | super(contractId, tokenType, tokenIndex); 148 | } 149 | } 150 | 151 | export class TokenChangeMessage { 152 | constructor(readonly field: string, readonly value: string) {} 153 | } 154 | 155 | export class ServiceTokenIssueMessage extends TxResultMessage { 156 | constructor( 157 | txResultCode: TxResultCode, 158 | height: number, 159 | txHash: string, 160 | from: string, 161 | readonly owner: string, 162 | readonly to: string, // receiver 163 | readonly issuedServiceToken: IssuedServiceTokenMessage, 164 | readonly amount: string, 165 | ) { 166 | super(txResultCode, height, txHash, from); 167 | } 168 | } 169 | 170 | export class ServiceTokenModifyMessage extends TxResultMessage { 171 | constructor( 172 | txResultCode: TxResultCode, 173 | height: number, 174 | txHash: string, 175 | sender: string, // sender 176 | readonly owner: string, 177 | readonly contractId: string, 178 | readonly changes: Array, 179 | ) { 180 | super(txResultCode, height, txHash, sender); 181 | } 182 | } 183 | 184 | export class ServiceTokenMintMessage extends TxResultMessage { 185 | constructor( 186 | txResultCode: TxResultCode, 187 | height: number, 188 | txHash: string, 189 | from: string, 190 | readonly owner: string, // from 191 | readonly to: string, // receiver 192 | readonly contractId: string, 193 | readonly amount: string, 194 | ) { 195 | super(txResultCode, height, txHash, from); 196 | } 197 | } 198 | 199 | export class ServiceTokenBurnMessage extends TxResultMessage { 200 | constructor( 201 | txResultCode: TxResultCode, 202 | height: number, 203 | txHash: string, 204 | from: string, 205 | readonly owner: string, 206 | readonly contractId: string, 207 | readonly amount: string, 208 | ) { 209 | super(txResultCode, height, txHash, from); 210 | } 211 | } 212 | 213 | export class ServiceTokenBurnFromMessage extends TxResultMessage { 214 | constructor( 215 | txResultCode: TxResultCode, 216 | height: number, 217 | txHash: string, 218 | from: string, 219 | readonly proxy: string, 220 | readonly contractId: string, 221 | readonly amount: string, 222 | ) { 223 | super(txResultCode, height, txHash, from); 224 | } 225 | } 226 | 227 | export class ServiceTokenGrantPermissionMessage extends TxResultMessage { 228 | constructor( 229 | txResultCode: TxResultCode, 230 | height: number, 231 | txHash: string, 232 | from: string, 233 | readonly owner: string, // from 234 | readonly contractId: string, 235 | readonly to: string, 236 | readonly permission: string, 237 | ) { 238 | super(txResultCode, height, txHash, from); 239 | } 240 | } 241 | 242 | export class ServiceTokenRevokePermissionMessage extends TxResultMessage { 243 | constructor( 244 | txResultCode: TxResultCode, 245 | height: number, 246 | txHash: string, 247 | from: string, 248 | readonly owner: string, // from 249 | readonly contractId: string, 250 | readonly permission: string, 251 | ) { 252 | super(txResultCode, height, txHash, from); 253 | } 254 | } 255 | 256 | export class ServiceTokenTransferMessage extends TxResultMessage { 257 | constructor( 258 | txResultCode: TxResultCode, 259 | height: number, 260 | txHash: string, 261 | from: string, 262 | readonly owner: string, // from 263 | readonly contractId: string, 264 | readonly to: string, 265 | readonly amount: string, 266 | ) { 267 | super(txResultCode, height, txHash, from); 268 | } 269 | } 270 | 271 | export class ServiceTokenTransferFromMessage extends TxResultMessage { 272 | constructor( 273 | txResultCode: TxResultCode, 274 | height: number, 275 | txHash: string, 276 | from: string, 277 | proxy: string, 278 | readonly owner: string, // from 279 | readonly contractId: string, 280 | readonly to: string, 281 | readonly amount: string, 282 | ) { 283 | super(txResultCode, height, txHash, from, proxy); 284 | } 285 | } 286 | 287 | export class ServiceTokenApprovedMessage extends TxResultMessage { 288 | constructor( 289 | txResultCode: TxResultCode, 290 | height: number, 291 | txHash: string, 292 | readonly sender: string, 293 | proxy: string, 294 | readonly approver: string, 295 | readonly contractId: string, 296 | ) { 297 | super(txResultCode, height, txHash, sender, proxy); 298 | } 299 | } 300 | 301 | export class ItemTokenCreateMessage extends TxResultMessage { 302 | constructor( 303 | txResultCode: TxResultCode, 304 | height: number, 305 | txHash: string, 306 | readonly sender: string, 307 | readonly createdItemToken: CreatedItemTokenMessage, 308 | ) { 309 | super(txResultCode, height, txHash, sender); 310 | } 311 | } 312 | 313 | export class ItemTokenModifyMessage extends TxResultMessage { 314 | constructor( 315 | txResultCode: TxResultCode, 316 | height: number, 317 | txHash: string, 318 | from: string, // sender 319 | readonly sender: string, 320 | readonly owner: string, // from 321 | readonly contractId: string, 322 | readonly tokenType: string, 323 | readonly tokenIndex: string, // if fungible then '00000000' 324 | readonly tokenId: string, 325 | readonly changes: Array, 326 | readonly isFungible: boolean = false, 327 | ) { 328 | super(txResultCode, height, txHash, from); 329 | if (!this.tokenId || this.tokenId.length < 1) { 330 | this.tokenId = `${tokenType}${tokenIndex}`; 331 | } 332 | } 333 | } 334 | 335 | export class ItemTokenApproveMessage extends TxResultMessage { 336 | constructor( 337 | txResultCode: TxResultCode, 338 | height: number, 339 | txHash: string, 340 | from: string, 341 | readonly approver: string, // from 342 | readonly contractId: string, 343 | readonly proxy: string, // approve to 344 | ) { 345 | super(txResultCode, height, txHash, from); 346 | } 347 | } 348 | 349 | export class ItemTokenDisapproveMessage extends TxResultMessage { 350 | constructor( 351 | txResultCode: TxResultCode, 352 | height: number, 353 | txHash: string, 354 | from: string, 355 | readonly approver: string, // from 356 | readonly contractId: string, 357 | readonly proxy: string, 358 | ) { 359 | super(txResultCode, height, txHash, from); 360 | } 361 | } 362 | 363 | export class ItemTokenGrantPermissionMessage extends TxResultMessage { 364 | constructor( 365 | txResultCode: TxResultCode, 366 | height: number, 367 | txHash: string, 368 | from: string, 369 | readonly owner: string, // from 370 | readonly contractId: string, 371 | readonly to: string, 372 | readonly permission: string, 373 | ) { 374 | super(txResultCode, height, txHash, from); 375 | } 376 | } 377 | 378 | export class ItemTokenRevokePermissionMessage extends TxResultMessage { 379 | constructor( 380 | txResultCode: TxResultCode, 381 | height: number, 382 | txHash: string, 383 | from: string, 384 | readonly owner: string, // from 385 | readonly contractId: string, 386 | readonly permission: string, 387 | ) { 388 | super(txResultCode, height, txHash, from); 389 | } 390 | } 391 | 392 | export class FungibleTokenIssueMessage extends TxResultMessage { 393 | constructor( 394 | txResultCode: TxResultCode, 395 | height: number, 396 | txHash: string, 397 | readonly sender: string, 398 | readonly owner: string, 399 | readonly to: string, // receiver 400 | readonly issuedFungibleToken: IssuedFungibleTokenMessage, 401 | readonly amount: string, 402 | ) { 403 | super(txResultCode, height, txHash, sender); 404 | } 405 | } 406 | 407 | export class FungibleTokenModifyMessage extends TxResultMessage { 408 | constructor( 409 | txResultCode: TxResultCode, 410 | height: number, 411 | txHash: string, 412 | from: string, 413 | readonly owner: string, 414 | readonly contractId: string, 415 | readonly tokenType: string, 416 | readonly changes: Array, 417 | ) { 418 | super(txResultCode, height, txHash, from); 419 | } 420 | } 421 | 422 | export class FungibleTokenMintMessage extends TxResultMessage { 423 | constructor( 424 | txResultCode: TxResultCode, 425 | height: number, 426 | txHash: string, 427 | from: string, 428 | readonly sender: string, 429 | readonly to: string, // receiver 430 | readonly mintedFungibleTokens: Array, 431 | ) { 432 | super(txResultCode, height, txHash, from); 433 | } 434 | } 435 | 436 | export class FungibleTokenBurnMessage extends TxResultMessage { 437 | constructor( 438 | txResultCode: TxResultCode, 439 | height: number, 440 | txHash: string, 441 | from: string, 442 | readonly sender: string, 443 | readonly contractId: string, 444 | readonly burnedFungibleTokens: Array, 445 | ) { 446 | super(txResultCode, height, txHash, from); 447 | } 448 | } 449 | 450 | export class FungibleTokenBurnFromMessage extends TxResultMessage { 451 | constructor( 452 | txResultCode: TxResultCode, 453 | height: number, 454 | txHash: string, 455 | from: string, 456 | proxy: string, 457 | readonly contractId: string, 458 | readonly burnedFungibleTokens: Array, 459 | ) { 460 | super(txResultCode, height, txHash, from, proxy); 461 | } 462 | } 463 | 464 | export class FungibleTokenTransferMessage extends TxResultMessage { 465 | constructor( 466 | txResultCode: TxResultCode, 467 | height: number, 468 | txHash: string, 469 | from: string, 470 | readonly sender: string, // from 471 | readonly contractId: string, 472 | readonly to: string, 473 | readonly transferredFungibleTokenAmount: TransferredFungibleTokenAmountMessage, 474 | ) { 475 | super(txResultCode, height, txHash, from); 476 | } 477 | } 478 | 479 | export class FungibleTokenTransferFromMessage extends TxResultMessage { 480 | constructor( 481 | txResultCode: TxResultCode, 482 | height: number, 483 | txHash: string, 484 | from: string, 485 | proxy: string, 486 | readonly owner: string, // from 487 | readonly contractId: string, 488 | readonly to: string, 489 | readonly transferredFungibleTokenAmount: TransferredFungibleTokenAmountMessage, 490 | ) { 491 | super(txResultCode, height, txHash, from, proxy); 492 | } 493 | } 494 | 495 | export class NonFungibleTokenIssueMessage extends TxResultMessage { 496 | constructor( 497 | txResultCode: TxResultCode, 498 | height: number, 499 | txHash: string, 500 | readonly sender: string, 501 | readonly contractId: string, 502 | readonly issuedNonFungibleToken: IssuedNonFungibleTokenMessage, 503 | ) { 504 | super(txResultCode, height, txHash, sender); 505 | } 506 | } 507 | 508 | export class NonFungibleTokenMintMessage extends TxResultMessage { 509 | constructor( 510 | txResultCode: TxResultCode, 511 | height: number, 512 | txHash: string, 513 | from: string = "", 514 | readonly mintedNonFungibleTokens: Array, 515 | ) { 516 | super(txResultCode, height, txHash, from); 517 | } 518 | } 519 | 520 | export class NonFungibleTokenBurnMessage extends TxResultMessage { 521 | constructor( 522 | txResultCode: TxResultCode, 523 | height: number, 524 | txHash: string, 525 | from: string, 526 | readonly sender: string, 527 | readonly contractId: string, 528 | readonly burnedNonFungibleToken: NonFungibleTokenMessage, 529 | ) { 530 | super(txResultCode, height, txHash, from); 531 | } 532 | } 533 | 534 | export class NonFungibleTokenBurnFromMessage extends TxResultMessage { 535 | constructor( 536 | txResultCode: TxResultCode, 537 | height: number, 538 | txHash: string, 539 | from: string, 540 | proxy: string, 541 | readonly owner: string, // from 542 | readonly contractId: string, 543 | readonly burnedNonFungibleToken: NonFungibleTokenMessage, 544 | ) { 545 | super(txResultCode, height, txHash, from, proxy); 546 | } 547 | } 548 | 549 | export class NonFungibleTokenTransferMessage extends TxResultMessage { 550 | constructor( 551 | txResultCode: TxResultCode, 552 | height: number, 553 | txHash: string, 554 | from: string, 555 | readonly transferredNonFungibleTokens: Array, 556 | ) { 557 | super(txResultCode, height, txHash, from); 558 | } 559 | } 560 | 561 | export class NonFungibleTokenTransferFromMessage extends TxResultMessage { 562 | constructor( 563 | txResultCode: TxResultCode, 564 | height: number, 565 | txHash: string, 566 | from: string, 567 | proxy: string, 568 | readonly transferredNonFungibleTokens: Array, 569 | ) { 570 | super(txResultCode, height, txHash, from, proxy); 571 | } 572 | } 573 | 574 | export class NonFungibleTokenAttachMessage extends TxResultMessage { 575 | constructor( 576 | txResultCode: TxResultCode, 577 | height: number, 578 | txHash: string, 579 | from: string, 580 | readonly sender: string, 581 | readonly parentNonFungibleToken: NonFungibleTokenMessage, 582 | readonly attachedNonFungibleToken: NonFungibleTokenMessage, 583 | ) { 584 | super(txResultCode, height, txHash, from); 585 | } 586 | } 587 | 588 | export class NonFungibleTokenAttachFromMessage extends TxResultMessage { 589 | constructor( 590 | txResultCode: TxResultCode, 591 | height: number, 592 | txHash: string, 593 | from: string, 594 | proxy: string, 595 | readonly sender: string, 596 | readonly parentNonFungibleToken: NonFungibleTokenMessage, 597 | readonly attachedNonFungibleToken: NonFungibleTokenMessage, 598 | ) { 599 | super(txResultCode, height, txHash, from, proxy); 600 | } 601 | } 602 | 603 | export class NonFungibleTokenDetachMessage extends TxResultMessage { 604 | constructor( 605 | txResultCode: TxResultCode, 606 | height: number, 607 | txHash: string, 608 | from: string, 609 | readonly sender: string, 610 | readonly parentNonFungibleToken: NonFungibleTokenMessage, 611 | readonly attachedNonFungibleToken: NonFungibleTokenMessage, 612 | ) { 613 | super(txResultCode, height, txHash, from); 614 | } 615 | } 616 | 617 | export class NonFungibleTokenDetachFromMessage extends TxResultMessage { 618 | constructor( 619 | txResultCode: TxResultCode, 620 | height: number, 621 | txHash: string, 622 | from: string, 623 | proxy: string, 624 | readonly sender: string, 625 | readonly parentNonFungibleToken: NonFungibleTokenMessage, 626 | readonly attachedNonFungibleToken: NonFungibleTokenMessage, 627 | ) { 628 | super(txResultCode, height, txHash, from, proxy); 629 | } 630 | } 631 | 632 | export class BaseCoinTransferMessage extends TxResultMessage { 633 | constructor( 634 | txResultCode: TxResultCode, 635 | height: number, 636 | txHash: string, 637 | from: string, 638 | readonly sender: string, // from 639 | readonly to: string, 640 | readonly baseCoinAmount: BaseCoinAmountMessage, 641 | ) { 642 | super(txResultCode, height, txHash, from); 643 | } 644 | } 645 | 646 | export class AccountMsgEmptyMessage extends TxResultMessage { 647 | constructor(txResultCode: TxResultCode, height: number, txHash: string, from: string) { 648 | super(txResultCode, height, txHash, from); 649 | } 650 | } 651 | -------------------------------------------------------------------------------- /lib/tx-core-models.ts: -------------------------------------------------------------------------------- 1 | // noinspection JSUnusedGlobalSymbols 2 | 3 | export enum TxSuccessResult { 4 | SUCCEEDED = "SUCCEEDED", 5 | FAILED = "FAILED", 6 | } 7 | 8 | export interface TransactionEvent { 9 | eventName: string; 10 | } 11 | 12 | export class TxMessage { 13 | constructor(readonly msgIndex: number, readonly requestType: string) {} 14 | 15 | readonly details: any = {}; // details are always empty. 16 | } 17 | 18 | export class TxStatusResult { 19 | constructor(readonly code: number = 0, readonly codeSpace: string = "") { 20 | if (this.code == 0) { 21 | this.result = TxSuccessResult.SUCCEEDED; 22 | } else { 23 | this.result = TxSuccessResult.FAILED; 24 | } 25 | } 26 | 27 | result: TxSuccessResult; 28 | } 29 | 30 | export class TxSigner { 31 | constructor(readonly address: string) {} 32 | } 33 | 34 | export class TxResultSummary { 35 | constructor( 36 | readonly height: number, 37 | readonly txIndex: number, 38 | readonly txHash: string, 39 | readonly signers: Array, 40 | readonly result: TxStatusResult, 41 | ) {} 42 | } 43 | 44 | export class TxResult { 45 | constructor( 46 | readonly summary: TxResultSummary, 47 | readonly txMessages: Array, 48 | readonly txEvents: Array, 49 | ) {} 50 | 51 | toJson(): any { 52 | return { 53 | summary: { 54 | height: this.summary.height, 55 | txIndex: this.summary.txIndex, 56 | txHash: this.summary.txHash, 57 | signers: [...this.summary.signers], 58 | result: this.summary.result, 59 | }, 60 | txMessages: [...this.txMessages], 61 | txEvents: [...this.txEvents], 62 | }; 63 | } 64 | } 65 | 66 | // events 67 | export class UnknownTransactionEvent implements TransactionEvent { 68 | constructor(readonly type: string, readonly attributes: Array, readonly extraMessage?: string) { 69 | if (!attributes) { 70 | this.attributes = []; 71 | } 72 | if (!extraMessage) { 73 | this.extraMessage = ""; 74 | } 75 | } 76 | 77 | eventName: string = "UnknownTransactionEvent"; 78 | } 79 | 80 | export class EventAccountCreated implements TransactionEvent { 81 | constructor(readonly msgIndex: number, readonly createdAddress: string) {} 82 | 83 | eventName: string = "EventAccountCreated"; 84 | } 85 | 86 | export class EventEmptyMsgCreated implements TransactionEvent { 87 | constructor(readonly msgIndex: number, readonly senderAddress: string) {} 88 | 89 | eventName: string = "EventEmptyMsgCreated"; 90 | } 91 | 92 | // bank events 93 | export class EventCoinTransferred implements TransactionEvent { 94 | constructor( 95 | readonly msgIndex: number, 96 | readonly denomination: string, 97 | readonly amount: string, 98 | readonly fromAddress: string, 99 | readonly toAddress: string, 100 | ) {} 101 | 102 | eventName: string = "EventCoinTransferred"; 103 | } 104 | 105 | export class EventTokenIssued implements TransactionEvent { 106 | constructor( 107 | readonly msgIndex: number, 108 | readonly contractId: string, 109 | readonly issuerAddress: string, 110 | readonly receiverAddress: string, 111 | readonly name: string, 112 | readonly symbol: string, 113 | readonly decimals: number, 114 | readonly amount: string, 115 | ) {} 116 | 117 | eventName: string = "EventTokenIssued"; 118 | } 119 | 120 | export class TokenAttribute { 121 | constructor(readonly key: string, readonly value: any) {} 122 | } 123 | 124 | export class EventTokenMinted implements TransactionEvent { 125 | constructor( 126 | readonly msgIndex: number, 127 | readonly contractId: string, 128 | readonly amount: string, 129 | readonly minterAddress: string, 130 | readonly toAddress: string, 131 | ) {} 132 | 133 | eventName: string = "EventTokenMinted"; 134 | } 135 | 136 | export class EventTokenBurned implements TransactionEvent { 137 | constructor( 138 | readonly msgIndex: number, 139 | readonly contractId: string, 140 | readonly amount: string, 141 | readonly fromAddress: string, 142 | readonly proxyAddress: string = "", 143 | ) {} 144 | 145 | eventName: string = "EventTokenBurned"; 146 | } 147 | 148 | export class EventTokenModified implements TransactionEvent { 149 | constructor( 150 | readonly msgIndex: number, 151 | readonly contractId: string, 152 | readonly modifierAddress: string, 153 | readonly tokenAttributes: Array, 154 | ) {} 155 | 156 | eventName: string = "EventTokenModified"; 157 | } 158 | 159 | enum TokenPermission { 160 | UNDEFINED = "UNDEFINED", 161 | TOKEN_MODIFY = "TOKEN_MODIFY", 162 | TOKEN_MINT = "TOKEN_MINT", 163 | TOKEN_BURN = "TOKEN_BURN", 164 | } 165 | 166 | export class EventTokenPermissionGranted implements TransactionEvent { 167 | constructor( 168 | readonly msgIndex: number, 169 | readonly contractId: string, 170 | readonly permission: TokenPermission, 171 | readonly granteeAddress: string, 172 | readonly granterAddress: string, 173 | ) {} 174 | 175 | eventName: string = "EventTokenPermissionGranted"; 176 | } 177 | 178 | export class EventTokenPermissionRenounced implements TransactionEvent { 179 | constructor( 180 | readonly msgIndex: number, 181 | readonly contractId: string, 182 | readonly permission: TokenPermission, 183 | readonly granteeAddress: string, 184 | ) {} 185 | 186 | eventName: string = "EventTokenPermissionRenounced"; 187 | } 188 | 189 | export class EventTokenProxyApproved implements TransactionEvent { 190 | constructor( 191 | readonly msgIndex: number, 192 | readonly contractId: string, 193 | readonly approverAddress: string, 194 | readonly proxyAddress: string, 195 | ) {} 196 | 197 | eventName: string = "EventTokenProxyApproved"; 198 | } 199 | 200 | export class EventTokenProxyDisapproved implements TransactionEvent { 201 | constructor( 202 | readonly msgIndex: number, 203 | readonly contractId: string, 204 | readonly approverAddress: TokenPermission, 205 | readonly proxyAddress: string, 206 | ) {} 207 | 208 | eventName: string = "EventTokenProxyDisapproved"; 209 | } 210 | 211 | export class EventTokenTransferred implements TransactionEvent { 212 | constructor( 213 | readonly msgIndex: number, 214 | readonly contractId: string, 215 | readonly amount: string, 216 | readonly fromAddress: string, 217 | readonly toAddress: string, 218 | readonly proxyAddress: string = "", 219 | ) {} 220 | 221 | eventName: string = "EventTokenTransferred"; 222 | } 223 | 224 | // item token events 225 | enum ItemTokenPermission { 226 | UNDEFINED = "UNDEFINED", 227 | COLLECTION_UNDEFINED = "COLLECTION_UNDEFINED", 228 | COLLECTION_ISSUE = "COLLECTION_ISSUE", 229 | COLLECTION_MODIFY = "COLLECTION_MODIFY", 230 | COLLECTION_MINT = "COLLECTION_MINT", 231 | COLLECTION_BURN = "COLLECTION_BURN", 232 | } 233 | 234 | export class CollectionAttribute { 235 | constructor(readonly key: string, readonly value: any) {} 236 | } 237 | 238 | export class EventCollectionCreated implements TransactionEvent { 239 | constructor( 240 | readonly msgIndex: number, 241 | readonly contractId: string, 242 | readonly name: string, 243 | readonly creatorAddress: string, 244 | ) {} 245 | 246 | eventName: string = "EventCollectionCreated"; 247 | } 248 | 249 | export class EventCollectionModified implements TransactionEvent { 250 | constructor( 251 | readonly msgIndex: number, 252 | readonly contractId: string, 253 | readonly tokenAttributes: Array, 254 | readonly modifierAddress: string, 255 | ) {} 256 | 257 | eventName: string = "EventCollectionModified"; 258 | } 259 | 260 | export class EventCollectionFtBurned implements TransactionEvent { 261 | constructor( 262 | readonly msgIndex: number, 263 | readonly contractId: string, 264 | readonly tokenType: string, 265 | readonly tokenId: string, 266 | readonly amount: string, 267 | readonly fromAddress: string, 268 | readonly proxyAddress: string = "", 269 | ) {} 270 | 271 | eventName: string = "EventCollectionFtBurned"; 272 | } 273 | 274 | export class EventCollectionFtIssued implements TransactionEvent { 275 | constructor( 276 | readonly msgIndex: number, 277 | readonly contractId: string, 278 | readonly tokenType: string, 279 | readonly name: string, 280 | readonly amount: string, 281 | readonly decimals: number = 0, 282 | readonly issuerAddress: string, 283 | readonly receiverAddress: string, 284 | readonly meta: string, 285 | readonly mintable: boolean = true, 286 | ) {} 287 | 288 | eventName: string = "EventCollectionFtIssued"; 289 | } 290 | 291 | export class EventCollectionFtMinted implements TransactionEvent { 292 | constructor( 293 | readonly msgIndex: number, 294 | readonly contractId: string, 295 | readonly tokenType: string, 296 | readonly tokenId: string, 297 | readonly amount: string, 298 | readonly toAddress: string, 299 | readonly minterAddress: string, 300 | ) {} 301 | 302 | eventName: string = "EventCollectionFtMinted"; 303 | } 304 | 305 | export class EventCollectionFtModified implements TransactionEvent { 306 | constructor( 307 | readonly msgIndex: number, 308 | readonly contractId: string, 309 | readonly tokenType: string, 310 | readonly tokenAttributes: Array, 311 | readonly modifierAddress: string, 312 | ) {} 313 | 314 | eventName: string = "EventCollectionFtModified"; 315 | } 316 | 317 | export class EventCollectionFtTransferred implements TransactionEvent { 318 | constructor( 319 | readonly msgIndex: number, 320 | readonly contractId: string, 321 | readonly tokenType: string, 322 | readonly tokenId: string, 323 | readonly amount: string, 324 | readonly fromAddress: string, 325 | readonly toAddress: string, 326 | readonly proxyAddress: string = "", 327 | ) {} 328 | 329 | eventName: string = "EventCollectionFtTransferred"; 330 | } 331 | 332 | export class EventCollectionNftAttached implements TransactionEvent { 333 | constructor( 334 | readonly msgIndex: number, 335 | readonly contractId: string, 336 | readonly childTokenId: string, 337 | readonly parentTokenId: string, 338 | readonly holderAddress: string, 339 | readonly proxyAddress: string = "", 340 | ) {} 341 | 342 | eventName: string = "EventCollectionNftAttached"; 343 | } 344 | 345 | export class EventCollectionNftBurned implements TransactionEvent { 346 | constructor( 347 | readonly msgIndex: number, 348 | readonly contractId: string, 349 | readonly tokenIds: Array, 350 | readonly fromAddress: string, 351 | readonly proxyAddress: string = "", 352 | ) {} 353 | 354 | eventName: string = "EventCollectionNftBurned"; 355 | } 356 | 357 | export class EventCollectionNftDetached implements TransactionEvent { 358 | constructor( 359 | readonly msgIndex: number, 360 | readonly contractId: string, 361 | readonly exChildTokenId: string, 362 | readonly exParentTokenId: string, 363 | readonly holderAddress: string, 364 | readonly proxyAddress: string = "", 365 | ) {} 366 | 367 | eventName: string = "EventCollectionNftDetached"; 368 | } 369 | 370 | export class EventCollectionNftHolderChanged implements TransactionEvent { 371 | constructor( 372 | readonly msgIndex: number, 373 | readonly contractId: string, 374 | readonly tokenIds: Array, 375 | readonly fromAddress: string, 376 | readonly toAddress: string, 377 | ) {} 378 | 379 | eventName: string = "EventCollectionNftHolderChanged"; 380 | } 381 | 382 | export class EventCollectionNftIssued implements TransactionEvent { 383 | constructor( 384 | readonly msgIndex: number, 385 | readonly contractId: string, 386 | readonly tokenType: string, 387 | readonly issuerAddress: string, 388 | ) {} 389 | 390 | eventName: string = "EventCollectionNftIssued"; 391 | } 392 | 393 | export class EventCollectionNftMinted implements TransactionEvent { 394 | constructor( 395 | readonly msgIndex: number, 396 | readonly contractId: string, 397 | readonly tokenIds: Array, 398 | readonly toAddress: string, 399 | readonly minterAddress: string, 400 | ) {} 401 | 402 | eventName: string = "EventCollectionNftMinted"; 403 | } 404 | 405 | export class EventCollectionNftModified implements TransactionEvent { 406 | constructor( 407 | readonly msgIndex: number, 408 | readonly contractId: string, 409 | readonly tokenId: string, 410 | readonly tokenAttributes: Array, 411 | readonly modifierAddress: string, 412 | ) {} 413 | 414 | eventName: string = "EventCollectionNftModified"; 415 | } 416 | 417 | export class EventCollectionNftRootChanged implements TransactionEvent { 418 | constructor( 419 | readonly msgIndex: number, 420 | readonly contractId: string, 421 | readonly tokenIds: Array, 422 | readonly oldRootTokenId: string, 423 | readonly newRootTokenId: string, 424 | ) {} 425 | 426 | eventName: string = "EventCollectionNftRootChanged"; 427 | } 428 | 429 | export class EventCollectionNftTransferred implements TransactionEvent { 430 | constructor( 431 | readonly msgIndex: number, 432 | readonly contractId: string, 433 | readonly tokenIds: Array, 434 | readonly fromAddress: string, 435 | readonly toAddress: string, 436 | readonly proxyAddress: string = "", 437 | ) {} 438 | 439 | eventName: string = "EventCollectionNftTransferred"; 440 | } 441 | 442 | export class EventCollectionNftTypeModified implements TransactionEvent { 443 | constructor( 444 | readonly msgIndex: number, 445 | readonly contractId: string, 446 | readonly tokenType: string, 447 | readonly tokenAttributes: Array, 448 | readonly modifierAddress: string, 449 | ) {} 450 | 451 | eventName: string = "EventCollectionNftTypeModified"; 452 | } 453 | 454 | export class EventCollectionPermissionGranted implements TransactionEvent { 455 | constructor( 456 | readonly msgIndex: number, 457 | readonly contractId: string, 458 | readonly permission: ItemTokenPermission, 459 | readonly granteeAddress: string, 460 | readonly granterAddress?: string, 461 | ) {} 462 | 463 | eventName: string = "EventCollectionPermissionGranted"; 464 | } 465 | 466 | export class EventCollectionPermissionRenounced implements TransactionEvent { 467 | constructor( 468 | readonly msgIndex: number, 469 | readonly contractId: string, 470 | readonly permission: ItemTokenPermission, 471 | readonly granteeAddress: string, 472 | ) {} 473 | 474 | eventName: string = "EventCollectionPermissionRenounced"; 475 | } 476 | 477 | export class EventCollectionProxyApproved implements TransactionEvent { 478 | constructor( 479 | readonly msgIndex: number, 480 | readonly contractId: string, 481 | readonly approverAddress: string, 482 | readonly proxyAddress: string, 483 | ) {} 484 | 485 | eventName: string = "EventCollectionProxyApproved"; 486 | } 487 | 488 | export class EventCollectionProxyDisapproved implements TransactionEvent { 489 | constructor( 490 | readonly msgIndex: number, 491 | readonly contractId: string, 492 | readonly approverAddress: string, 493 | readonly proxyAddress: string, 494 | ) {} 495 | 496 | eventName: string = "EventCollectionProxyDisapproved"; 497 | } 498 | -------------------------------------------------------------------------------- /lib/tx-result-codes.ts: -------------------------------------------------------------------------------- 1 | import { TxResultResponse } from "./response"; 2 | 3 | const txResultCodeMappings = [ 4 | { 5 | codespace: "bank", 6 | codes: [ 7 | { code: 0, description: "" }, 8 | { 9 | code: 1, 10 | description: 'No "inputs" for "send" type transaction', 11 | }, 12 | { 13 | code: 2, 14 | description: 'No "outputs" for "send" type transaction', 15 | }, 16 | { code: 3, description: 'Sum "inputs" != sum "outputs"' }, 17 | { code: 4, description: '"Send" type transactions are disabled.' }, 18 | ], 19 | }, 20 | { 21 | codespace: "coin", 22 | codes: [ 23 | { code: 0, description: "" }, 24 | { 25 | code: 1, 26 | description: 'No "inputs" for "send" type transaction', 27 | }, 28 | { 29 | code: 2, 30 | description: 'No "outputs" for "send" type transaction', 31 | }, 32 | { code: 3, description: 'Sum "inputs" != sum "outputs"' }, 33 | { code: 4, description: '"Send" type transactions are disabled.' }, 34 | { code: 5, description: "Can't transfer to safety box addresses." }, 35 | { 36 | code: 6, 37 | description: "The number of addresses exceeded the limit.", 38 | }, 39 | ], 40 | }, 41 | { 42 | codespace: "collection", 43 | codes: [ 44 | { code: 0, description: "" }, 45 | { 46 | code: 1, 47 | description: "Token with the given token ID already exists in the contract.", 48 | }, 49 | { 50 | code: 2, 51 | description: "Token with the given token ID doesn't exist in the contract.", 52 | }, 53 | { 54 | code: 3, 55 | description: "Token with the given token ID in the contract isn't mintable.", 56 | }, 57 | { code: 4, description: "Token name shouldn't be empty." }, 58 | { code: 5, description: "Invalid token ID" }, 59 | { 60 | code: 6, 61 | description: "Token decimals should be within the range in 0–18.", 62 | }, 63 | { 64 | code: 7, 65 | description: 66 | "Issuing token with amount[1], decimals[0], mintable[false] prohibited. Issue non-fungible token instead.", 67 | }, 68 | { code: 8, description: "Invalid token amount" }, 69 | { code: 9, description: 'Invalid "base_img_uri" length' }, 70 | { code: 10, description: 'Invalid "name" length' }, 71 | { code: 11, description: "Invalid token type pattern found." }, 72 | { code: 12, description: "Invalid token index pattern found." }, 73 | { code: 13, description: "Collection already exists." }, 74 | { code: 14, description: "Collection doesn't exist." }, 75 | { 76 | code: 15, 77 | description: "Token Type for the given contract ID already exists.", 78 | }, 79 | { 80 | code: 16, 81 | description: "Token Type for the given contract ID doesn't exist.", 82 | }, 83 | { 84 | code: 17, 85 | description: "All token types for the given contract ID are occupied.", 86 | }, 87 | { 88 | code: 18, 89 | description: "All non-fungible token indices for contract ID and token type are occupied.", 90 | }, 91 | { 92 | code: 19, 93 | description: "All fungible token IDs for contract ID are occupied.", 94 | }, 95 | { code: 20, description: "Account doesn't have the permission." }, 96 | { 97 | code: 21, 98 | description: "Token is already a child of some other token.", 99 | }, 100 | { code: 22, description: "Token isn't a child of some other token." }, 101 | { code: 23, description: "Token is being not owned." }, 102 | { code: 24, description: "Can't transfer a child token." }, 103 | { code: 25, description: "Token isn't a non-fungible token." }, 104 | { code: 26, description: "Can't attach token to itself." }, 105 | { code: 27, description: "Can't attach token to a descendant." }, 106 | { code: 28, description: "Approver is same as proxy." }, 107 | { code: 29, description: "Proxy isn't approved on the collection." }, 108 | { 109 | code: 30, 110 | description: "Proxy is already approved on the collection.", 111 | }, 112 | { code: 31, description: "Account already exists." }, 113 | { code: 32, description: "Account doesn't exist." }, 114 | { code: 33, description: "Insufficient supply" }, 115 | { code: 34, description: "Invalid coin" }, 116 | { code: 35, description: 'Invalid count of field "changes"' }, 117 | { code: 36, description: '"changes" is empty.' }, 118 | { code: 37, description: 'Invalid field of "changes"' }, 119 | { 120 | code: 38, 121 | description: "There is a token index but no token type.", 122 | }, 123 | { 124 | code: 39, 125 | description: "There is a token type of FT but no token index.", 126 | }, 127 | { code: 40, description: "Insufficient token" }, 128 | { code: 41, description: 'Duplicate field of "changes"' }, 129 | { code: 42, description: 'Invalid "meta" length' }, 130 | { code: 43, description: "Supply for collection reached maximum." }, 131 | { code: 44, description: "Required field can't be empty." }, 132 | { 133 | code: 45, 134 | description: "Can't attach token. (composition too deep)", 135 | }, 136 | { 137 | code: 46, 138 | description: "Can't attach token. (composition too wide)", 139 | }, 140 | ], 141 | }, 142 | { 143 | codespace: "token", 144 | codes: [ 145 | { code: 0, description: "" }, 146 | { code: 1, description: "Token already exists." }, 147 | { code: 2, description: "Token doesn't exist." }, 148 | { code: 3, description: "Token isn't mintable." }, 149 | { code: 4, description: "Token name shouldn't be empty." }, 150 | { 151 | code: 5, 152 | description: "Token decimals should be within the range of 0–18.", 153 | }, 154 | { code: 6, description: "Invalid token amount" }, 155 | { code: 7, description: "Invalid token URI length" }, 156 | { code: 8, description: "Invalid name length" }, 157 | { code: 9, description: "Invalid token symbol" }, 158 | { code: 10, description: "Account doesn't have the permission." }, 159 | { code: 11, description: "Account already exists." }, 160 | { code: 12, description: "Account doesn't exist." }, 161 | { code: 13, description: "Insufficient balance" }, 162 | { code: 14, description: "Supply for token already exists" }, 163 | { code: 15, description: "Insufficient supply" }, 164 | { code: 16, description: 'Invalid count of field "changes"' }, 165 | { code: 17, description: '"changes" is empty.' }, 166 | { code: 18, description: 'Invalid field of "changes"' }, 167 | { code: 19, description: 'Invalid field of "changes"' }, 168 | { code: 20, description: 'Invalid "meta" length' }, 169 | { code: 21, description: "Supply for token reached maximum" }, 170 | { code: 22, description: "Approver is same as proxy." }, 171 | { code: 23, description: "Proxy isn't approved on the token." }, 172 | { code: 24, description: "Proxy is already approved on the token." }, 173 | ], 174 | }, 175 | { 176 | codespace: "contract", 177 | codes: [ 178 | { code: 0, description: "" }, 179 | { code: 1, description: "Invalid contract ID" }, 180 | { code: 2, description: "Contract doesn't exist." }, 181 | ], 182 | }, 183 | { 184 | codespace: "link", 185 | codes: [ 186 | { code: 0, description: "" }, 187 | { code: 1, description: "Error" }, 188 | { code: 2, description: "Invalid permission" }, 189 | { code: 3, description: "Invalid name" }, 190 | ], 191 | }, 192 | { 193 | codespace: "sdk", 194 | codes: [ 195 | { code: 0, description: "" }, 196 | { code: 2, description: "Tx parse error" }, 197 | { code: 3, description: "Invalid sequence" }, 198 | { code: 4, description: "Unauthorized" }, 199 | { code: 5, description: "Insufficient funds" }, 200 | { code: 6, description: "Unknown request" }, 201 | { code: 7, description: "Invalid address" }, 202 | { code: 8, description: "Invalid public key" }, 203 | { code: 9, description: "Unknown address" }, 204 | { code: 10, description: "Invalid coins" }, 205 | { code: 11, description: "Out of gas" }, 206 | { code: 12, description: "Memo is too large." }, 207 | { code: 13, description: "Insufficient fee" }, 208 | { code: 14, description: "Maximum number of signatures exceeded." }, 209 | { code: 15, description: "No signatures supplied." }, 210 | { code: 16, description: "Failed to marshal JSON bytes." }, 211 | { code: 17, description: "Failed to unmarshal JSON bytes." }, 212 | { code: 18, description: "Invalid request" }, 213 | { code: 19, description: "Tx already in mempool." }, 214 | { code: 20, description: "Mempool is full." }, 215 | { code: 21, description: "Tx too large" }, 216 | ], 217 | }, 218 | ]; 219 | 220 | export class TxResultCode { 221 | constructor(readonly codeSpace: string, readonly code: number, readonly description: string) {} 222 | 223 | isSuccess(): boolean { 224 | return this.code == 0; 225 | } 226 | 227 | txResultType(): TxResultType { 228 | if (this.isSuccess()) { 229 | return TxResultType.SUCCESS; 230 | } else { 231 | return TxResultType.FAIL; 232 | } 233 | } 234 | 235 | static invalidTxResultCode(): TxResultCode { 236 | return new TxResultCode("invalid-name-space", -1, "invalid tx-result-code"); 237 | } 238 | } 239 | 240 | export enum TxResultType { 241 | SUCCESS, 242 | FAIL, 243 | } 244 | 245 | export class TxResultCodeMappingsProvider { 246 | private static mappings: Array = txResultCodeMappings; 247 | 248 | private constructor() {} 249 | 250 | static codes(codespace: string): Array { 251 | return this.mappings 252 | .filter(it => it.codespace == codespace) 253 | .flatMap(it => it.codes) 254 | .map(it => new TxResultCode(codespace, it.code, it.description)); 255 | } 256 | 257 | static code(txResultResponse: TxResultResponse): TxResultCode { 258 | const isSuccess = txResultResponse.code === 0; 259 | if (isSuccess) { 260 | return new TxResultCode("", txResultResponse.code, ""); 261 | } 262 | 263 | const code = this.mappings 264 | .filter(it => it.codespace == txResultResponse.codespace) 265 | .flatMap(it => it.codes) 266 | .find(it => it.code == txResultResponse.code); 267 | 268 | if (code) { 269 | return new TxResultCode(code.codespace, code.code, code.description); 270 | } else { 271 | return TxResultCode.invalidTxResultCode(); 272 | } 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /lib/tx-result-util.ts: -------------------------------------------------------------------------------- 1 | import * as _ from "lodash"; 2 | import jsonpath from "jsonpath"; 3 | import { TokenUtil } from "./token-util"; 4 | import { TxResultResponse } from "./response"; 5 | import { 6 | TokenChangeMessage, 7 | IssuedServiceTokenMessage, 8 | CreatedItemTokenMessage, 9 | MintedFungibleTokenMessage, 10 | BurnedFungibleTokenMessage, 11 | IssuedNonFungibleTokenMessage, 12 | IssuedFungibleTokenMessage, 13 | MintedNonFungibleTokenMessage, 14 | NonFungibleTokenMessage, 15 | BaseCoinAmountMessage, 16 | TransferredFungibleTokenAmountMessage, 17 | } from "./transaction-messages"; 18 | 19 | export class TxResultUtil { 20 | private constructor() {} 21 | 22 | static findFromWalletAddress(txResultResponse: TxResultResponse): string { 23 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "from", ""); 24 | } 25 | 26 | static findOwnerWalletAddress(txResultResponse: TxResultResponse): string { 27 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "owner", ""); 28 | } 29 | 30 | static findProxyWalletAddress(txResultResponse: TxResultResponse): string { 31 | const proxyAddress = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "proxy", ""); 32 | if (!proxyAddress || proxyAddress.length < 1) { 33 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "proxy"); 34 | } else { 35 | return proxyAddress; 36 | } 37 | } 38 | 39 | static findSenderWalletAddress(txResultResponse: TxResultResponse): any { 40 | const senderAddress = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "sender", ""); 41 | if (!senderAddress || senderAddress.length < 1) { 42 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "sender"); 43 | } else { 44 | return senderAddress; 45 | } 46 | } 47 | 48 | static findApproverWalletAddress(txResultResponse: TxResultResponse): string { 49 | const approverAddress = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "approver", ""); 50 | if (!approverAddress || approverAddress.length < 1) { 51 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "approver"); 52 | } else { 53 | return approverAddress; 54 | } 55 | } 56 | 57 | static findChanges(txResultResponse: TxResultResponse): Array { 58 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "changes", ""); 59 | } 60 | 61 | static findToWalletAddress(txResultResponse: TxResultResponse): string { 62 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "to", ""); 63 | } 64 | 65 | static findContractId(txResultResponse: TxResultResponse): string { 66 | const contractId = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "contractId", ""); 67 | 68 | if (contractId && contractId.length > 1) { 69 | return contractId; 70 | } else { 71 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "contract_id"); 72 | } 73 | } 74 | 75 | static findAmount(txResultResponse: TxResultResponse): string { 76 | let amount = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "amount", "") as string; 77 | if (!amount || amount.length < 1) { 78 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "amount").toString(); 79 | } else { 80 | return amount.toString(); 81 | } 82 | } 83 | 84 | static findCreatedItemToken(txResultResponse: TxResultResponse): CreatedItemTokenMessage { 85 | return new CreatedItemTokenMessage( 86 | TxResultUtil.findContractId(txResultResponse), 87 | TxResultUtil.findOwnerWalletAddress(txResultResponse), 88 | TxResultUtil.findTokenName(txResultResponse), 89 | TxResultUtil.findTokenMeta(txResultResponse), 90 | TxResultUtil.findBaseImgUri(txResultResponse), 91 | ); 92 | } 93 | 94 | static findTransferredFungibleTokenAmount(txResultResponse: TxResultResponse): TransferredFungibleTokenAmountMessage { 95 | const amounts = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "amount", []); 96 | const tokenId = amounts[0]["tokenId"]; 97 | const amount = amounts[0]["amount"]; 98 | return new TransferredFungibleTokenAmountMessage( 99 | TxResultUtil.findContractId(txResultResponse), 100 | TokenUtil.tokenTypeFrom(tokenId), 101 | (amount || "0").toString(), 102 | ); 103 | } 104 | 105 | static findBaseImgUri(txResultResponse: TxResultResponse): string { 106 | const baseImgUri = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "base_img_uri", ""); 107 | if (!baseImgUri || baseImgUri.length < 1) { 108 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "baseImgUri", ""); 109 | } else { 110 | return baseImgUri; 111 | } 112 | } 113 | 114 | static findImgUri(txResultResponse: TxResultResponse): string { 115 | const imgUri = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "img_uri", ""); 116 | if (!imgUri || imgUri.length < 1) { 117 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "imgUri", ""); 118 | } else { 119 | return imgUri; 120 | } 121 | } 122 | 123 | static findIssuedServiceToken(txResultResponse: TxResultResponse): IssuedServiceTokenMessage { 124 | return new IssuedServiceTokenMessage( 125 | TxResultUtil.findContractId(txResultResponse), 126 | TxResultUtil.findTokenName(txResultResponse), 127 | TxResultUtil.findTokenSymbol(txResultResponse), 128 | TxResultUtil.findTokenMeta(txResultResponse), 129 | TxResultUtil.findBaseImgUri(txResultResponse), 130 | TxResultUtil.findTokenDecimals(txResultResponse), 131 | ); 132 | } 133 | 134 | static findMintedFungibleTokens(txResultResponse: TxResultResponse): Array { 135 | // array of object 136 | let amounts: Array = TxResultUtil.findValueFromMessages(txResultResponse, "amount"); 137 | return amounts.map(it => { 138 | const tokenId = it["tokenId"]; 139 | const tokenType = TokenUtil.tokenTypeFrom(tokenId); 140 | return new MintedFungibleTokenMessage( 141 | TxResultUtil.findContractId(txResultResponse), 142 | tokenType, 143 | (it["amount"] || "0").toString(), 144 | ); 145 | }); 146 | } 147 | 148 | static findBurnedFungibleTokens(txResultResponse: TxResultResponse): Array { 149 | // array of object 150 | let amounts: Array = TxResultUtil.findValueFromMessages(txResultResponse, "amount"); 151 | return amounts.map(it => { 152 | const tokenId = it["tokenId"]; 153 | const tokenType = TokenUtil.tokenTypeFrom(tokenId); 154 | return new BurnedFungibleTokenMessage( 155 | TxResultUtil.findContractId(txResultResponse), 156 | tokenType, 157 | (it["amount"] || "0").toString(), 158 | ); 159 | }); 160 | } 161 | 162 | static findIssuedFungibleToken(txResultResponse: TxResultResponse): IssuedFungibleTokenMessage { 163 | const tokenId = TxResultUtil.findTokenIdFromEvents(txResultResponse); 164 | const tokenType = TokenUtil.tokenTypeFrom(tokenId); 165 | return new IssuedFungibleTokenMessage( 166 | TxResultUtil.findContractId(txResultResponse), 167 | tokenType, 168 | TxResultUtil.findTokenName(txResultResponse), 169 | TxResultUtil.findTokenMeta(txResultResponse), 170 | TxResultUtil.findTokenDecimals(txResultResponse), 171 | ); 172 | } 173 | 174 | static findIssuedNonFungibleToken(txResultResponse: TxResultResponse): IssuedNonFungibleTokenMessage { 175 | return new IssuedNonFungibleTokenMessage( 176 | TxResultUtil.findContractId(txResultResponse), 177 | TxResultUtil.findTokenType(txResultResponse), 178 | TxResultUtil.findTokenName(txResultResponse), 179 | TxResultUtil.findTokenMeta(txResultResponse), 180 | ); 181 | } 182 | 183 | static findMintedNonFungibleToken(txResultResponse: TxResultResponse): MintedNonFungibleTokenMessage { 184 | const tokenId = TxResultUtil.findTokenId(txResultResponse); 185 | const tokenType = TokenUtil.tokenTypeFrom(tokenId); 186 | const tokenIndex = TokenUtil.tokenIndexFrom(tokenId); 187 | return new MintedNonFungibleTokenMessage( 188 | TxResultUtil.findFromWalletAddress(txResultResponse), 189 | TxResultUtil.findSenderWalletAddress(txResultResponse), 190 | TxResultUtil.findToWalletAddress(txResultResponse), 191 | TxResultUtil.findContractId(txResultResponse), 192 | tokenType, 193 | tokenIndex, 194 | TxResultUtil.findTokenNameFromMintNFT(txResultResponse), 195 | TxResultUtil.findTokenMetaFromMintNFT(txResultResponse), 196 | ); 197 | } 198 | 199 | static findMintedNonFungibleTokens(txResultResponse: TxResultResponse): Array { 200 | const senderAddresses = jsonpath.query(txResultResponse.logs, `$..[?(@.key === 'sender')].value`); 201 | const fromAddresses = jsonpath.query(txResultResponse.logs, `$..[?(@.key === 'from')].value`); 202 | const toAddresses = jsonpath.query(txResultResponse.logs, `$..[?(@.key === 'to')].value`); 203 | const contractIdList = jsonpath.query(txResultResponse.logs, `$..[?(@.key === 'contract_id')].value`); 204 | const tokenIdList = jsonpath.query(txResultResponse.logs, `$..[?(@.key === 'token_id')].value`); 205 | const params = jsonpath.query(txResultResponse.tx.value.msg, "$..params[0]"); 206 | 207 | return tokenIdList.map((it, index) => { 208 | const tokenType = TokenUtil.tokenTypeFrom(it); 209 | const tokenIndex = TokenUtil.tokenIndexFrom(it); 210 | return new MintedNonFungibleTokenMessage( 211 | fromAddresses[index], 212 | senderAddresses[index], 213 | toAddresses[index], 214 | contractIdList[index], 215 | tokenType, 216 | tokenIndex, 217 | params[index]["name"], 218 | params[index]["meta"], 219 | ); 220 | }); 221 | } 222 | 223 | static findBurnedNonFungibleToken(txResultResponse: TxResultResponse): NonFungibleTokenMessage { 224 | return TxResultUtil.findNonFungibleToken(txResultResponse); 225 | } 226 | 227 | static findTransferredNonFungibleToken(txResultResponse: TxResultResponse): Array { 228 | const contractId = TxResultUtil.findContractId(txResultResponse); 229 | const tokenIdList = TxResultUtil.findMultiTokenIds(txResultResponse); 230 | 231 | return tokenIdList.map((it, _) => { 232 | const tokenType = TokenUtil.tokenTypeFrom(it); 233 | const tokenIndex = TokenUtil.tokenIndexFrom(it); 234 | return new NonFungibleTokenMessage(contractId, tokenType, tokenIndex); 235 | }); 236 | } 237 | 238 | static findTransferredFromNonFungibleTokens(txResultResponse: TxResultResponse): Array { 239 | const tokenIdList = jsonpath.query(txResultResponse.logs, `$..[?(@.key === 'token_id')].value`); 240 | const contractId = TxResultUtil.findContractId(txResultResponse); 241 | return tokenIdList.map((it, _) => { 242 | const tokenType = TokenUtil.tokenTypeFrom(it); 243 | const tokenIndex = TokenUtil.tokenIndexFrom(it); 244 | return new NonFungibleTokenMessage(contractId, tokenType, tokenIndex); 245 | }); 246 | } 247 | 248 | static findMultiTokenIds(txResultResponse: TxResultResponse): Array { 249 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "tokenIds", []); 250 | } 251 | 252 | static findNonFungibleToken(txResultResponse: TxResultResponse): NonFungibleTokenMessage { 253 | const tokenId = TxResultUtil.findTokenIdList(txResultResponse)[0]; 254 | const tokenType = TokenUtil.tokenTypeFrom(tokenId); 255 | const tokenIndex = TokenUtil.tokenIndexFrom(tokenId); 256 | return new NonFungibleTokenMessage(TxResultUtil.findContractId(txResultResponse), tokenType, tokenIndex); 257 | } 258 | 259 | static findTokenIdList(txResultResponse: TxResultResponse): Array { 260 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "tokenIds", []); 261 | } 262 | 263 | static findTokenNameFromMintNFT(txResultResponse: TxResultResponse): string { 264 | return txResultResponse.tx.value.msg[0].value["params"][0]["name"].toString(); 265 | } 266 | 267 | static findTokenMetaFromMintNFT(txResultResponse: TxResultResponse): string { 268 | return txResultResponse.tx.value.msg[0].value["params"][0]["meta"].toString(); 269 | } 270 | 271 | static findTokenId(txResultResponse: TxResultResponse): string { 272 | let tokenId = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "tokenId", "") as string; 273 | if (tokenId && tokenId.length == 16) { 274 | return tokenId; 275 | } else { 276 | tokenId = TxResultUtil.findValueFromLogEvents(txResultResponse, "token_id"); 277 | if (tokenId && tokenId.length == 16) { 278 | return tokenId; 279 | } else { 280 | return `${TxResultUtil.findTokenType(txResultResponse)}${TxResultUtil.findTokenIndex(txResultResponse)}`; 281 | } 282 | } 283 | } 284 | 285 | static findTokenIdFromEvents(txResultResponse: TxResultResponse): string { 286 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "token_id"); 287 | } 288 | 289 | static findParentTokenId(txResultResponse: TxResultResponse): string { 290 | const parentTokenId = TxResultUtil.findValueFromMessagesWithDefaultValue( 291 | txResultResponse, 292 | "toTokenId", 293 | "", 294 | ) as string; 295 | if (parentTokenId && parentTokenId.length > 1) { 296 | return parentTokenId; 297 | } else { 298 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "to_token_id"); 299 | } 300 | } 301 | 302 | static findOldParentTokenId(txResultResponse: TxResultResponse): string { 303 | const oldParentTokenId = TxResultUtil.findValueFromMessagesWithDefaultValue( 304 | txResultResponse, 305 | "oldRootTokenId", 306 | "", 307 | ) as string; 308 | if (oldParentTokenId && oldParentTokenId.length > 1) { 309 | return oldParentTokenId; 310 | } else { 311 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "old_root_token_id"); 312 | } 313 | } 314 | 315 | static findParentTokenIdFromDetach(txResultResponse: TxResultResponse): string { 316 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "from_token_id"); 317 | } 318 | 319 | static findTokenType(txResultResponse: TxResultResponse): string { 320 | const tokenType = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "tokenType", ""); 321 | if (tokenType && tokenType.length == 8) { 322 | return tokenType; 323 | } else { 324 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "token_type"); 325 | } 326 | } 327 | 328 | static findTokenIndex(txResultResponse: TxResultResponse): string { 329 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "tokenIndex", ""); 330 | } 331 | 332 | static findTokenName(txResultResponse: TxResultResponse): string { 333 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "name", ""); 334 | } 335 | 336 | static findTokenSymbol(txResultResponse: TxResultResponse): string { 337 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "symbol", ""); 338 | } 339 | 340 | static findTokenDecimals(txResultResponse: TxResultResponse): number { 341 | const decimals = TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "decimals", 0); 342 | 343 | if (!decimals || decimals.toString().length < 1) { 344 | return TxResultUtil.findValueFromLogEvents(txResultResponse, "decimals"); 345 | } else { 346 | return decimals; 347 | } 348 | } 349 | 350 | static findTokenMeta(txResultResponse: TxResultResponse): string { 351 | return TxResultUtil.findValueFromMessagesWithDefaultValue(txResultResponse, "meta", ""); 352 | } 353 | 354 | static findBaseCoinAmount(txResultResponse: TxResultResponse): BaseCoinAmountMessage { 355 | const amount = txResultResponse.tx.value.msg[0].value.amount[0]; 356 | return new BaseCoinAmountMessage(amount["denom"], (amount["amount"] || "0").toString()); 357 | } 358 | 359 | static findValueFromMessagesWithDefaultValue( 360 | txResultResponse: TxResultResponse, 361 | key: string, 362 | defaultValue: any, 363 | ): any { 364 | const value = TxResultUtil.findValueFromMessages(txResultResponse, key); 365 | if (value) { 366 | return value; 367 | } else { 368 | return defaultValue; 369 | } 370 | } 371 | 372 | static findValueFromMessages(txResultResponse: TxResultResponse, key: string): any { 373 | if (txResultResponse.tx.value.msg.length < 1) { 374 | return ""; 375 | } else { 376 | const msg = _.head(_.filter(txResultResponse.tx.value.msg, it => !!it.value[key])); 377 | if (msg && msg.value) { 378 | return msg.value[key]; 379 | } else { 380 | return null; 381 | } 382 | } 383 | } 384 | 385 | static findValueFromLogEvents(txResultResponse: TxResultResponse, key: string): any { 386 | let targetAttribute = _.head(jsonpath.query(txResultResponse.logs, `$..[?(@.key === '${key}')]`)); 387 | if (targetAttribute && targetAttribute["value"]) { 388 | return targetAttribute["value"]; 389 | } else { 390 | return ""; 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v2 13 | with: 14 | node-version: 12 15 | registry-url: https://registry.npmjs.org/ 16 | - run: npm install 17 | - run: npm publish 18 | env: 19 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@line/lbd-sdk-js", 3 | "version": "1.4.8", 4 | "description": "javascript sdk for Line Blockchain Developers", 5 | "engines": { 6 | "node": ">=10" 7 | }, 8 | "main": "dist/index.js", 9 | "types": "dist/index.d.ts", 10 | "files": [ 11 | "dist", 12 | "lib" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "git@github.com:line/line-blockchain-developers-sdk-js.git" 17 | }, 18 | "license": "Apache-2.0", 19 | "keywords": [ 20 | "line-blockchain-developers-sdk", 21 | "line blockchain", 22 | "line-blockchain-developers" 23 | ], 24 | "scripts": { 25 | "prettier": "prettier --parser typescript --trailing-comma all --arrow-parens avoid \"{lib,test}/**/*.ts\"", 26 | "format": "npm run prettier -- --write", 27 | "format:check": "npm run prettier -- -l", 28 | "pretest": "npm run build", 29 | "clean": "rm -rf dist/* && rm -f tsconfig.tsbuildinfo", 30 | "build": "tsc -p tsconfig.json", 31 | "test-api": "mocha test/http-client-base.spec.ts -r ts-node/register", 32 | "test:integration": "mocha integration-test/*.spec.ts -r ts-node/register", 33 | "test-single": "mocha -g", 34 | "test": "mocha test/**/*.ts -r ts-node/register", 35 | "generate-changelog": "ts-node ./scripts/generate-changelog.ts", 36 | "prepare-release": "run-s reset-hard test cov:check doc:html version doc:publish", 37 | "prepare": "husky install || exit 0", 38 | "release": "npm run build && npm publish --access public" 39 | }, 40 | "dependencies": { 41 | "@cosmjs/amino": "^0.29.5", 42 | "@types/crypto-js": "^4.0.1", 43 | "@types/jsonpath": "^0.2.0", 44 | "@types/lodash": "^4.14.165", 45 | "axios": "^0.21.1", 46 | "crypto-js": "^4.0.0", 47 | "crypto-random-string": "^3.3.0", 48 | "js-base64": "^3.7.3", 49 | "jsonpath": "^1.1.1", 50 | "lodash": "^4.17.20", 51 | "tslog": "^3.0.2", 52 | "typescript-collections": "^1.3.3" 53 | }, 54 | "devDependencies": { 55 | "@types/chai": "^4.3.6", 56 | "@types/chai-as-promised": "^7.1.6", 57 | "@types/finalhandler": "^1.1.0", 58 | "@types/mocha": "^8.0.3", 59 | "@types/node": "^14.14.25", 60 | "axios-mock-adapter": "^1.19.0", 61 | "chai": "^4.2.0", 62 | "chai-as-promised": "^7.1.1", 63 | "finalhandler": "^1.1.2", 64 | "husky": "^5.1.3", 65 | "mocha": "^10.2.0", 66 | "nock": "^13.0.4", 67 | "nyc": "^15.1.0", 68 | "prettier": "^2.1.1", 69 | "ts-dotenv": "^0.8.3", 70 | "ts-node": "^10.8.1", 71 | "typescript": "^4.0.2" 72 | }, 73 | "husky": { 74 | "hooks": { 75 | "pre-commit": "npm run format:check", 76 | "pre-push": "npm run format:check && npm run build && npm run test" 77 | } 78 | }, 79 | "nyc": { 80 | "require": [ 81 | "ts-node/register" 82 | ], 83 | "extension": [ 84 | ".ts" 85 | ], 86 | "reporter": [ 87 | "lcov", 88 | "text" 89 | ], 90 | "sourceMap": true, 91 | "instrument": true 92 | }, 93 | "mocha": { 94 | "require": "ts-node/register", 95 | "spec": "test/*.spec.ts" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /scripts/generate-changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # used in actions 3 | 4 | git checkout ${GITHUB_HEAD_REF} 5 | 6 | git config --global user.email "action@github.com" 7 | git config --global user.name "GitHub Action" 8 | 9 | npm run generate-changelog 10 | 11 | git add -A 12 | git commit -m "(Changelog CI) Added Changelog" 13 | git push -u origin ${GITHUB_HEAD_REF} 14 | -------------------------------------------------------------------------------- /scripts/generate-changelog.ts: -------------------------------------------------------------------------------- 1 | import {execSync} from "child_process"; 2 | import {readFileSync, writeFileSync} from "fs"; 3 | import {resolve} from "path"; 4 | 5 | const {version: lastVersion} = require("../package.json"); 6 | 7 | const changeLogPath = resolve(__dirname, "../CHANGELOG.md"); 8 | 9 | let newVersion = lastVersion; 10 | 11 | console.log("Gets Release Version from GITHUB_EVENT_PATH"); 12 | if (process.env.GITHUB_EVENT_PATH) { 13 | const { 14 | pull_request: {title}, 15 | } = require(process.env.GITHUB_EVENT_PATH); 16 | 17 | if (/^release/i.test(title)) 18 | newVersion = (title as string).match(/release ([\d\.]+)/i)[1]; 19 | else { 20 | console.log("Not target pull request, exiting"); 21 | process.exit(0); 22 | } 23 | } 24 | console.log(`New Version: ${newVersion}`); 25 | 26 | console.log("Bump Version"); 27 | execSync(`npm version ${newVersion}`); 28 | 29 | const gitLogOutput = execSync( 30 | `git log v${lastVersion}... --format=%s` 31 | ).toString("utf-8"); 32 | 33 | const commitsArray = gitLogOutput 34 | .split("\n") 35 | .filter((message) => message && message !== ""); 36 | 37 | const category = { 38 | miscs: [] as string[], 39 | features: [] as string[], 40 | bugFixes: [] as string[], 41 | }; 42 | 43 | commitsArray.forEach((message) => { 44 | let cat: keyof typeof category; 45 | if (/^([\d\.]+)$/.test(message)) { 46 | return; 47 | } else if (message.includes("test")) { 48 | cat = "miscs"; 49 | } else if (/(add)|(support)/i.test(message)) { 50 | cat = "features"; 51 | } else if (/fix/i.test(message)) { 52 | cat = "bugFixes"; 53 | } else { 54 | cat = "miscs"; 55 | } 56 | category[cat].push(`* ${message}`); 57 | }); 58 | 59 | const now = new Date(); 60 | const MonthText = [ 61 | "Jan", 62 | "Feb", 63 | "Mar", 64 | "Apr", 65 | "May", 66 | "Jun", 67 | "Jul", 68 | "Aug", 69 | "Sep", 70 | "Oct", 71 | "Nov", 72 | "Dec", 73 | ]; 74 | let newChangelog = `## ${newVersion} (${now.getDate()} ${MonthText[now.getMonth()] 75 | } ${now.getFullYear()}) 76 | `; 77 | 78 | if (category.features.length > 0) { 79 | newChangelog += ` 80 | ### Feature 81 | ${category.features.join("\n")} 82 | `; 83 | } 84 | 85 | if (category.bugFixes.length > 0) { 86 | newChangelog += ` 87 | ### Bug fix 88 | ${category.bugFixes.join("\n")} 89 | `; 90 | } 91 | 92 | if (category.miscs.length > 0) { 93 | newChangelog += ` 94 | ### Misc 95 | ${category.miscs.join("\n")} 96 | `; 97 | } 98 | 99 | const currentChangelog = readFileSync(changeLogPath, "utf-8"); 100 | 101 | writeFileSync( 102 | changeLogPath, 103 | `${newChangelog} 104 | ${currentChangelog}` 105 | ); 106 | -------------------------------------------------------------------------------- /test/get-signer-addresses.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { 4 | RawTransactionRequestPubKey, 5 | RawTxSignature, 6 | RawTransactionRequest, 7 | RawTransactionRequestValue, 8 | RawTransactionRequestFee, 9 | RawTransactionSignerAddressUtil, 10 | } from "../lib/tx-raw-models"; 11 | 12 | describe("RawTransactionSignerAddressUtil test", () => { 13 | it("test getSignerAddresses", () => { 14 | let rawTransactionRequestValue: RawTransactionRequestValue = new RawTransactionRequestValue( 15 | [], 16 | new RawTransactionRequestFee(1, []), 17 | "", 18 | [ 19 | new RawTxSignature( 20 | new RawTransactionRequestPubKey("tendermint/PubKeySecp256k1", "A41pCdZ71Vw66K5er5JrzVqYffiZsjoLBDB2szrNIJjy"), 21 | "AF71IQpmzGaJLrv8EJ0tCtrUNQdyo5vsgDpPNyLIePhqNnzObEo00efm+9ACLbXdI4ETEGe3DQ+B0AHt70sC4A==", 22 | ), 23 | ], 24 | ); 25 | let tx: RawTransactionRequest = new RawTransactionRequest("cosmos-sdk/StdTx", rawTransactionRequestValue); 26 | let actualSignerAddress = RawTransactionSignerAddressUtil.getSignerAddresses("tlink", tx); 27 | let expectedSignerAddress = "tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq"; 28 | expect(expectedSignerAddress).to.equal(actualSignerAddress[0]); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/http-client-base-v2-api.spec.ts: -------------------------------------------------------------------------------- 1 | import MockAdapter from "axios-mock-adapter"; 2 | 3 | import * as chai from "chai"; 4 | import chaiAsPromised from "chai-as-promised"; 5 | 6 | chai.use(chaiAsPromised); 7 | 8 | const expect = chai.expect; 9 | import { describe, it } from "mocha"; 10 | 11 | import _ from "lodash"; 12 | import { HttpClient } from "../lib/http-client-base"; 13 | import { TransactionMsgTypes } from "../lib/constants"; 14 | import { DEFAULT_PAGE_REQUEST, PageRequest, OrderBy, TokenId, RequestType, CursorPageRequest } from "../lib/request"; 15 | import { transactionResult, singleTransactionResult } from "./test-data-v2"; 16 | import { HttpTestUtil } from "./http-test-util"; 17 | 18 | describe("http-client-base v2 APIs test", () => { 19 | let stub: MockAdapter; 20 | 21 | after(() => { 22 | stub.restore(); 23 | }); 24 | 25 | const baseUrl = "http://localhost"; 26 | const testApiKey = "test-api-key"; 27 | const testSecret = "test-api-secret"; 28 | const httpClient = new HttpClient(baseUrl, testApiKey, testSecret); 29 | 30 | it("list of transactions of a user v2 api test", async () => { 31 | const testUserId = "U556719f559479aab8b8f74c488bf6317"; 32 | const pageRequest = new PageRequest(0, 10, OrderBy.DESC); 33 | const testTxHash = "D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A"; 34 | const testTxResultResponse = transactionResult; 35 | 36 | stub = new MockAdapter(httpClient.getAxiosInstance()); 37 | 38 | stub.onGet(`/v2/users/${testUserId}/transactions`).reply(config => { 39 | HttpTestUtil.assertHeaders(config.headers); 40 | HttpTestUtil.assertPageParameters(config.params, pageRequest); 41 | return [200, testTxResultResponse]; 42 | }); 43 | 44 | const response = await httpClient.userTransactionsV2(testUserId, pageRequest); 45 | expect(response["statusCode"]).to.equal(1000); 46 | expect(response["responseData"][0]["summary"]).to.deep.equal(testTxResultResponse.responseData[0]["summary"]); 47 | }); 48 | 49 | it("list of transactions of a so wallet v2 api test", async () => { 50 | const testAddress = "tlink1nf5uhdmtsshmkqvlmq45kn4q9atnkx4l3u4rww"; 51 | const pageRequest = new PageRequest(0, 10, OrderBy.DESC); 52 | const testTxHash = "D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A"; 53 | const testTxResultResponse = transactionResult; 54 | 55 | stub = new MockAdapter(httpClient.getAxiosInstance()); 56 | 57 | stub.onGet(`/v2/wallets/${testAddress}/transactions`).reply(config => { 58 | HttpTestUtil.assertHeaders(config.headers); 59 | HttpTestUtil.assertPageParameters(config.params, pageRequest); 60 | return [200, testTxResultResponse]; 61 | }); 62 | 63 | const response = await httpClient.walletTransactionsV2(testAddress, pageRequest); 64 | 65 | expect(response["statusCode"]).to.equal(1000); 66 | expect(response["responseData"][0]["summary"]).to.deep.equal(testTxResultResponse.responseData[0]["summary"]); 67 | }); 68 | 69 | it("transaction result v2 api test", async () => { 70 | const testTxHash = "D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A"; 71 | const testTxResultResponse = singleTransactionResult; 72 | 73 | stub = new MockAdapter(httpClient.getAxiosInstance()); 74 | 75 | stub.onGet(`/v2/transactions/${testTxHash}`).reply(config => { 76 | HttpTestUtil.assertHeaders(config.headers); 77 | return [200, testTxResultResponse]; 78 | }); 79 | 80 | const response = await httpClient.transactionResultV2(testTxHash); 81 | expect(response["statusCode"]).to.equal(1000); 82 | expect(response["responseData"]["summary"]).to.deep.equal(testTxResultResponse.responseData["summary"]); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /test/http-test-util.ts: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import * as chai from "chai"; 3 | 4 | const expect = chai.expect; 5 | import { Constant } from "../lib/constants"; 6 | import { PageRequest } from "../lib/request"; 7 | 8 | export class HttpTestUtil { 9 | private constructor() {} 10 | 11 | public static assertHeaders(headers: any) { 12 | expect(headers).to.have.any.keys(Constant.SERVICE_API_KEY_HEADER); 13 | expect(headers).to.have.any.keys(Constant.NONCE_HEADER); 14 | expect(headers).to.have.any.keys(Constant.SIGNATURE_HEADER); 15 | expect(headers).to.have.any.keys(Constant.TIMESTAMP_HEADER); 16 | } 17 | 18 | public static assertPageParameters(pageParameters: any, pageRequest: PageRequest) { 19 | expect(pageParameters["page"]).to.equal(pageRequest.page); 20 | expect(pageParameters["limit"]).to.equal(pageRequest.limit); 21 | expect(pageParameters["orderBy"]).to.equal(pageRequest.orderBy); 22 | } 23 | 24 | public static assertParameters(configParams: any, params: any) { 25 | console.log("configParams: " + JSON.stringify(configParams)); 26 | _.forOwn(params, (value, key) => { 27 | console.log(`key:${key}, value: ${value}`); 28 | expect(configParams[key]).to.equal(value); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/lbd-tx-result-adapter.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from "mocha"; 2 | import { HrpPrefix } from "../lib/constants"; 3 | import { LbdTxResultAdapterV1, TxResultAdapter } from "../lib/tx-result-adapters"; 4 | import { RawTransactionResult } from "../lib/tx-raw-models"; 5 | import { TxResult, TxSigner } from "../lib/tx-core-models"; 6 | import { accountMsgEmptyTxResult, baseCoinTransferTxResult, createAccountTxResult } from "./test-data"; 7 | import { expect } from "chai"; 8 | import _ from "lodash"; 9 | 10 | describe("LbdTxResultAdapterV1 test", () => { 11 | let underTest: TxResultAdapter = new LbdTxResultAdapterV1(HrpPrefix.TEST_NET); 12 | 13 | it("test baseCoinTransferTxResult", () => { 14 | let inputRawTxResult = baseCoinTransferTxResult; 15 | let lbdTxResult = underTest.adapt(inputRawTxResult); 16 | expect(lbdTxResult.summary.height).to.equal(inputRawTxResult.height); 17 | expect(lbdTxResult.summary.txHash).to.equal(inputRawTxResult.txhash); 18 | expect(lbdTxResult.summary.txIndex).to.equal(inputRawTxResult.index); 19 | expect(lbdTxResult.summary.signers).to.deep.include(new TxSigner("tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq")); 20 | expect(lbdTxResult.txMessages).to.be.not.empty; 21 | expect(lbdTxResult.txEvents).to.be.not.empty; 22 | expect(_.first(Array.from(lbdTxResult.txEvents))?.["eventName"]).to.equal("EventCoinTransferred"); 23 | }); 24 | 25 | it("test createAccountTxResult", () => { 26 | let inputRawTxResult = createAccountTxResult; 27 | let lbdTxResult = underTest.adapt(inputRawTxResult); 28 | expect(lbdTxResult.summary.height).to.equal(inputRawTxResult.height); 29 | expect(lbdTxResult.summary.txHash).to.equal(inputRawTxResult.txhash); 30 | expect(lbdTxResult.summary.txIndex).to.equal(inputRawTxResult.index); 31 | expect(lbdTxResult.txMessages).to.be.not.empty; 32 | expect(lbdTxResult.txEvents).to.be.not.empty; 33 | expect(_.first(Array.from(lbdTxResult.txEvents))?.["eventName"]).to.equal("EventAccountCreated"); 34 | }); 35 | 36 | it("test accountMsgEmptyTxResult", () => { 37 | let inputRawTxResult = accountMsgEmptyTxResult; 38 | let lbdTxResult = underTest.adapt(inputRawTxResult); 39 | expect(lbdTxResult.summary.height).to.equal(inputRawTxResult.height); 40 | expect(lbdTxResult.summary.txHash).to.equal(inputRawTxResult.txhash); 41 | expect(lbdTxResult.summary.txIndex).to.equal(inputRawTxResult.index); 42 | expect(lbdTxResult.txMessages).to.be.not.empty; 43 | expect(lbdTxResult.txEvents).to.be.not.empty; 44 | expect(_.first(Array.from(lbdTxResult.txEvents))?.["eventName"]).to.equal("EventEmptyMsgCreated"); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/lbd-tx-summary-adapter.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { HrpPrefix } from "../lib/constants"; 4 | import { TxSigner, TxSuccessResult } from "../lib/tx-core-models"; 5 | import { LbdTxSummaryAdapterV1 } from "../lib/tx-result-adapters"; 6 | import { baseCoinTransferTxResult } from "./test-data"; 7 | 8 | describe("lbd-tx-result-summary-adapter test", () => { 9 | it("with baseCoinTransferTxResult", () => { 10 | let inputRawTxResult = baseCoinTransferTxResult; 11 | let lbdTxResultSummary = new LbdTxSummaryAdapterV1(HrpPrefix.TEST_NET).adapt(inputRawTxResult); 12 | 13 | expect(inputRawTxResult.height).to.equal(lbdTxResultSummary.height); 14 | expect(inputRawTxResult.txhash).to.equal(lbdTxResultSummary.txHash); 15 | expect(inputRawTxResult.index).to.equal(lbdTxResultSummary.txIndex); 16 | expect(inputRawTxResult.code).to.equal(lbdTxResultSummary.result.code); 17 | expect(inputRawTxResult.codespace).to.equal(lbdTxResultSummary.result.codeSpace); 18 | expect(TxSuccessResult.SUCCEEDED).to.equal(lbdTxResultSummary.result.result); 19 | 20 | let expectedSigners = [new TxSigner("tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq")]; 21 | expect(expectedSigners).to.deep.equal(lbdTxResultSummary.signers); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/raw-event-types-util.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { RawMessageEventKeyType, RawMessageEventKeyTypes, RawMessageEventKeyTypeUtil } from "../lib/tx-raw-models"; 4 | 5 | describe("RawEventTypesUtil tests", () => { 6 | it("test convertToEventType with AccountMsgCreateAccount", () => { 7 | let matchedTypeValue = "account/MsgCreateAccount"; 8 | let actualValue: RawMessageEventKeyType = RawMessageEventKeyTypeUtil.convertToEventType(matchedTypeValue); 9 | 10 | let expectedValue: RawMessageEventKeyType = RawMessageEventKeyTypes.AccountMsgCreateAccount; 11 | expect(expectedValue).to.equal(actualValue); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/raw-transaction-event.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { 4 | RawTransactionEvent, 5 | RawTransactionEventUtil, 6 | RawTransactionEventAttribute, 7 | EventAttributeType, 8 | EventAttributeUtil, 9 | EventAttributeTypes, 10 | } from "../lib/tx-raw-models"; 11 | 12 | describe("RawTransactionEvent test", () => { 13 | it("test findAttributeNotNull with unknown eventAttributeType", () => { 14 | let defaultValue = ""; 15 | let attributes = [new RawTransactionEventAttribute("amount", "120000")]; 16 | let rawTransactionEvent = new RawTransactionEvent("test-type", attributes); 17 | 18 | let testEventAttributeType: EventAttributeType = { 19 | names: ["unknown"], 20 | matches(attributeName: string): boolean { 21 | return EventAttributeUtil.hasMatchedAttribute(this.names, attributeName); 22 | }, 23 | }; 24 | 25 | let actualValue = RawTransactionEventUtil.findAttributeNotNull( 26 | rawTransactionEvent, 27 | testEventAttributeType, 28 | defaultValue, 29 | ); 30 | let expectedValue = defaultValue; 31 | expect(expectedValue).to.equal(actualValue); 32 | }); 33 | 34 | it("test findAttributeNotNull with amount eventAttributeType", () => { 35 | let attributes = [new RawTransactionEventAttribute("amount", "120000")]; 36 | let rawTransactionEvent = new RawTransactionEvent("test-type", attributes); 37 | 38 | let testEventAttributeType = EventAttributeTypes.Amount; 39 | let actualValue = RawTransactionEventUtil.findAttributeNotNull(rawTransactionEvent, testEventAttributeType, ""); 40 | let expectedValue = "120000"; 41 | expect(expectedValue).to.equal(actualValue); 42 | }); 43 | 44 | it("test findAttributeNotNull with from eventAttributeType", () => { 45 | let attributes = [new RawTransactionEventAttribute("from", "test-from-address")]; 46 | let rawTransactionEvent = new RawTransactionEvent("from", attributes); 47 | 48 | let testEventAttributeType = EventAttributeTypes.From; 49 | let actualValue = RawTransactionEventUtil.findAttributeNotNull(rawTransactionEvent, testEventAttributeType, ""); 50 | let expectedValue = "test-from-address"; 51 | expect(expectedValue).to.equal(actualValue); 52 | }); 53 | 54 | it("test findAttributeNotNull with approver eventAttributeType", () => { 55 | let attributes = [new RawTransactionEventAttribute("approver", "test-approver-address")]; 56 | let rawTransactionEvent = new RawTransactionEvent("approver", attributes); 57 | 58 | let testEventAttributeType = EventAttributeTypes.Approver; 59 | let actualValue = RawTransactionEventUtil.findAttributeNotNull(rawTransactionEvent, testEventAttributeType, ""); 60 | let expectedValue = "test-approver-address"; 61 | expect(expectedValue).to.equal(actualValue); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/raw-transaction-result.spc.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { RawTransactionResult } from "../lib/tx-raw-models"; 4 | import { baseCoinTransferTxResult, accountMsgEmptyTxResult } from "./test-data"; 5 | 6 | describe("RawTransactionResult test", () => { 7 | it("test baseCoinTransferTxResult", () => { 8 | let rawTransactionResult: RawTransactionResult = baseCoinTransferTxResult; 9 | expect(53310).to.equal(rawTransactionResult.height); 10 | }); 11 | 12 | it("test accountMsgEmptyTxResult", () => { 13 | let rawTransactionResult: RawTransactionResult = accountMsgEmptyTxResult; 14 | expect(1207045).to.equal(rawTransactionResult.height); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/raw-tx-result-adapter.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { baseCoinTransferTxResult } from "./test-data"; 4 | import { LbdTxEventsAdapterV1, RawTransactionResultAdapter } from "../lib/tx-result-adapters"; 5 | import { EventCoinTransferred } from "../lib/tx-core-models"; 6 | 7 | describe("raw-tx-result-adapter test", () => { 8 | it("with baseCoinTransferTxResult", () => { 9 | let inputTxResultResponse = baseCoinTransferTxResult; 10 | let rawTransactionResult = new RawTransactionResultAdapter().adapt(inputTxResultResponse); 11 | expect(inputTxResultResponse.height).to.equal(rawTransactionResult.height); 12 | 13 | let adapter = new LbdTxEventsAdapterV1(); 14 | 15 | let actual = adapter.adapt(rawTransactionResult); 16 | 17 | expect(1).to.equal(actual.length); 18 | 19 | let event = actual.values().next().value; 20 | expect(EventCoinTransferred.name).to.equal(event.constructor.name); 21 | let eventCoinTransferred: EventCoinTransferred = event; 22 | 23 | let expectedValue = new EventCoinTransferred( 24 | 0, 25 | "tcony", 26 | "1", 27 | "tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq", 28 | "tlink1nf5uhdmtsshmkqvlmq45kn4q9atnkx4l3u4rww", 29 | ); 30 | 31 | expect(expectedValue).to.deep.equal(eventCoinTransferred); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/request-body-flattener.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | 4 | import _ from "lodash"; 5 | 6 | import { RequestBodyFlattener } from "../lib/request-body-flattener"; 7 | 8 | describe("request-body-flatten test", () => { 9 | it("flatten request body with mint-list parameter value test", () => { 10 | let req_params = { 11 | ownerAddress: "tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq", 12 | ownerSecret: "uhbdnNvIqQFnnIFDDG8EuVxtqkwsLtDR/owKInQIYmo=", 13 | toAddress: "tlink18zxqds28mmg8mwduk32csx5xt6urw93ycf8jwp", 14 | mintList: [ 15 | { 16 | tokenType: "10000001", 17 | name: "NewNFT", 18 | }, 19 | { 20 | tokenType: "10000003", 21 | name: "NewNFT2", 22 | meta: "New nft 2 meta information", 23 | }, 24 | ], 25 | }; 26 | 27 | let flatten_req_params = 28 | "mintList.meta=,New nft 2 meta information&mintList.name=NewNFT,NewNFT2&mintList.tokenType=10000001,10000003&ownerAddress=tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq&ownerSecret=uhbdnNvIqQFnnIFDDG8EuVxtqkwsLtDR/owKInQIYmo=&toAddress=tlink18zxqds28mmg8mwduk32csx5xt6urw93ycf8jwp"; 29 | 30 | let flatten = RequestBodyFlattener.flatten(req_params); 31 | expect(flatten).to.equal(flatten_req_params); 32 | }); 33 | 34 | it("flatten request body with mint-list with multi receivers test", () => { 35 | const req_params = { 36 | ownerAddress: "tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7", 37 | ownerSecret: "vPnwd8QBC/M4ZgKAYAJjiBEskLvbWvpkysQl1WQtthc=", 38 | mintList: [ 39 | { 40 | toAddress: "tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7", 41 | tokenType: "10000001", 42 | name: "aiEw", 43 | meta: "viz23", 44 | }, 45 | { 46 | toUserId: "U9cd1b4384f912279b17765e0b1847c99", 47 | tokenType: "10000001", 48 | name: "IEjfz", 49 | meta: "viz23", 50 | }, 51 | ], 52 | }; 53 | 54 | const flatten_req_params = 55 | "mintList.meta=viz23,viz23&mintList.name=aiEw,IEjfz&mintList.toAddress=tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7,&mintList.toUserId=,U9cd1b4384f912279b17765e0b1847c99&mintList.tokenType=10000001,10000001&ownerAddress=tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7&ownerSecret=vPnwd8QBC/M4ZgKAYAJjiBEskLvbWvpkysQl1WQtthc="; 56 | // const flatten_req_params = 57 | // "mintList.meta=viz23,viz23&mintList.name=aiEw,IEjfz&mintList.toAddress=tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7&mintList.toUserId=,U9cd1b4384f912279b17765e0b1847c99&mintList.tokenType=10000001,10000001&ownerAddress=tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7&ownerSecret=vPnwd8QBC/M4ZgKAYAJjiBEskLvbWvpkysQl1WQtthc="; 58 | 59 | const flatten = RequestBodyFlattener.flatten(req_params); 60 | expect(flatten).to.equal(flatten_req_params); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/request-parameter-validator.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { RequestParameterValidator } from "../lib/request-parameter-validator"; 4 | 5 | describe("request-parameter validator test - token name", () => { 6 | it("validate token name with valid name", () => { 7 | let validTokenName = "TestToken1"; 8 | let isValid = RequestParameterValidator.isValidTokenName(validTokenName); 9 | expect(isValid).to.equal(true); 10 | }); 11 | 12 | it("validate token name with invalid name - with not alpha numeric chars", () => { 13 | let validTokenName = "TestToken1_"; 14 | let isValid = RequestParameterValidator.isValidTokenName(validTokenName); 15 | expect(isValid).to.equal(false); 16 | }); 17 | 18 | it("validate token name with invalid name - too small characters", () => { 19 | let validTokenName = "Te"; 20 | let isValid = RequestParameterValidator.isValidTokenName(validTokenName); 21 | expect(isValid).to.equal(false); 22 | }); 23 | 24 | it("validate token name with invalid name - over length limit", () => { 25 | let validTokenName = "a12345678901234567890"; 26 | let isValid = RequestParameterValidator.isValidTokenName(validTokenName); 27 | expect(isValid).to.equal(false); 28 | }); 29 | 30 | it("validate token name with invalid name - empty", () => { 31 | let validTokenName = ""; 32 | let isValid = RequestParameterValidator.isValidTokenName(validTokenName); 33 | expect(isValid).to.equal(false); 34 | }); 35 | }); 36 | 37 | describe("request-parameter validator test - token symbol", () => { 38 | it("validate token symbol with valid symbol", () => { 39 | let validTokenSymbol = "TEST"; 40 | let isValid = RequestParameterValidator.isValidSymbol(validTokenSymbol); 41 | expect(isValid).to.equal(true); 42 | }); 43 | 44 | it("validate token symbol with invalid symbol - with not alpha numeric chars", () => { 45 | let validTokenSymbol = "TEST_"; 46 | let isValid = RequestParameterValidator.isValidSymbol(validTokenSymbol); 47 | expect(isValid).to.equal(false); 48 | }); 49 | 50 | it("validate token symbol with invalid symbol - with not capital chars", () => { 51 | let validTokenSymbol = "TESTa"; 52 | let isValid = RequestParameterValidator.isValidSymbol(validTokenSymbol); 53 | expect(isValid).to.equal(false); 54 | }); 55 | 56 | it("validate token symbol with invalid symbol - too small characters", () => { 57 | let validTokenSymbol = "T"; 58 | let isValid = RequestParameterValidator.isValidSymbol(validTokenSymbol); 59 | expect(isValid).to.equal(false); 60 | }); 61 | 62 | it("validate token symbol with invalid symbol - over length limit", () => { 63 | let validTokenSymbol = "TEST12"; 64 | let isValid = RequestParameterValidator.isValidSymbol(validTokenSymbol); 65 | expect(isValid).to.equal(false); 66 | }); 67 | 68 | it("validate token symbol with invalid symbol - empty", () => { 69 | let validTokenSymbol = ""; 70 | let isValid = RequestParameterValidator.isValidSymbol(validTokenSymbol); 71 | expect(isValid).to.equal(false); 72 | }); 73 | }); 74 | 75 | describe("request-parameter validator test - token initialSupply", () => { 76 | it("validate token initialSupply with valid initialSupply", () => { 77 | let validTokenInitialSupply = "10000"; 78 | let isValid = RequestParameterValidator.isValidInitialSupply(validTokenInitialSupply); 79 | expect(isValid).to.equal(true); 80 | }); 81 | 82 | it("validate token initialSupply with invalid initialSupply - with not alpha numeric chars", () => { 83 | let invalidTokenInitialSupply = "TEST_"; 84 | let isValid = RequestParameterValidator.isValidInitialSupply(invalidTokenInitialSupply); 85 | expect(isValid).to.equal(false); 86 | }); 87 | 88 | it("validate token initialSupply with invalid initialSupply - empty", () => { 89 | let invalidTokenInitialSupply = ""; 90 | let isValid = RequestParameterValidator.isValidInitialSupply(invalidTokenInitialSupply); 91 | expect(isValid).to.equal(false); 92 | }); 93 | }); 94 | 95 | describe("request-parameter validator test - wallet address", () => { 96 | it("validate token wallet address with the valid", () => { 97 | let validWalletAddress = "tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7"; 98 | let isValid = RequestParameterValidator.isValidWalletAddress(validWalletAddress); 99 | expect(isValid).to.equal(true); 100 | }); 101 | 102 | it("validate token wallet address with the invalid - short length", () => { 103 | let invalidTokenInitialSupply = "tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk"; 104 | let isValid = RequestParameterValidator.isValidInitialSupply(invalidTokenInitialSupply); 105 | expect(isValid).to.equal(false); 106 | }); 107 | 108 | it("validate token wallet address with the invalid - invalid prefix", () => { 109 | let invalidTokenInitialSupply = "test145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk"; 110 | let isValid = RequestParameterValidator.isValidInitialSupply(invalidTokenInitialSupply); 111 | expect(isValid).to.equal(false); 112 | }); 113 | 114 | it("validate token wallet address with the invalid - empty", () => { 115 | let invalidTokenInitialSupply = ""; 116 | let isValid = RequestParameterValidator.isValidInitialSupply(invalidTokenInitialSupply); 117 | expect(isValid).to.equal(false); 118 | }); 119 | }); 120 | 121 | describe("request-parameter validator test - baseUri", () => { 122 | it("validate token baseUri with the valid", () => { 123 | let validBaseUri = "https://test-image-server.com:3000/"; 124 | let isValid = RequestParameterValidator.isValidBaseUri(validBaseUri); 125 | expect(isValid).to.equal(true); 126 | }); 127 | 128 | it("validate token baseUri with the invalid - invalid protocol", () => { 129 | let validBaseUri = "http://test-image-server:3000.com/"; 130 | let isValid = RequestParameterValidator.isValidBaseUri(validBaseUri); 131 | expect(isValid).to.equal(false); 132 | }); 133 | 134 | it("validate token baseUri with the invalid - empty", () => { 135 | let validBaseUri = ""; 136 | let isValid = RequestParameterValidator.isValidBaseUri(validBaseUri); 137 | expect(isValid).to.equal(true); 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /test/request.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { IssueServiceTokenRequest } from "../lib/request"; 4 | 5 | describe("request objects tests", () => { 6 | it("given all valid values, create IssueServiceTokenRequest", () => { 7 | expect( 8 | () => 9 | new IssueServiceTokenRequest( 10 | "tlink14vvjtkr39ssmy9qrhv7egrxw8kg5ylpj6l07r8", 11 | "test-secret", 12 | "test", 13 | "TEST", 14 | "1000", 15 | "tlink14vvjtkr39ssmy9qrhv7egrxw8kg5ylpj6l07r8", 16 | ), 17 | ).to.not.throw(Error); 18 | }); 19 | it("given invalid so wallet address, fail to create IssueServiceTokenRequest", () => { 20 | expect( 21 | () => 22 | new IssueServiceTokenRequest( 23 | "invalid-address", 24 | "test-secret", 25 | "test", 26 | "TEST", 27 | "1000", 28 | "tlink14vvjtkr39ssmy9qrhv7egrxw8kg5ylpj6l07r8", 29 | ), 30 | ).to.throw(Error); 31 | }); 32 | 33 | it("given invalid receiver wallet address, fail to create IssueServiceTokenRequest", () => { 34 | expect( 35 | () => 36 | new IssueServiceTokenRequest( 37 | "tlink14vvjtkr39ssmy9qrhv7egrxw8kg5ylpj6l07r8", 38 | "test-secret", 39 | "test", 40 | "TEST", 41 | "1000", 42 | "invalid-address", 43 | ), 44 | ).to.throw(Error); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/sinature-generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { SignatureGenerator } from "../lib/signature-generator"; 4 | 5 | describe("signature-generator test", () => { 6 | // it('signature without parameters test', () => { 7 | // let method = "GET" 8 | // let path = "/v1/wallets" 9 | // let timestamp = 1581850266351 10 | // let secret = "9256bf8a-2b86-42fe-b3e0-d3079d0141fe" 11 | // let nonce = "Bp0IqgXE" 12 | // let signature = SignatureGenerator.signature(secret, method, path, timestamp, nonce) 13 | // expect(signature).to.equal("2LtyRNI16y/5/RdoTB65sfLkO0OSJ4pCuz2+ar0npkRbk1/dqq1fbt1FZo7fueQl1umKWWlBGu/53KD2cptcCA==") 14 | // }); 15 | // 16 | // it('signature without parameters test2', () => { 17 | // let method = "GET" 18 | // let path = "/v1/wallets" 19 | // let timestamp = 1611911260000 20 | // let secret = "4bd950dc-329f-40e7-a0d6-6bbe7e7201e9" 21 | // let nonce = "7wqcvYVf" 22 | // let signature = SignatureGenerator.signature(secret, method, path, timestamp, nonce) 23 | // expect(signature).to.equal("fCePTa/ggRQBK5Hq5LI/GeqO/FG5DlBzEq1HzVMz0gsZfE6+jCeHf0mCJL3rhkmjzlos44jxx4julZ2frpFZOA==") 24 | // }); 25 | // 26 | // it('signature with parameters test', () => { 27 | // let parameters = { 28 | // "page": 2, 29 | // "msgType": "coin/MsgSend" 30 | // }; 31 | // 32 | // let method = "GET" 33 | // let path = "/v1/wallets/tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq/transactions" 34 | // let timestamp = 1581850266351 35 | // let secret = "9256bf8a-2b86-42fe-b3e0-d3079d0141fe" 36 | // let nonce = "Bp0IqgXE" 37 | // let signature = SignatureGenerator.signature(secret, method, path, timestamp, nonce, parameters) 38 | // expect(signature).to.equal("5x6bEV1mHkpJpEJMnMsCUH7jV5GzKzA038UwcqpYIAx7Zn1SvA9qhdf+aitu+3juXzXB+qSxM4zRon6/aNVMFg==") 39 | // }); 40 | // 41 | // it('signature with paing parameters test', () => { 42 | // // paging parameters sorted by its key when generating signature 43 | // let parameters = { 44 | // "limit": 10, 45 | // "page": 1, 46 | // "orderBy": "desc" 47 | // }; 48 | // 49 | // let method = "GET" 50 | // let path = "/v1/service-tokens/a48f097b/holders" 51 | // let timestamp = 1611243023551 52 | // let secret = "098d8862-477d-49f2-928f-7655489be2d3" 53 | // let nonce = "KScYbbH0" 54 | // // sign-target will be "KScYbbH01611243023551GET/v1/service-tokens/a48f097b/holders?limit=10&orderBy=desc&page=1" 55 | // let signature = SignatureGenerator.signature(secret, method, path, timestamp, nonce, parameters) 56 | // expect(signature).to.equal("8vcqBHXiwGaP5+78ZvuidcoZ/UiKnR1IrgXKzUaRf+HqetD5eHMaeTEW3OvHoKn7Z512WVNuKmRQDW88DvJ1aA==") 57 | // }); 58 | 59 | it("signature with all parameters test", () => { 60 | // paging parameters sorted by its key when generating signature 61 | let parameters = { 62 | limit: 10, 63 | page: 0, 64 | orderBy: "desc", 65 | msgType: "collection/MsgTransferNFTFrom", 66 | after: 1614563991000, 67 | before: 1617155991000, 68 | }; 69 | 70 | let method = "GET"; 71 | let path = "/v1/wallets/tlink1ey2p39e4l78h49pm28z5ms62ycd06sgrprtps5/transactions"; 72 | let timestamp = 1617503164770; 73 | let secret = "7d55f1f5-0f6f-426e-909c-47913aa09e72"; 74 | let nonce = "805d1b42"; 75 | // sign-target will be "805d1b421617503164770GET/v1/wallets/tlink1ey2p39e4l78h49pm28z5ms62ycd06sgrprtps5/transactions?after=1614563991000&before=1617155991000&limit=10&msgType=collection/MsgTransferNFTFrom&orderBy=desc&page=0" 76 | let signature = SignatureGenerator.signature(secret, method, path, timestamp, nonce, parameters); 77 | expect(signature).to.equal( 78 | "Iq4lDCgzMmtFrZHuE0b7Xu6PqaqnoVJlG2WxMtuAHWuB8hoG98swyb578LMZMUbHLE3D1ldQA1U4hxSPyxiFSA==", 79 | ); 80 | }); 81 | 82 | // it('signature with query parameters and body test', () => { 83 | // // paging parameters sorted by its key when generating signature 84 | // let queryParameters = { 85 | // "requestType": "aoa" 86 | // }; 87 | // 88 | // let request_body = { 89 | // 'ownerAddress': "tlink1ey2p39e4l78h49pm28z5ms62ycd06sgrprtps5", 90 | // 'landingUri': 'https://my.service.landing/home' 91 | // } 92 | // 93 | // let method = "POST" 94 | // let path = "/v1/users/U9fc03e78e1ae958b1bd3633cfb48acb9/service-tokens/493aba33/request-proxy" 95 | // let timestamp = 1615593846507 96 | // let secret = "7d55f1f5-0f6f-426e-909c-47913aa09e72" 97 | // let nonce = "fcd9cf1a" 98 | // // sign-target will be "KScYbbH01611243023551GET/v1/service-tokens/a48f097b/holders?limit=10&orderBy=desc&page=1" 99 | // let signature = SignatureGenerator.signature(secret, method, path, timestamp, nonce, queryParameters, request_body) 100 | // expect(signature).to.equal("hnb+iDG0PPgoByLaUCPtVv5GqcJO1fcKgTO5VolKTITqpRIux7wvCE2d07eY+xXW/553Vq5wLiZ2lX8dZBIOhw==") 101 | // }); 102 | }); 103 | -------------------------------------------------------------------------------- /test/string-util.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { StringUtil } from "../lib/string-util"; 4 | 5 | describe("StringUtil tests", () => { 6 | it("test parseAmount", () => { 7 | var testAmount = "1:tcony"; 8 | var parseAmount = StringUtil.parseAmount(testAmount); 9 | expect("1").to.equal(parseAmount.amount); 10 | expect("tcony").to.equal(parseAmount.denomination); 11 | 12 | testAmount = "1000000:tcony"; 13 | parseAmount = StringUtil.parseAmount(testAmount); 14 | expect("1000000").to.equal(parseAmount.amount); 15 | expect("tcony").to.equal(parseAmount.denomination); 16 | 17 | testAmount = "1000000tcony"; 18 | parseAmount = StringUtil.parseAmount(testAmount); 19 | expect("1000000").to.equal(parseAmount.amount); 20 | expect("tcony").to.equal(parseAmount.denomination); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/test-data-v2.ts: -------------------------------------------------------------------------------- 1 | export const transactionResult = { 2 | responseTime: 1585467706110, 3 | statusCode: 1000, 4 | statusMessage: "Success", 5 | responseData: [ 6 | { 7 | summary: { 8 | height: 241476, 9 | txIndex: 2, 10 | txHash: "D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A", 11 | signers: ["tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq"], 12 | result: { 13 | code: 0, 14 | codeSpace: "collection", 15 | }, 16 | }, 17 | txMessages: [ 18 | { 19 | msgIndex: 0, 20 | requestType: "collection/MsgTransferNFT", 21 | details: { 22 | from: "tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq", 23 | contractId: "61e14383", 24 | to: "tlink1s658utvasn7f5q92034h6zgv0zh2uxy9tzmtqv", 25 | tokenIds: ["1000000100000001"], 26 | }, 27 | }, 28 | ], 29 | txEvents: [ 30 | { 31 | eventName: "EventCollectionNftTransferred", 32 | msgIndex: 0, 33 | contractId: "", 34 | tokenIds: [], 35 | fromAddress: "", 36 | toAddress: "", 37 | }, 38 | ], 39 | }, 40 | ], 41 | }; 42 | 43 | export const singleTransactionResult = { 44 | responseTime: 1585467706110, 45 | statusCode: 1000, 46 | statusMessage: "Success", 47 | responseData: { 48 | summary: { 49 | height: 241476, 50 | txIndex: 2, 51 | txHash: "D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A", 52 | signers: ["tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq"], 53 | result: { 54 | code: 0, 55 | codeSpace: "collection", 56 | }, 57 | }, 58 | txMessages: [ 59 | { 60 | msgIndex: 0, 61 | requestType: "collection/MsgTransferNFT", 62 | details: { 63 | from: "tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq", 64 | contractId: "61e14383", 65 | to: "tlink1s658utvasn7f5q92034h6zgv0zh2uxy9tzmtqv", 66 | tokenIds: ["1000000100000001"], 67 | }, 68 | }, 69 | ], 70 | txEvents: [ 71 | { 72 | eventName: "EventCollectionNftTransferred", 73 | msgIndex: 0, 74 | contractId: "", 75 | tokenIds: [], 76 | fromAddress: "", 77 | toAddress: "", 78 | }, 79 | ], 80 | }, 81 | }; 82 | -------------------------------------------------------------------------------- /test/tx-core-models.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | 4 | import { 5 | TransactionEvent, 6 | TxMessage, 7 | TxResult, 8 | TxResultSummary, 9 | TxSigner, 10 | TxStatusResult, 11 | } from "../lib/tx-core-models"; 12 | 13 | describe("core tx model tests", () => { 14 | it("build core models", () => { 15 | let txSigner = new TxSigner("tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7"); 16 | 17 | let txStatusResult = new TxStatusResult(0, ""); 18 | let txMessage = new TxMessage(0, "test"); 19 | let txEvent: TransactionEvent = { 20 | eventName: "TestEvent", 21 | }; 22 | 23 | let txResultSummary = new TxResultSummary( 24 | 0, 25 | 0, 26 | "D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A", 27 | [txSigner], 28 | txStatusResult, 29 | ); 30 | 31 | let txResult = new TxResult(txResultSummary, [txMessage], [txEvent]); 32 | 33 | let expectedTxResultJson = 34 | '{"summary":{"height":0,"txIndex":0,"txHash":"D3833E2CED77A11639D03EC3DF4B0EC9B77EBFF48795B7151D5201439738031A","signers":[{"address":"tlink145knu8tlpjmx9gsf0dxxfdcr68a4sapv5x6tk7"}],"result":{"code":0,"codeSpace":"","result":"SUCCEEDED"}},"txMessages":[{"msgIndex":0,"requestType":"test","details":{}}],"txEvents":[{"eventName":"TestEvent"}]}'; 35 | expect(JSON.stringify(txResult.toJson())).to.equal(expectedTxResultJson); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/tx-result-code-mappings-prvider.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { TxResultCodeMappingsProvider, TxResultType } from "../lib/tx-result-codes"; 4 | import { transferFromNonFungibleTxResult, failedTransferFromNonFungibleTxResult } from "./test-data"; 5 | 6 | describe("txResultMessageParserFactory-test", () => { 7 | it("test get tx-result-codes", () => { 8 | expect(TxResultCodeMappingsProvider.codes("bank")[1].isSuccess()).to.false; 9 | expect(TxResultType.FAIL).to.equal(TxResultCodeMappingsProvider.codes("bank")[1].txResultType()); 10 | expect(1).to.equal(TxResultCodeMappingsProvider.codes("bank")[1].code); 11 | expect('No "inputs" for "send" type transaction', TxResultCodeMappingsProvider.codes("bank")[1].description); 12 | }); 13 | 14 | it("test get tx-result-code from successful txResult", () => { 15 | const txResultCode = TxResultCodeMappingsProvider.code(transferFromNonFungibleTxResult); 16 | expect(txResultCode.isSuccess()).to.true; 17 | expect(TxResultType.SUCCESS).to.equal(txResultCode.txResultType()); 18 | expect(0).to.equal(txResultCode.code); 19 | expect("").to.equal(txResultCode.description); 20 | }); 21 | 22 | it("test get tx-result-code from failed txResult", () => { 23 | const txResultCode = TxResultCodeMappingsProvider.code(failedTransferFromNonFungibleTxResult); 24 | expect(txResultCode.isSuccess()).to.false; 25 | expect(TxResultType.FAIL).to.equal(txResultCode.txResultType()); 26 | expect(23).to.equal(txResultCode.code); 27 | expect("Token is being not owned.").to.equal(txResultCode.description); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/tx-result-util.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { describe, it } from "mocha"; 3 | import { TxResultUtil } from "../lib/tx-result-util"; 4 | import { serviceTokenBurnFromTxResult, singleTransactionResult } from "./test-data"; 5 | 6 | describe("tx-result-util test with tx message", () => { 7 | const singleTransactionResultResponse = singleTransactionResult.responseData; 8 | // it("findFromWalletAddress test", () => { 9 | // const fromAddress = TxResultUtil.findFromWalletAddress( 10 | // singleTransactionResultResponse, 11 | // ); 12 | // expect("tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq").to.equal( 13 | // fromAddress, 14 | // ); 15 | // }); 16 | 17 | // it("findFromWalletAddress test", () => { 18 | // const ownerAddress = TxResultUtil.findOwnerWalletAddress( 19 | // nftUpdateTxResultResponse, 20 | // ); 21 | // expect("tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq").to.equal( 22 | // ownerAddress, 23 | // ); 24 | // }); 25 | 26 | // it("findChanges test", () => { 27 | // const changes = TxResultUtil.findChanges(nftUpdateTxResultResponse); 28 | // const expectedChanges = [ 29 | // { field: "name", value: "NFT index name" }, 30 | // { field: "meta", value: "NFT index meta" }, 31 | // ]; 32 | // expectedChanges.forEach((it, index) => { 33 | // expect(it.field).to.equal(changes[index].field); 34 | // expect(it.value).to.equal(changes[index].value); 35 | // }); 36 | // }); 37 | 38 | // it("findAmount test", () => { 39 | // const amount = TxResultUtil.findAmount(serviceTokenMintTxResult); 40 | // expect("1000").to.equal(amount); 41 | // }); 42 | 43 | // it("findToWalletAddress test", () => { 44 | // const toAddress = TxResultUtil.findToWalletAddress( 45 | // singleTransactionResultResponse, 46 | // ); 47 | // expect("tlink1s658utvasn7f5q92034h6zgv0zh2uxy9tzmtqv").to.equal(toAddress); 48 | // }); 49 | 50 | // it("findProxyWalletAddress test", () => { 51 | // const toAddress = TxResultUtil.findProxyWalletAddress( 52 | // serviceTokenTransferFromTxResult, 53 | // ); 54 | // expect("tlink1xrr7amq5g80afllmfcud59y3w60q58llx2zpe9").to.equal(toAddress); 55 | // }); 56 | 57 | // it("give no to wallet address, then findToWalletAddress return empty ", () => { 58 | // const toAddress = TxResultUtil.findToWalletAddress( 59 | // nftDetachTxResultResponse, 60 | // ); 61 | // expect("").to.equal(toAddress); 62 | // }); 63 | 64 | // it("given required value in messages, then findValueFromMessages return the value ", () => { 65 | // const contractId = TxResultUtil.findValueFromMessages( 66 | // nftDetachTxResultResponse, 67 | // "contractId", 68 | // ); 69 | // expect("61e14383").to.equal(contractId); 70 | // }); 71 | 72 | // it("given no required value in messages, then findValueFromMessages return the value ", () => { 73 | // const not_exist_but_required = TxResultUtil.findValueFromMessages( 74 | // nftDetachTxResultResponse, 75 | // "not_exist_but_required", 76 | // ); 77 | // expect(null).to.equal(not_exist_but_required); 78 | // }); 79 | 80 | // it("given messages have message with contractId, then findContractId returns the contractId", () => { 81 | // const contractId = TxResultUtil.findContractId(nftUpdateTxResultResponse); 82 | // expect("61e14383").to.equal(contractId); 83 | // }); 84 | 85 | // it("given messages doesn't have message with contractId, then findContractId returns the contractId", () => { 86 | // const contractId = TxResultUtil.findContractId(memoTxResultResponse); 87 | // expect("").to.equal(contractId); 88 | // }); 89 | 90 | // it("given messages have message with tokenType, then findTokenType returns the tokenType", () => { 91 | // const tokenType = TxResultUtil.findTokenType(nftUpdateTxResultResponse); 92 | // expect("10000001").to.equal(tokenType); 93 | // }); 94 | 95 | // it("given messages doesn't have message with contractId, then findTokenType returns the tokenType", () => { 96 | // const tokenType = TxResultUtil.findTokenType(memoTxResultResponse); 97 | // expect("").to.equal(tokenType); 98 | // }); 99 | 100 | // it("given messages have message with tokenId, then findTokenId returns the tokenId", () => { 101 | // const tokenId = TxResultUtil.findTokenId(nftUpdateTxResultResponse); 102 | // expect("1000000100000001").to.equal(tokenId); 103 | // }); 104 | 105 | // it("given messages doesn't have message with tokenId, then findTokenId returns the tokenId", () => { 106 | // const tokenId = TxResultUtil.findTokenId(memoTxResultResponse); 107 | // expect("").to.equal(tokenId); 108 | // }); 109 | 110 | // it("given messages have message with tokenIndex, then findTokenId returns the tokenIndex", () => { 111 | // const tokenIndex = TxResultUtil.findTokenIndex(nftUpdateTxResultResponse); 112 | // expect("00000001").to.equal(tokenIndex); 113 | // }); 114 | 115 | // it("given messages doesn't have message with tokenIndex, then findTokenId returns the tokenIndex", () => { 116 | // const tokenIndex = TxResultUtil.findTokenIndex(memoTxResultResponse); 117 | // expect("").to.equal(tokenIndex); 118 | // }); 119 | // }); 120 | 121 | // describe("tx-result-util test with logs and events", () => { 122 | // it("given there is sender key and value, findValueFromLogEvents return the value", () => { 123 | // const senderWalletAddress = TxResultUtil.findSenderFromLogEvents( 124 | // nftUpdateTxResultResponse, 125 | // ); 126 | // expect("tlink1fr9mpexk5yq3hu6jc0npajfsa0x7tl427fuveq").to.equal( 127 | // senderWalletAddress, 128 | // ); 129 | // }); 130 | 131 | // it("given there is contract_id key and value, findValueFromLogEvents return the value", () => { 132 | // const senderWalletAddress = TxResultUtil.findValueFromLogEvents( 133 | // nftUpdateTxResultResponse, 134 | // "contract_id", 135 | // ); 136 | // expect("61e14383").to.equal(senderWalletAddress); 137 | // }); 138 | 139 | // it("given there is no required key and value, findValueFromLogEvents return empty", () => { 140 | // const senderWalletAddress = TxResultUtil.findValueFromLogEvents( 141 | // nftUpdateTxResultResponse, 142 | // "not_exist_node", 143 | // ); 144 | // expect("").to.equal(senderWalletAddress); 145 | // }); 146 | 147 | it("given service-token-burn-from message, find contractId", () => { 148 | const senderWalletAddress = TxResultUtil.findContractId(serviceTokenBurnFromTxResult); 149 | expect("678c146a").to.equal(senderWalletAddress); 150 | }); 151 | }); 152 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "target": "es2017", 5 | "strict": true, 6 | "outDir": "dist", 7 | "rootDir": "lib", 8 | "moduleResolution": "node", 9 | "module": "commonjs", 10 | "declaration": true, 11 | "esModuleInterop": true 12 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 13 | "resolveJsonModule": true 14 | /* Include modules imported with .json extension. */, 15 | /* Additional Checks */ 16 | "noUnusedParameters": true 17 | /* Report errors on unused parameters. */, 18 | "noImplicitReturns": true 19 | /* Report error when not all code paths in function return a value. */, 20 | "noFallthroughCasesInSwitch": true 21 | /* Report errors for fallthrough cases in switch statement. */, 22 | /* Debugging Options */ 23 | "traceResolution": false 24 | /* Report module resolution log messages. */, 25 | "listEmittedFiles": false 26 | /* Print names of generated files part of the compilation. */, 27 | "listFiles": false 28 | /* Print names of files part of the compilation. */, 29 | "pretty": true 30 | /* Stylize errors and messages using color and context. */, 31 | "lib": [ 32 | "es2017", 33 | "dom" 34 | ], 35 | "types": [ 36 | "chai", 37 | "chai-as-promised", 38 | ], 39 | "typeRoots": [ 40 | "node_modules/@types", 41 | "src/types" 42 | ] 43 | }, 44 | "include": [ 45 | "lib/**/*.ts" 46 | ], 47 | "exclude": [ 48 | "node_modules/**" 49 | ], 50 | "compileOnSave": false 51 | } 52 | --------------------------------------------------------------------------------