├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── test-with-coverage.yml ├── .gitignore ├── .ncurc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── babel.config.js ├── build ├── package.json ├── rollup.cjs.config.js ├── rollup.config.js └── rollup.uglify.config.js ├── jest-bundle-browser-env.js ├── jest-bundle-browser-setup.js ├── jest-bundle-browser.config.js ├── jest-bundle-cjs.config.js ├── jest.config.js ├── minter-logo.svg ├── package-lock.json ├── package.json ├── src ├── api │ ├── estimate-coin-buy.js │ ├── estimate-coin-sell-all.js │ ├── estimate-coin-sell.js │ ├── estimate-tx-commission.js │ ├── get-coin-info.js │ ├── get-commission-price.js │ ├── get-min-gas-price.js │ ├── get-nonce.js │ ├── get-pool-info.js │ ├── index.js │ ├── post-signed-tx.js │ ├── post-tx.js │ └── replace-coin.js ├── check.js ├── index.js ├── link.js ├── minter.js ├── tx-data │ ├── candidacy-declare.js │ ├── candidate-edit-commission.js │ ├── candidate-edit-public-key.js │ ├── candidate-edit.js │ ├── candidate-set-off.js │ ├── candidate-set-on.js │ ├── convert-buy.js │ ├── convert-sell-all.js │ ├── convert-sell.js │ ├── create-coin.js │ ├── create-multisig.js │ ├── edit-multisig.js │ ├── edit-ticker-owner.js │ ├── index.js │ ├── limit-order-add.js │ ├── limit-order-remove.js │ ├── lock.js │ ├── multisend.js │ ├── pool-add-liquidity.js │ ├── pool-buy.js │ ├── pool-create.js │ ├── pool-remove-liquidity.js │ ├── pool-sell-all.js │ ├── pool-sell.js │ ├── recreate-coin.js │ ├── redeem-check.js │ ├── send.js │ ├── stake-delegate.js │ ├── stake-lock.js │ ├── stake-move.js │ ├── stake-unbond.js │ ├── token-burn.js │ ├── token-create.js │ ├── token-mint.js │ ├── token-recreate.js │ ├── vote-commission.js │ ├── vote-halt-block.js │ ├── vote-price.js │ └── vote-update.js ├── tx-decorator │ ├── candidacy-declare.js │ ├── convert-buy-pool.js │ ├── convert-buy.js │ ├── convert-sell-all-pool.js │ ├── convert-sell-all.js │ ├── convert-sell-pool.js │ ├── convert-sell.js │ ├── index.js │ ├── limit-order-add.js │ ├── lock.js │ ├── pool-add-liquidity.js │ ├── pool-create.js │ ├── redeem-check.js │ ├── send.js │ ├── stake-delegate.js │ ├── stake-move.js │ ├── stake-unbond.js │ └── token-burn.js ├── tx.js ├── utils.js └── variables.js ├── test ├── api │ ├── estimate-coin-convert.test.js │ ├── estimate-tx-commission.test.js │ ├── get-coin-info.test.js │ ├── get-commission-price.test.js │ ├── get-min-gas-price.test.js │ ├── get-nonce.test.js │ ├── get-pool-info.test.js │ ├── post-tx.test.js │ ├── replace-coin.test.js │ └── variables.js ├── check.test.js ├── index.html ├── link.test.js ├── test-data.js ├── test-utils.js ├── tx-data │ ├── candidacy-declare.test.js │ ├── candidate-edit-commission.test.js │ ├── candidate-edit-public-key.test.js │ ├── candidate-edit.test.js │ ├── candidate-set-off.test.js │ ├── candidate-set-on.test.js │ ├── convert-buy.test.js │ ├── convert-sell-all.test.js │ ├── convert-sell.test.js │ ├── create-coin.test.js │ ├── create-multisig.test.js │ ├── edit-multisig.test.js │ ├── edit-ticker-owner.test.js │ ├── index.test.js │ ├── limit-order-add.test.js │ ├── limit-order-remove.test.js │ ├── lock.test.js │ ├── multisend.test.js │ ├── pool-add-liquidity.test.js │ ├── pool-buy.test.js │ ├── pool-create.test.js │ ├── pool-remove-liquidity.test.js │ ├── pool-sell-all.test.js │ ├── pool-sell.test.js │ ├── recreate-coin.test.js │ ├── redeem-check.test.js │ ├── send.test.js │ ├── stake-delegate.test.js │ ├── stake-lock.test.js │ ├── stake-move.test.js │ ├── stake-unbond.test.js │ ├── token-burn.test.js │ ├── token-create.test.js │ ├── token-mint.test.js │ ├── token-recreate.test.js │ ├── vote-commission.test.js │ ├── vote-halt-block.test.js │ ├── vote-price.test.js │ └── vote-update.test.js ├── tx-decorator │ └── index.test.js ├── tx.test.js └── utils.test.js ├── tsconfig.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [{.babelrc,.stylelintrc,.eslintrc*,jest.config,*.json,*.jsb3,*.jsb2,*.bowerrc,*.yaml,*.yml}] 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /dist 3 | /build 4 | /coverage 5 | /tmp 6 | node_modules 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: '@babel/eslint-parser', 6 | // parserOptions: { 7 | // sourceType: 'module' 8 | // }, 9 | env: { 10 | browser: true, 11 | jest: true, 12 | }, 13 | plugins: [ 14 | 'jest', 15 | 'security', 16 | 'unicorn', 17 | 'jsdoc', 18 | ], 19 | extends: [ 20 | 'airbnb-base', 21 | ], 22 | settings: { 23 | 'import/resolver': { 24 | alias: [ 25 | ['~/src', './src'], 26 | ['~/test', './test'], 27 | ] 28 | }, 29 | 'jsdoc': { 30 | mode: 'jsdoc', // instead of 'typescript' 31 | tagNamePreference: { 32 | // "return": "return", 33 | }, 34 | }, 35 | }, 36 | // // add your custom rules here 37 | rules: { 38 | 'indent': ['error', 4, {SwitchCase: 1}], 39 | // allow paren-less arrow functions 40 | 'arrow-parens': 0, 41 | // allow braces around function body 42 | 'arrow-body-style': 0, 43 | // allow async-await 44 | 'generator-star-spacing': 0, 45 | // allow debugger during development 46 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 47 | 'object-curly-spacing': 0, 48 | // disable length limit 49 | 'max-len': 0, 50 | // allow `new Buffer()` 51 | 'no-buffer-constructor': 0, 52 | // allow assigning to function parameter 53 | 'no-param-reassign': 0, 54 | 'no-underscore-dangle': 0, 55 | 'no-else-return': 0, 56 | 'no-unused-vars': ['warn', { 'vars': 'all', 'args': 'after-used', 'ignoreRestSiblings': false }], 57 | 'no-plusplus': ["error", { "allowForLoopAfterthoughts": true }], 58 | 'no-use-before-define' : 0, 59 | 'no-multiple-empty-lines': ["error", { "max": 3, "maxEOF": 1 }], 60 | // allow single line imports 61 | 'object-curly-newline': 0, 62 | 'prefer-arrow-callback': 0, 63 | // allow Object.assign() 64 | 'prefer-object-spread': 0, 65 | 'prefer-const': 0, 66 | // disable for nested destructuring 67 | "prefer-destructuring": ["error", { 68 | "AssignmentExpression": { 69 | "array": false, 70 | "object": false 71 | } 72 | }], 73 | 'space-before-function-paren': ['error', { 74 | anonymous: 'never', 75 | named: 'never', 76 | asyncArrow: 'always' 77 | }], 78 | 'import/extensions': ['error', 'always', {ignorePackages: true} ], 79 | // named exports are not bad 80 | 'import/prefer-default-export': 0, 81 | // allow `export {default} from '...'` 82 | 'no-restricted-exports': 0, 83 | }, 84 | overrides: [ 85 | { 86 | files: ['src/**/*'], 87 | extends: [ 88 | 'plugin:security/recommended', 89 | 'plugin:unicorn/recommended', 90 | 'plugin:jsdoc/recommended', 91 | ], 92 | rules: { 93 | 'security/detect-object-injection': 0, 94 | 'unicorn/better-regex': 0, 95 | // full path import is per spec 96 | 'unicorn/import-index': 0, 97 | // IE11 support needed 98 | 'unicorn/prefer-includes': 0, 99 | // allow lowercase hex number 100 | 'unicorn/number-literal-case': 0, 101 | // allow explicitly return undefined 102 | 'unicorn/no-useless-undefined': 0, 103 | // allow forEach 104 | 'unicorn/no-array-for-each': 0, 105 | // allow negated 106 | 'unicorn/no-negated-condition': 0, 107 | 'unicorn/prefer-optional-catch-binding': 0, 108 | 'unicorn/prefer-ternary': 0, 109 | // available since node@15 110 | // @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll#browser_compatibility 111 | 'unicorn/prefer-string-replace-all': 0, 112 | // available since node@16.6 113 | // @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at#browser_compatibility 114 | 'unicorn/prefer-at': 0, 115 | // waiting `node:` to be backported to node@14 116 | // @see https://stackoverflow.com/questions/67263317/how-to-fix-eslint-error-when-using-the-node-protocol-when-importing-node-js-bui 117 | // @see https://github.com/import-js/eslint-plugin-import/issues/2031 118 | 'unicorn/prefer-node-protocol': 0, 119 | // incorrectly treat `Big` as `Number` 120 | // wontfix https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1463 121 | 'unicorn/require-number-to-fixed-digits-argument': 0, 122 | // not supported yet 123 | 'unicorn/numeric-separators-style': 0, 124 | 'unicorn/prevent-abbreviations': ['error', { 125 | replacements: { 126 | 'params': false, 127 | }, 128 | allowList: { 129 | 'fn': true, 130 | 'otherArgs': true, 131 | 'resData': true, 132 | 'txParams': true, 133 | 'txProps': true, 134 | } 135 | }], 136 | // jsdoc 137 | 'jsdoc/require-param-description': 0, 138 | 'jsdoc/require-returns-description': 0, 139 | 'jsdoc/require-property-description': 0, 140 | 'jsdoc/newline-after-description': 0, 141 | // poor syntax validator 142 | 'jsdoc/valid-types': 0, 143 | // @TODO allow both return and returns 144 | 'jsdoc/require-returns': 0, 145 | // @TODO allow both return and returns 146 | 'jsdoc/check-tag-names': 0, 147 | // @TODO all custom types treated as undefined 148 | 'jsdoc/no-undefined-types': 0, 149 | }, 150 | }, 151 | { 152 | files: ['examples/**/*', 'test/**/*'], 153 | rules: { 154 | 'import/no-extraneous-dependencies': 0, 155 | 'no-console': 0, 156 | } 157 | }, 158 | { 159 | files: ['test/**/*'], 160 | extends: [ 161 | 'plugin:jest/recommended', 162 | ], 163 | rules: { 164 | 'no-unused-vars': 0, 165 | 'import/extensions': 0, 166 | // 'jest-expect-message' allow multiple arguments 167 | 'jest/valid-expect': 0, 168 | // allow `expect` inside `then` 169 | 'jest/no-conditional-expect': 0, 170 | } 171 | }, 172 | ] 173 | }; 174 | -------------------------------------------------------------------------------- /.github/workflows/test-with-coverage.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | name: Test with coverage 10 | runs-on: ubuntu-latest 11 | if: "!contains(github.event.head_commit.message, 'skip test')" 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Setup Node.js 15 | uses: actions/setup-node@v3 16 | with: 17 | node-version: lts/* 18 | 19 | - run: npm ci 20 | 21 | - name: Test with coverage 22 | run: npm run test 23 | 24 | - name: Coveralls 25 | uses: coverallsapp/github-action@1.1.3 26 | with: 27 | github-token: ${{ secrets.GITHUB_TOKEN }} 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /tmp 3 | 4 | # dependencies 5 | node_modules 6 | /coverage 7 | 8 | # logs 9 | npm-debug.log 10 | -------------------------------------------------------------------------------- /.ncurc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | format: [ 3 | 'group', 4 | 'repo', 5 | 'ownerChanged', 6 | ], 7 | reject: [ 8 | 'ethereum-cryptography', 9 | 'rlp', 10 | ], 11 | }; 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Respective Authors all rights reserved. 2 | 3 | The MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | // "targets": { 7 | // "node": true 8 | // }, 9 | // "modules": "commonjs" 10 | } 11 | ] 12 | ], 13 | "plugins": [ 14 | "@babel/plugin-transform-runtime", 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /build/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /build/rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import del from 'rollup-plugin-delete'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import babel from '@rollup/plugin-babel'; 5 | import _rename from 'rollup-plugin-rename'; 6 | 7 | const rename = _rename.default || _rename; 8 | 9 | 10 | export default { 11 | input: 'src/index.js', 12 | output: { 13 | dir: 'dist/cjs/', 14 | format: 'cjs', 15 | preserveModules: true, 16 | exports: 'auto', 17 | }, 18 | external: ['@babel/runtime'], 19 | plugins: [ 20 | del({targets: ['dist/cjs/']}), 21 | // nodejs v10 doesn't support optional chaining 22 | // babel({ 23 | // babelrc: false, 24 | // configFile: false, 25 | // "plugins": [ 26 | // "@babel/plugin-proposal-optional-chaining", 27 | // ], 28 | // }), 29 | commonjs({ 30 | }), 31 | // fixes "Cannot use import statement outside a module" 32 | resolve({ 33 | resolveOnly: ['lodash-es'], 34 | // modulesOnly: true, 35 | // preferBuiltins: false, 36 | }), 37 | babel({ 38 | babelHelpers: 'runtime', 39 | }), 40 | rename({ 41 | include: ['**/*.js', '**/*.js\\?commonjs-entry'], 42 | map: (name) => name 43 | .replace('src/', '') 44 | .replace('node_modules/', 'external/') 45 | .replace('../../external', '../external'), 46 | }), 47 | ], 48 | }; 49 | -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import json from '@rollup/plugin-json'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import nodePolyfills from 'rollup-plugin-polyfill-node'; 5 | // import builtins from 'rollup-plugin-node-builtins'; 6 | // import globals from 'rollup-plugin-node-globals'; 7 | import babel from '@rollup/plugin-babel'; 8 | import {visualizer} from 'rollup-plugin-visualizer' 9 | 10 | export default { 11 | input: 'src/index.js', 12 | output: [ 13 | { 14 | file: 'dist/index.js', 15 | format: 'umd', 16 | name: 'minterSDK', 17 | exports: 'auto', 18 | }, 19 | { 20 | file: 'dist/index.esm.js', 21 | format: 'esm', 22 | // name: 'minterSDK', 23 | // exports: 'auto', 24 | } 25 | ], 26 | plugins: [ 27 | // old acorn in rollup-plugin-node-globals doesn't support new syntax 28 | /* 29 | babel({ 30 | babelrc: false, 31 | configFile: false, 32 | "plugins": [ 33 | "@babel/plugin-proposal-optional-chaining", 34 | "@babel/plugin-proposal-numeric-separator", 35 | ], 36 | }), 37 | */ 38 | commonjs({ 39 | // required to include bip39 wordlists 40 | ignoreTryCatch: false, 41 | // namedExports: { 42 | // 'node_modules/ethereumjs-util/dist/index.js': [ 'stripHexPrefix', 'padToEven' ], 43 | // }, 44 | }), 45 | json(), 46 | // globals(), 47 | // builtins({ 48 | // // crypto: true, 49 | // }), 50 | nodePolyfills(), 51 | resolve({ 52 | browser: true, 53 | preferBuiltins: false, 54 | }), 55 | babel({ 56 | exclude: 'node_modules/@babel/runtime/**', 57 | babelHelpers: 'runtime', 58 | }), 59 | visualizer({ 60 | filename: 'tmp/stats.html', 61 | }), 62 | ], 63 | strictDeprecations: true, 64 | }; 65 | -------------------------------------------------------------------------------- /build/rollup.uglify.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from './rollup.config.js'; 2 | 3 | // uglifyjs alternative with es6 support 4 | import terser from '@rollup/plugin-terser'; 5 | 6 | const config = Object.assign({}, baseConfig); 7 | // const config = Object.assign({}, baseConfig, {output: Object.assign({}, baseConfig.output)}); 8 | 9 | 10 | if (config.plugins.at(-1).name === 'visualizer') { 11 | // put just before 'visualizer' 12 | config.plugins.splice(-1, 0, terser()); 13 | } else { 14 | config.plugins.push(terser()); 15 | } 16 | 17 | config.output = Array.isArray(config.output) ? config.output : [config.output]; 18 | config.output = config.output.map((item) => { 19 | return { 20 | ...item, 21 | file: item.file.replace(/\.js$/, '.min.js') 22 | }; 23 | }); 24 | 25 | export default config; 26 | -------------------------------------------------------------------------------- /jest-bundle-browser-env.js: -------------------------------------------------------------------------------- 1 | // jest.env.js 2 | const JSDOMEnvironment = require("jest-environment-jsdom").default; 3 | class CustomJSDOMEnvironment extends JSDOMEnvironment { 4 | /* 5 | // doesn't work in jest 28 6 | constructor(config, context) { 7 | super({ 8 | ...config, 9 | globals: { 10 | ...config.globals, 11 | Uint32Array, 12 | Uint8Array, 13 | ArrayBuffer, 14 | }, 15 | }, context); 16 | } 17 | */ 18 | async setup() { 19 | await super.setup(); 20 | this.global.Uint8Array = Uint8Array; 21 | this.global.ArrayBuffer = ArrayBuffer; 22 | } 23 | } 24 | module.exports = CustomJSDOMEnvironment; 25 | -------------------------------------------------------------------------------- /jest-bundle-browser-setup.js: -------------------------------------------------------------------------------- 1 | import {isBuffer} from 'buffer-es6'; 2 | import {Buffer as safeBuffer} from 'safe-buffer'; 3 | 4 | 5 | 6 | 7 | const originalExpect = global.expect; 8 | 9 | global.expect = (value) => { 10 | value = walkFix(value); 11 | const expectResult = originalExpect(value); 12 | 13 | // fix toEqual 14 | const originalToEqual = expectResult.toEqual; 15 | expectResult.toEqual = (value) => { 16 | value = walkFix(value); 17 | return originalToEqual(value); 18 | }; 19 | expectResult.toEqual.__proto__ = originalToEqual; 20 | return expectResult; 21 | }; 22 | global.expect.__proto__ = originalExpect; 23 | 24 | 25 | const WALK_DEPTH = 10; 26 | /** 27 | * walk through keys and fix each 28 | * @param obj 29 | * @param {number} [currentDepth] 30 | */ 31 | function walkFix(obj, currentDepth = 0) { 32 | // fix it if it's a Buffer 33 | obj = fixBuffer(obj); 34 | if (!obj || currentDepth > WALK_DEPTH) { 35 | return obj; 36 | } 37 | // try fix each key if it's an Object 38 | Object.keys(obj).forEach((key) => { 39 | const descriptor = Object.getOwnPropertyDescriptor(obj, key); 40 | if (descriptor.writable) { 41 | obj[key] = walkFix(obj[key], currentDepth + 1); 42 | } 43 | }); 44 | return obj; 45 | } 46 | 47 | /** 48 | * Convert Buffer implementation of bundled `buffer-es6` to `safe-buffer` implementation used in tests and `safe-buffer` used in rollup's browserify 49 | * It requires to satisfy jest's `.toEqual()` deep equality check 50 | * @param value 51 | * @return {Buffer} 52 | */ 53 | function fixBuffer(value) { 54 | if (isBuffer(value)) { 55 | value = safeBuffer.from(value); 56 | } 57 | return value; 58 | } 59 | -------------------------------------------------------------------------------- /jest-bundle-browser.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // testEnvironment: 'jsdom', 3 | // @see https://github.com/facebook/jest/issues/12586#issuecomment-1073298261 4 | testEnvironment: '/jest-bundle-browser-env.js', 5 | setupFilesAfterEnv: ["/jest-bundle-browser-setup.js"], 6 | moduleNameMapper: { 7 | '~\/src$': '/dist/index.js', 8 | // '~\/src\/(.*)$': '/src/$1', 9 | '~\/src\/utils\.js$': '/src/utils.js', 10 | '~\/test\/(.*)$': '/test/$1', 11 | }, 12 | transform: { 13 | // ensure dist/ not transpiled 14 | // '^.+\\.jsx?$': 'babel-jest', 15 | 'src\/utils\.js$': 'babel-jest', 16 | 'test\/.+\\.jsx?$': 'babel-jest', 17 | 'node_modules\/.+\\.jsx?$': 'babel-jest', 18 | 'jest-bundle-browser-setup\.js$': 'babel-jest', 19 | }, 20 | transformIgnorePatterns: [ 21 | 'node_modules/(?!(buffer-es6|pretty-num)/)', 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /jest-bundle-cjs.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleNameMapper: { 3 | '~\/src$': '/dist/cjs/index.js', 4 | '~\/src\/utils\.js$': '/src/utils.js', 5 | '~\/test\/(.*)$': '/test/$1', 6 | }, 7 | transformIgnorePatterns: [ 8 | 'node_modules/(?!(pretty-num)/)', 9 | ], 10 | testEnvironment: 'node', 11 | }; 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bail: true, 3 | moduleNameMapper: { 4 | '~(.*)$': '/$1', 5 | }, 6 | transform: { 7 | '^.+\\.jsx?$': 'babel-jest', 8 | }, 9 | transformIgnorePatterns: [ 10 | 'node_modules/(?!(minterjs-tx|minterjs-util|minterjs-wallet|lodash-es|pretty-num)/)', 11 | ], 12 | testEnvironment: 'node', 13 | // collectCoverage: true, 14 | collectCoverageFrom: ["./src/**"], 15 | coverageReporters: ["lcov", "text"] 16 | }; 17 | -------------------------------------------------------------------------------- /minter-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minter-js-sdk", 3 | "version": "0.46.2", 4 | "description": "JS SDK for Minter Blockchain", 5 | "main": "dist/cjs/index.js", 6 | "module": "src/index.js", 7 | "browser": { 8 | "./dist/cjs/index.js": "./dist/index.js" 9 | }, 10 | "unpkg": "dist/index.min.js", 11 | "files": [ 12 | "/src/", 13 | "/dist/" 14 | ], 15 | "scripts": { 16 | "build": "npm run build:browser && npm run build:browser-minify && npm run build:cjs", 17 | "build:browser": "rollup -c build/rollup.config.js", 18 | "build:browser-minify": "rollup -c build/rollup.uglify.config.js", 19 | "build:cjs": "rollup -c build/rollup.cjs.config.js", 20 | "prepublishOnly": "npm run lint && npm run test:light", 21 | "lint": "eslint --ext .js ./src ./test", 22 | "lint:fix": "eslint --ext .js ./src ./test --fix", 23 | "tsc": "tsc --project tsconfig.json", 24 | "test": "npm run test:src && npm run build && npm run jest:bundle-browser && npm run jest:bundle-cjs", 25 | "test:light": "npm run test:src && npm run build && npm run jest:bundle-browser-unit && npm run jest:bundle-cjs-unit", 26 | "test:src": "npm run jest-coverage", 27 | "test:bundle-browser": "npm run build:browser && npm run jest:bundle-browser", 28 | "test:bundle-cjs": "npm run build:cjs && npm run jest:bundle-cjs", 29 | "test:bundle-browser-unit": "npm run build:browser && npm run jest:bundle-browser-unit", 30 | "test:bundle-cjs-unit": "npm run build:cjs && npm run jest:bundle-cjs-unit", 31 | "jest:src": "jest", 32 | "jest:src-unit": "jest --testPathIgnorePatterns='/test/api'", 33 | "jest:src-e2e": "jest --testPathPattern='api/'", 34 | "jest:bundle-browser": "jest --config jest-bundle-browser.config.js", 35 | "jest:bundle-cjs": "jest --config jest-bundle-cjs.config.js", 36 | "jest:bundle-browser-unit": "jest --config jest-bundle-browser.config.js --testPathIgnorePatterns='/test/api'", 37 | "jest:bundle-cjs-unit": "jest --config jest-bundle-cjs.config.js --testPathIgnorePatterns='/test/api'", 38 | "jest-coverage": "jest --coverage", 39 | "precommit": "echo 'Pre-commit checks...' && npm run lint" 40 | }, 41 | "pre-commit": [ 42 | "precommit" 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/MinterTeam/minter-js-sdk.git" 47 | }, 48 | "keywords": [ 49 | "minter", 50 | "blockchain", 51 | "sdk" 52 | ], 53 | "author": "MinterTeam (https://github.com/MinterTeam)", 54 | "license": "MIT", 55 | "bugs": { 56 | "url": "https://github.com/MinterTeam/minter-js-sdk/issues" 57 | }, 58 | "homepage": "https://github.com/MinterTeam/minter-js-sdk#readme", 59 | "dependencies": { 60 | "@babel/runtime": "^7.22.3", 61 | "axios": "^1.4.0", 62 | "big.js": "^6.2.1", 63 | "bn.js": "^5.2.1", 64 | "ethereum-cryptography": "0.1.3", 65 | "ethereumjs-util": "^7.1.5", 66 | "ethjs-util": "^0.1.6", 67 | "lodash-es": "^4.17.21", 68 | "minterjs-tx": "^12.0.3", 69 | "minterjs-util": "^0.25.1", 70 | "minterjs-wallet": "^6.2.0", 71 | "qs": "^6.11.2", 72 | "rlp": "^2", 73 | "secp256k1": "^4.0.3" 74 | }, 75 | "devDependencies": { 76 | "@babel/cli": "^7.21.5", 77 | "@babel/core": "^7.22.1", 78 | "@babel/eslint-parser": "^7.21.8", 79 | "@babel/plugin-transform-runtime": "^7.22.4", 80 | "@babel/preset-env": "^7.22.4", 81 | "@rollup/plugin-babel": "^6.0.3", 82 | "@rollup/plugin-commonjs": "^25.0.0", 83 | "@rollup/plugin-json": "^6.0.0", 84 | "@rollup/plugin-node-resolve": "^15.0.2", 85 | "@rollup/plugin-terser": "^0.4.3", 86 | "babel-jest": "^29.5.0", 87 | "coveralls": "^3.1.1", 88 | "eslint": "^8.41.0", 89 | "eslint-config-airbnb-base": "^15.0.0", 90 | "eslint-import-resolver-alias": "^1.1.2", 91 | "eslint-plugin-import": "^2.27.5", 92 | "eslint-plugin-jest": "^27.2.1", 93 | "eslint-plugin-jsdoc": "^45.0.0", 94 | "eslint-plugin-security": "^1.7.1", 95 | "eslint-plugin-unicorn": "^47.0.0", 96 | "jest": "^29.5.0", 97 | "jest-environment-jsdom": "^29.5.0", 98 | "pre-commit": "^1.2.2", 99 | "rollup": "^3.23.0", 100 | "rollup-plugin-delete": "^2.0.0", 101 | "rollup-plugin-polyfill-node": "^0.12.0", 102 | "rollup-plugin-rename": "^1.0.1", 103 | "rollup-plugin-visualizer": "^5.9.0", 104 | "typescript": "^5.0.4" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/api/estimate-coin-buy.js: -------------------------------------------------------------------------------- 1 | import {stringify as qsStringify} from 'qs'; 2 | import {convertFromPip, convertToPip} from 'minterjs-util'; 3 | // import {convertFromPip, convertToPip} from 'minterjs-util/src/converter.js'; 4 | import {isCoinId, isValidNumber} from '../utils.js'; 5 | 6 | /** 7 | * @typedef {object} EstimateBuyResult 8 | * @property {number|string} will_pay - amount of coinToSell 9 | * @property {number|string} commission - amount of coinToSell to pay fee 10 | * @property {"pool"|"bancor"} swap_from 11 | */ 12 | 13 | /** 14 | * @param {MinterApiInstance} apiInstance 15 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 16 | * @return {EstimateCoinBuyInstance} 17 | */ 18 | export default function EstimateCoinBuy(apiInstance, factoryAxiosOptions) { 19 | /** 20 | * @typedef {Function} EstimateCoinBuyInstance 21 | * @param {object} params 22 | * @param {string|number} params.coinToBuy - ID or symbol of the coin to buy 23 | * @param {string|number} params.valueToBuy 24 | * @param {string|number} params.coinToSell - ID or symbol of the coin to sell 25 | * @param {ESTIMATE_SWAP_TYPE} [params.swapFrom] - estimate from pool, bancor or optimal 26 | * @param {Array} [params.route] - IDs of intermediate coins for pool swaps 27 | * @param {string|number} [params.gasCoin] 28 | * @param {string|number} [params.coinCommission] - gasCoin alias 29 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 30 | * @return {Promise} 31 | */ 32 | return function estimateCoinBuy(params, axiosOptions) { 33 | if (params.coinIdToSell || params.coinIdToSell === 0) { 34 | params.coinToSell = params.coinIdToSell; 35 | // eslint-disable-next-line no-console 36 | console.warn('coinIdToSell is deprecated, use coinToSell instead'); 37 | } 38 | if (params.coinIdToBuy || params.coinIdToBuy === 0) { 39 | params.coinToBuy = params.coinIdToBuy; 40 | // eslint-disable-next-line no-console 41 | console.warn('coinIdToSell is deprecated, use coinToSell instead'); 42 | } 43 | 44 | if (!params.coinToBuy && params.coinToBuy !== 0) { 45 | return Promise.reject(new Error('Coin to buy not specified')); 46 | } 47 | if (!params.valueToBuy) { 48 | return Promise.reject(new Error('Value to buy not specified')); 49 | } 50 | if (!params.coinToSell && params.coinToSell !== 0) { 51 | return Promise.reject(new Error('Coin to sell not specified')); 52 | } 53 | 54 | const gasCoin = (params.gasCoin || params.gasCoin === 0) ? params.gasCoin : params.coinCommission; 55 | 56 | params = { 57 | coin_id_to_buy: isCoinId(params.coinToBuy) ? params.coinToBuy : undefined, 58 | coin_to_buy: !isCoinId(params.coinToBuy) ? params.coinToBuy : undefined, 59 | value_to_buy: convertToPip(params.valueToBuy), 60 | coin_id_to_sell: isCoinId(params.coinToSell) ? params.coinToSell : undefined, 61 | coin_to_sell: !isCoinId(params.coinToSell) ? params.coinToSell : undefined, 62 | swap_from: params.swapFrom, 63 | route: params.route, 64 | coin_id_commission: isCoinId(gasCoin) ? gasCoin : undefined, 65 | coin_commission: !isCoinId(gasCoin) ? gasCoin : undefined, 66 | }; 67 | 68 | return apiInstance.get('estimate_coin_buy', { 69 | ...factoryAxiosOptions, 70 | ...axiosOptions, 71 | params, 72 | // @see https://github.com/axios/axios/issues/5058#issuecomment-1272107602 73 | paramsSerializer: { 74 | // eslint-disable-next-line unicorn/no-null 75 | indexes: null, 76 | }, 77 | }) 78 | .then((response) => { 79 | const resData = response.data; 80 | if (!isValidNumber(resData.will_pay)) { 81 | throw new Error('Invalid estimation data, `will_pay` not specified'); 82 | } 83 | if (!isValidNumber(resData.commission)) { 84 | throw new Error('Invalid estimation data, `commission` not specified'); 85 | } 86 | 87 | return { 88 | ...resData, 89 | // convert pips 90 | will_pay: convertFromPip(resData.will_pay), 91 | commission: convertFromPip(resData.commission), 92 | }; 93 | }); 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /src/api/estimate-coin-sell-all.js: -------------------------------------------------------------------------------- 1 | import {stringify as qsStringify} from 'qs'; 2 | import {convertFromPip, convertToPip} from 'minterjs-util'; 3 | // import {convertFromPip, convertToPip} from 'minterjs-util/src/converter.js'; 4 | import {isValidNumber, isCoinId} from '../utils.js'; 5 | 6 | /** 7 | * @typedef {object} EstimateSellAllResult 8 | * @property {number|string} will_get - amount of coinToBuy 9 | * @property {"pool"|"bancor"} [swap_from] 10 | */ 11 | 12 | /** 13 | * @param {MinterApiInstance} apiInstance 14 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 15 | * @return {EstimateCoinSellAllInstance} 16 | */ 17 | export default function EstimateCoinSellAll(apiInstance, factoryAxiosOptions) { 18 | /** 19 | * @typedef {Function} EstimateCoinSellAllInstance 20 | * @param {object} params 21 | * @param {string|number} params.coinToSell - ID or symbol of the coin to sell 22 | * @param {string|number} params.valueToSell 23 | * @param {string|number} params.coinToBuy - ID or symbol of the coin to buy 24 | * @param {ESTIMATE_SWAP_TYPE} [params.swapFrom] - estimate pool swap 25 | * @param {Array} [params.route] - IDs of intermediate coins for pool swaps 26 | * @param {string|number} [params.gasPrice] 27 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 28 | * @return {Promise} 29 | */ 30 | return function estimateCoinSellAll(params, axiosOptions) { 31 | if (params.coinIdToSell || params.coinIdToSell === 0) { 32 | params.coinToSell = params.coinIdToSell; 33 | // eslint-disable-next-line no-console 34 | console.warn('coinIdToSell is deprecated, use coinToSell instead'); 35 | } 36 | if (params.coinIdToBuy || params.coinIdToBuy === 0) { 37 | params.coinToBuy = params.coinIdToBuy; 38 | // eslint-disable-next-line no-console 39 | console.warn('coinIdToSell is deprecated, use coinToSell instead'); 40 | } 41 | 42 | if (!params.coinToBuy && params.coinToBuy !== 0) { 43 | return Promise.reject(new Error('Coin to buy not specified')); 44 | } 45 | if (!params.valueToSell) { 46 | return Promise.reject(new Error('Value to sell not specified')); 47 | } 48 | if (!params.coinToSell && params.coinToSell !== 0) { 49 | return Promise.reject(new Error('Coin to sell not specified')); 50 | } 51 | 52 | params = { 53 | coin_id_to_sell: isCoinId(params.coinToSell) ? params.coinToSell : undefined, 54 | coin_to_sell: !isCoinId(params.coinToSell) ? params.coinToSell : undefined, 55 | value_to_sell: convertToPip(params.valueToSell), 56 | coin_id_to_buy: isCoinId(params.coinToBuy) ? params.coinToBuy : undefined, 57 | coin_to_buy: !isCoinId(params.coinToBuy) ? params.coinToBuy : undefined, 58 | swap_from: params.swapFrom, 59 | route: params.route, 60 | gas_price: params.gasPrice, 61 | }; 62 | 63 | return apiInstance.get('estimate_coin_sell_all', { 64 | ...factoryAxiosOptions, 65 | ...axiosOptions, 66 | params, 67 | // @see https://github.com/axios/axios/issues/5058#issuecomment-1272107602 68 | paramsSerializer: { 69 | // eslint-disable-next-line unicorn/no-null 70 | indexes: null, 71 | }, 72 | }) 73 | .then((response) => { 74 | const resData = response.data; 75 | if (!isValidNumber(resData.will_get)) { 76 | throw new Error('Invalid estimation data, `will_get` not specified'); 77 | } 78 | 79 | return { 80 | ...resData, 81 | // receive pips from node and convert them 82 | will_get: convertFromPip(resData.will_get), 83 | }; 84 | }); 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /src/api/estimate-coin-sell.js: -------------------------------------------------------------------------------- 1 | import {stringify as qsStringify} from 'qs'; 2 | import {convertFromPip, convertToPip} from 'minterjs-util'; 3 | // import {convertFromPip, convertToPip} from 'minterjs-util/src/converter.js'; 4 | import {isValidNumber, isCoinId} from '../utils.js'; 5 | 6 | /** 7 | * @typedef {object} EstimateSellResult 8 | * @property {number|string} will_get - amount of coinToBuy 9 | * @property {number|string} commission - amount of coinToSell to pay fee 10 | * @property {"pool"|"bancor"} [swap_from] 11 | */ 12 | 13 | /** 14 | * @param {MinterApiInstance} apiInstance 15 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 16 | * @return {EstimateCoinSellInstance} 17 | */ 18 | export default function EstimateCoinSell(apiInstance, factoryAxiosOptions) { 19 | /** 20 | * @typedef {Function} EstimateCoinSellInstance 21 | * @param {object} params 22 | * @param {string|number} params.coinToSell - ID or symbol of the coin to sell 23 | * @param {string|number} params.valueToSell 24 | * @param {string|number} params.coinToBuy - ID or symbol of the coin to buy 25 | * @param {ESTIMATE_SWAP_TYPE} [params.swapFrom] - estimate pool swap 26 | * @param {Array} [params.route] - IDs of intermediate coins for pool swaps 27 | * @param {string|number} [params.gasCoin] 28 | * @param {string|number} [params.coinCommission] - gasCoin alias 29 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 30 | * @return {Promise} 31 | */ 32 | return function estimateCoinSell(params, axiosOptions) { 33 | if (params.coinIdToSell || params.coinIdToSell === 0) { 34 | params.coinToSell = params.coinIdToSell; 35 | // eslint-disable-next-line no-console 36 | console.warn('coinIdToSell is deprecated, use coinToSell instead'); 37 | } 38 | if (params.coinIdToBuy || params.coinIdToBuy === 0) { 39 | params.coinToBuy = params.coinIdToBuy; 40 | // eslint-disable-next-line no-console 41 | console.warn('coinIdToSell is deprecated, use coinToSell instead'); 42 | } 43 | 44 | if (!params.coinToBuy && params.coinToBuy !== 0) { 45 | return Promise.reject(new Error('Coin to buy not specified')); 46 | } 47 | if (!params.valueToSell) { 48 | return Promise.reject(new Error('Value to sell not specified')); 49 | } 50 | if (!params.coinToSell && params.coinToSell !== 0) { 51 | return Promise.reject(new Error('Coin to sell not specified')); 52 | } 53 | 54 | const gasCoin = (params.gasCoin || params.gasCoin === 0) ? params.gasCoin : params.coinCommission; 55 | 56 | params = { 57 | coin_id_to_sell: isCoinId(params.coinToSell) ? params.coinToSell : undefined, 58 | coin_to_sell: !isCoinId(params.coinToSell) ? params.coinToSell : undefined, 59 | value_to_sell: convertToPip(params.valueToSell), 60 | coin_id_to_buy: isCoinId(params.coinToBuy) ? params.coinToBuy : undefined, 61 | coin_to_buy: !isCoinId(params.coinToBuy) ? params.coinToBuy : undefined, 62 | swap_from: params.swapFrom, 63 | route: params.route, 64 | coin_id_commission: isCoinId(gasCoin) ? gasCoin : undefined, 65 | coin_commission: !isCoinId(gasCoin) ? gasCoin : undefined, 66 | }; 67 | 68 | return apiInstance.get('estimate_coin_sell', { 69 | ...factoryAxiosOptions, 70 | ...axiosOptions, 71 | params, 72 | // @see https://github.com/axios/axios/issues/5058#issuecomment-1272107602 73 | paramsSerializer: { 74 | // eslint-disable-next-line unicorn/no-null 75 | indexes: null, 76 | }, 77 | }) 78 | .then((response) => { 79 | const resData = response.data; 80 | if (!isValidNumber(resData.will_get)) { 81 | throw new Error('Invalid estimation data, `will_get` not specified'); 82 | } 83 | if (!isValidNumber(resData.commission)) { 84 | throw new Error('Invalid estimation data, `commission` not specified'); 85 | } 86 | 87 | return { 88 | ...resData, 89 | // receive pips from node and convert them 90 | will_get: convertFromPip(resData.will_get), 91 | commission: convertFromPip(resData.commission), 92 | }; 93 | }); 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /src/api/get-coin-info.js: -------------------------------------------------------------------------------- 1 | import {isCoinId, isCoinSymbol} from '../utils.js'; 2 | 3 | /** 4 | * @param {MinterApiInstance} apiInstance 5 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 6 | * @return {GetCoinInfoInstance} 7 | */ 8 | export default function GetCoinInfo(apiInstance, factoryAxiosOptions) { 9 | return getCoinInfo; 10 | /** 11 | * Get nonce for new transaction: last transaction number + 1 12 | * @typedef {Function} GetCoinInfoInstance 13 | * @param {string|number} coin 14 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 15 | * @return {Promise} 16 | */ 17 | function getCoinInfo(coin, axiosOptions) { 18 | axiosOptions = { 19 | ...factoryAxiosOptions, 20 | ...axiosOptions, 21 | }; 22 | let coinInfoPromise; 23 | if (isCoinId(coin)) { 24 | coinInfoPromise = apiInstance.get(`coin_info_by_id/${coin}`, axiosOptions); 25 | } else if (isCoinSymbol(coin)) { 26 | coinInfoPromise = apiInstance.get(`coin_info/${coin}`, axiosOptions); 27 | } else { 28 | return Promise.reject(new Error('Invalid coin')); 29 | } 30 | return coinInfoPromise 31 | .then((response) => { 32 | response.data.id = Number(response.data.id); 33 | return response.data; 34 | }); 35 | } 36 | } 37 | 38 | /** 39 | * @typedef {object} CoinInfo 40 | * @property {number|string} id 41 | * @property {string} name 42 | * @property {string} symbol 43 | * @property {number|string} volume 44 | * @property {number|string} crr 45 | * @property {number|string} reserve_balance 46 | * @property {number|string} max_supply 47 | * @property {string|null} owner_address 48 | */ 49 | -------------------------------------------------------------------------------- /src/api/get-commission-price.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {MinterApiInstance} apiInstance 3 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 4 | * @return {GetCommissionPriceInstance} 5 | */ 6 | export default function GetCommissionPrice(apiInstance, factoryAxiosOptions) { 7 | /** 8 | * Get nonce for new transaction: last transaction number + 1 9 | * @typedef {Function} GetCommissionPriceInstance 10 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 11 | * @return {Promise} 12 | */ 13 | return function getCommissionPrice(axiosOptions) { 14 | return apiInstance.get('price_commissions', { 15 | ...factoryAxiosOptions, 16 | ...axiosOptions, 17 | }) 18 | .then((response) => { 19 | return response.data; 20 | }); 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/api/get-min-gas-price.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @param {MinterApiInstance} apiInstance 4 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 5 | * @return {GetMinGasPriceInstance} 6 | */ 7 | export default function GetMinGasPrice(apiInstance, factoryAxiosOptions) { 8 | /** 9 | * Get current minimal gas price 10 | * @typedef {Function} GetMinGasPriceInstance 11 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 12 | * @return {Promise} 13 | */ 14 | return function getMinGasPrice(axiosOptions) { 15 | return apiInstance.get('min_gas_price', { 16 | ...factoryAxiosOptions, 17 | ...axiosOptions, 18 | }) 19 | .then((response) => { 20 | const resData = response.data; 21 | const minGasPrice = resData.min_gas_price; 22 | return Number(minGasPrice); 23 | }); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/api/get-nonce.js: -------------------------------------------------------------------------------- 1 | import {API_TYPE_GATE} from '../variables.js'; 2 | 3 | 4 | /** 5 | * @param {MinterApiInstance} apiInstance 6 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 7 | * @return {GetNonceInstance} 8 | */ 9 | export default function GetNonce(apiInstance, factoryAxiosOptions) { 10 | /** 11 | * Get nonce for new transaction: last transaction number + 1 12 | * @typedef {Function} GetNonceInstance 13 | * @param {string} address 14 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 15 | * @return {Promise} 16 | */ 17 | return function getNonce(address, axiosOptions) { 18 | const nonceUrl = apiInstance.defaults.apiType === API_TYPE_GATE 19 | ? `nonce/${address}` 20 | : `address/${address}`; 21 | 22 | return apiInstance.get(nonceUrl, { 23 | ...factoryAxiosOptions, 24 | ...axiosOptions, 25 | }) 26 | .then((response) => { 27 | const resData = response.data; 28 | const nonce = apiInstance.defaults.apiType === API_TYPE_GATE ? resData.nonce : resData.transaction_count; 29 | const newNonce = Number(nonce) + 1; 30 | if (Number.isNaN(newNonce)) { 31 | // eslint-disable-next-line unicorn/prefer-type-error 32 | throw new Error(`Can't get nonce, API returns '${nonce}'`); 33 | } 34 | 35 | return newNonce; 36 | }); 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/api/get-pool-info.js: -------------------------------------------------------------------------------- 1 | import {convertFromPip} from 'minterjs-util'; 2 | import {ReplaceCoinSymbolByPath} from './replace-coin.js'; 3 | 4 | /** 5 | * @param {MinterApiInstance} apiInstance 6 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 7 | * @param {import('axios').AxiosRequestConfig} [factoryExtraAxiosOptions] - options for getting coin id 8 | * @return {GetPoolInfoInstance} 9 | */ 10 | export default function GetPoolInfo(apiInstance, factoryAxiosOptions, factoryExtraAxiosOptions) { 11 | const replaceCoinSymbolByPath = ReplaceCoinSymbolByPath(apiInstance, factoryExtraAxiosOptions); 12 | /** 13 | * @typedef {Function} GetPoolInfoInstance 14 | * @param {number|string} coin0 - first coin id 15 | * @param {number|string} coin1 - second coin id 16 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 17 | * @param {import('axios').AxiosRequestConfig} [extraAxiosOptions] 18 | * @return {Promise} 19 | */ 20 | return async function getPoolInfo(coin0, coin1, axiosOptions, extraAxiosOptions) { 21 | const coins = await replaceCoinSymbolByPath([coin0, coin1], ['0', '1'], undefined, extraAxiosOptions); 22 | return apiInstance.get(`swap_pool/${coins[0]}/${coins[1]}`, { 23 | ...factoryAxiosOptions, 24 | ...axiosOptions, 25 | }) 26 | .then((response) => { 27 | response.data.id = Number(response.data.id); 28 | return { 29 | ...response.data, 30 | id: Number(response.data.id), 31 | liquidity: convertFromPip(response.data.liquidity), 32 | amount0: convertFromPip(response.data.amount0), 33 | amount1: convertFromPip(response.data.amount1), 34 | }; 35 | }); 36 | }; 37 | } 38 | 39 | /** 40 | * @typedef {object} PoolInfo 41 | * @property {number} id 42 | * @property {string|number} amount0 43 | * @property {string|number} amount1 44 | * @property {string|number} liquidity 45 | */ 46 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | // import createError from 'axios/lib/core/createError'; 3 | import {API_TYPE_NODE} from '../variables.js'; 4 | 5 | /** 6 | * @typedef {object} MinterApiInstanceType 7 | * @property {AxiosDefaults} defaults 8 | * @property {string} defaults.apiType 9 | * 10 | * @typedef {AxiosInstance | MinterApiInstanceType} MinterApiInstance 11 | */ 12 | 13 | /** 14 | * @param {object} [options] 15 | * @param {string} [options.apiType] 16 | * @param {number} [options.chainId] 17 | * @param {string} [options.baseURL] 18 | * @param {...import('axios').AxiosRequestConfig} [options.*] 19 | * @return {MinterApiInstance} 20 | */ 21 | export default function MinterApi(options = {}) { 22 | if (!options.apiType) { 23 | options.apiType = API_TYPE_NODE; 24 | } 25 | 26 | // ensure error payload will be rejected 27 | // options.adapter = thenableToRejectedAdapter; 28 | 29 | // ensure `options.transformResponse` is array 30 | if (!Array.isArray(options.transformResponse)) { 31 | options.transformResponse = options.transformResponse ? [options.transformResponse] : []; 32 | } 33 | 34 | // @TODO duplication with getData 35 | // transform response from gate to minter-node api format 36 | // if (options.apiType === API_TYPE_GATE) { 37 | // options.transformResponse.push((data) => { 38 | // data = parseData(data); 39 | // // transform `then` 40 | // // `data: {data: {}}` to `data: {result: {}}` 41 | // // if (data.data) { 42 | // // data.result = data.data; 43 | // // } 44 | // 45 | // return data; 46 | // }); 47 | // } 48 | 49 | // ensure, that error.message exists 50 | options.transformResponse.push((data) => { 51 | data = parseData(data); 52 | if (data?.error?.details) { 53 | data.error.data = data.error.details; 54 | } 55 | // transform `result` to `error` if its failed 56 | // if (data.result && data.result.log) { 57 | // data.error = data.result; 58 | // } 59 | // rename error.log 60 | // if (data.error && data.error.log && !data.error.message) { 61 | // data.error.message = data.error.log; 62 | // } 63 | // rename error.tx_result.log 64 | // if (data.error && data.error.tx_result && data.error.tx_result.log && !data.error.tx_result.message) { 65 | // data.error.tx_result.message = data.error.tx_result.log; 66 | // } 67 | 68 | return data; 69 | }); 70 | 71 | const instance = axios.create(options); 72 | instance.defaults.apiType = options.apiType; 73 | instance.defaults.chainId = options.chainId; 74 | // ensure trailing slash on baseURL 75 | instance.interceptors.request.use((config) => { 76 | if (config.baseURL[config.baseURL.length - 1] !== '/') { 77 | config.baseURL += '/'; 78 | } 79 | return config; 80 | }); 81 | 82 | 83 | return instance; 84 | } 85 | 86 | 87 | // transform thenable response with error payload into rejected 88 | /* 89 | function thenableToRejectedAdapter(config) { 90 | const adapter = (thenableToRejectedAdapter !== config.adapter && config.adapter) || axios.defaults.adapter; 91 | 92 | return new Promise((resolve, reject) => { 93 | adapter(config) 94 | .then((response) => { 95 | response.data = parseData(response.data); 96 | if (response.data.error || (response.data.result && response.data.result.message)) { 97 | reject(createError( 98 | `Request failed with status code ${response.status}`, 99 | response.config, 100 | null, 101 | response.request, 102 | response, 103 | )); 104 | } 105 | 106 | resolve(response); 107 | }) 108 | .catch(reject); 109 | }); 110 | } 111 | */ 112 | 113 | /** 114 | * @param {string|any} data 115 | */ 116 | function parseData(data) { 117 | if (typeof data === 'string') { 118 | try { 119 | data = JSON.parse(data); 120 | } catch (error) { 121 | // eslint-disable-next-line no-console 122 | console.log(error); 123 | // eslint-disable-next-line no-console 124 | console.log(data); 125 | data = { 126 | error: { 127 | message: 'Invalid response: failed to parse JSON data. Looks like request URL is invalid.', 128 | }, 129 | }; 130 | } 131 | } 132 | return data; 133 | } 134 | -------------------------------------------------------------------------------- /src/api/post-signed-tx.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @param {MinterApiInstance} apiInstance 4 | * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] 5 | * @return {PostSignedTxInstance} 6 | */ 7 | export default function PostSignedTx(apiInstance, factoryAxiosOptions) { 8 | /** 9 | * @typedef {Function} PostSignedTxInstance 10 | * @param {string|Buffer} signedTx 11 | * @param {import('axios').AxiosRequestConfig} [axiosOptions] 12 | * @return {Promise} 13 | */ 14 | return function postSignedTx(signedTx, axiosOptions) { 15 | if (Buffer.isBuffer(signedTx)) { 16 | signedTx = `0x${signedTx.toString('hex')}`; 17 | } 18 | 19 | return apiInstance.post('send_transaction', { 20 | tx: signedTx, 21 | }, { 22 | ...factoryAxiosOptions, 23 | ...axiosOptions, 24 | }) 25 | .then((response) => { 26 | const resData = response.data; 27 | 28 | if (resData.transaction?.code > 0) { 29 | throw new Error(`Transaction included in the block with error code ${resData.transaction.code}: ${resData.transaction.log}`); 30 | } 31 | 32 | // @TODO check error code 33 | return resData.transaction || {hash: resData.hash}; 34 | }); 35 | }; 36 | } 37 | 38 | /** 39 | * @typedef {NodeTransaction|{hash: string}} PostTxResponse 40 | */ 41 | 42 | /** 43 | * @typedef NodeTransaction 44 | * @property {string} hash 45 | * @property {string} raw_tx 46 | * @property {string} height 47 | * @property {string} from 48 | * @property {string} nonce 49 | * @property {string} gas 50 | * @property {number} gas_price 51 | * @property {string} gas_coin 52 | * @property {number} type 53 | * @property {TxData} data 54 | * @property {string} payload 55 | * @property {object} tags 56 | */ 57 | -------------------------------------------------------------------------------- /src/check.js: -------------------------------------------------------------------------------- 1 | import {ecsign} from 'ethereumjs-util/dist/signature.js'; 2 | import {rlphash, sha256} from 'ethereumjs-util/dist/hash.js'; 3 | import {toBuffer as ethToBuffer} from 'ethereumjs-util/dist/bytes.js'; 4 | import secp256k1 from 'secp256k1'; 5 | import {defineProperties} from 'minterjs-tx'; 6 | import {convertToPip, convertFromPip, mPrefixStrip, toBuffer} from 'minterjs-util'; 7 | // import {convertToPip, convertFromPip} from 'minterjs-util/src/converter.js'; 8 | // import {mPrefixStrip} from 'minterjs-util/src/prefix.js'; 9 | import {integerToHexString, bufferToInteger, validateUint, validateAmount, getPrivateKeyFromSeedPhrase} from './utils.js'; 10 | 11 | class Check { 12 | constructor(data) { 13 | data = data || {}; 14 | if (typeof data === 'string') { 15 | data = mPrefixStrip(data); 16 | } 17 | 18 | // Define Properties 19 | const fields = [ 20 | { 21 | name: 'nonce', 22 | length: 16, 23 | allowLess: true, 24 | }, { 25 | name: 'chainId', 26 | length: 1, 27 | }, { 28 | name: 'dueBlock', 29 | length: 8, 30 | allowLess: true, 31 | }, { 32 | name: 'coin', 33 | length: 4, 34 | allowLess: true, 35 | }, { 36 | name: 'value', 37 | length: 32, 38 | allowLess: true, 39 | }, { 40 | name: 'gasCoin', 41 | length: 4, 42 | allowLess: true, 43 | }, { 44 | name: 'lock', 45 | allowZero: true, 46 | allowLess: true, 47 | length: 65, 48 | default: Buffer.from([]), 49 | }, { 50 | name: 'v', 51 | allowZero: true, 52 | default: Buffer.from([0x1c]), 53 | }, { 54 | name: 'r', 55 | length: 32, 56 | allowZero: true, 57 | allowLess: true, 58 | default: Buffer.from([]), 59 | }, { 60 | name: 's', 61 | length: 32, 62 | allowZero: true, 63 | allowLess: true, 64 | default: Buffer.from([]), 65 | }]; 66 | 67 | /** 68 | * Returns the rlp encoding of the transaction 69 | * @method serialize 70 | * @return {Buffer} 71 | * @memberof Transaction 72 | * @name serialize 73 | */ 74 | // attached serialize 75 | defineProperties(this, fields, data); 76 | } 77 | 78 | hash() { 79 | // don't hash last 4 fields (lock and signature) 80 | return rlphash(this.raw.slice(0, -4)); 81 | } 82 | 83 | sign(privateKey, password) { 84 | const messageHash = this.hash(false); 85 | 86 | if (typeof password === 'string') { 87 | password = Buffer.from(password, 'utf8'); 88 | } 89 | 90 | const passwordBuffer = sha256(password); 91 | const lock = secp256k1.ecdsaSign(messageHash, passwordBuffer); 92 | /** @type {Buffer} */ 93 | const lockWithRecovery = Buffer.alloc(65); 94 | lockWithRecovery.set(lock.signature, 0); 95 | lockWithRecovery[64] = lock.recid; 96 | this.lock = `0x${lockWithRecovery.toString('hex')}`; 97 | 98 | // don't hash last 3 signature fields 99 | const messageHashWithLock = rlphash(this.raw.slice(0, -3)); 100 | const sig = ecsign(messageHashWithLock, privateKey); 101 | Object.assign(this, sig); 102 | } 103 | } 104 | 105 | /** 106 | * @param {object} params 107 | * @param {string} [params.seedPhrase] 108 | * @param {string|Buffer} [params.privateKey] - hex or Buffer 109 | * @param {string} params.password - utf8 110 | * @param {string} params.nonce 111 | * @param {number} [params.chainId=1] 112 | * @param {number|string} params.coin 113 | * @param {number|string} params.value 114 | * @param {number|string} params.gasCoin 115 | * @param {number} [params.dueBlock=999999999] 116 | * @param {boolean} [isReturnObject] 117 | * @return {string|Check} 118 | */ 119 | export default function issueCheck({seedPhrase, privateKey, password, nonce, chainId = 1, coin, value, gasCoin = 0, dueBlock = 999999999} = {}, isReturnObject = false) { 120 | validateUint(dueBlock, 'dueBlock'); 121 | validateUint(coin, 'coin'); 122 | validateUint(gasCoin, 'gasCoin'); 123 | validateAmount(value, 'value'); 124 | 125 | if (!seedPhrase && !privateKey) { 126 | throw new Error('seedPhrase or privateKey are required'); 127 | } 128 | 129 | if (!privateKey && seedPhrase) { 130 | privateKey = getPrivateKeyFromSeedPhrase(seedPhrase); 131 | } 132 | 133 | privateKey = ethToBuffer(privateKey); 134 | 135 | let check = new Check({ 136 | nonce: Buffer.from(nonce.toString(), 'utf8'), 137 | chainId: integerToHexString(chainId), 138 | coin: integerToHexString(coin), 139 | value: `0x${convertToPip(value, 'hex')}`, 140 | gasCoin: integerToHexString(gasCoin), 141 | dueBlock: integerToHexString(dueBlock), 142 | }); 143 | check.sign(privateKey, password); 144 | 145 | return isReturnObject ? check : `Mc${check.serialize().toString('hex')}`; 146 | } 147 | 148 | 149 | /** 150 | * @param {string} rawCheck 151 | */ 152 | export function decodeCheck(rawCheck) { 153 | const check = new Check(rawCheck); 154 | return { 155 | nonce: check.nonce.toString('utf8'), 156 | chainId: bufferToInteger(check.chainId), 157 | coin: bufferToInteger(check.coin), 158 | value: convertFromPip(bufferToInteger(check.value)), 159 | gasCoin: bufferToInteger(check.gasCoin), 160 | dueBlock: bufferToInteger(check.dueBlock), 161 | }; 162 | } 163 | 164 | /** 165 | * @param {string|Buffer} rawCheck 166 | * @return {string} 167 | */ 168 | export function getGasCoinFromCheck(rawCheck) { 169 | try { 170 | const check = new Check(toBuffer(rawCheck)); 171 | return bufferToInteger(check.gasCoin); 172 | } catch (error) { 173 | error.message = `Can't decode check: ${error.message}`; 174 | throw error; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export {TX_TYPE} from 'minterjs-util'; 2 | 3 | export {API_TYPE_NODE, API_TYPE_GATE, ESTIMATE_SWAP_TYPE} from './variables.js'; 4 | export {default as Minter, default} from './minter.js'; 5 | export {default as MinterApi} from './api/index.js'; 6 | export {default as PostTx, EnsureNonce} from './api/post-tx.js'; 7 | export {default as PostSignedTx} from './api/post-signed-tx.js'; 8 | export {default as GetNonce} from './api/get-nonce.js'; 9 | export {default as GetCoinInfo} from './api/get-coin-info.js'; 10 | export {default as GetMinGasPrice} from './api/get-min-gas-price.js'; 11 | export {default as EstimateCoinSell} from './api/estimate-coin-sell.js'; 12 | export {default as EstimateCoinSellAll} from './api/estimate-coin-sell-all.js'; 13 | export {default as EstimateCoinBuy} from './api/estimate-coin-buy.js'; 14 | export {default as EstimateTxCommission, FEE_PRECISION_SETTING} from './api/estimate-tx-commission.js'; 15 | export {ReplaceCoinSymbol, ReplaceCoinSymbolByPath, GetCoinId, ReplaceCoinId, ReplaceCoinIdByPath, GetCoinSymbol} from './api/replace-coin.js'; 16 | export {default as issueCheck, decodeCheck, getGasCoinFromCheck} from './check.js'; 17 | export {prepareLink, decodeLink} from './link.js'; 18 | 19 | export {default as prepareSignedTx, decodeTx, prepareTx, makeSignature} from './tx.js'; 20 | export {default as getTxData} from './tx-data/index.js'; 21 | 22 | export {default as RedeemCheckTxData} from './tx-data/redeem-check.js'; 23 | export {default as SendTxData} from './tx-data/send.js'; 24 | export {default as MultisendTxData} from './tx-data/multisend.js'; 25 | export {default as SellTxData} from './tx-data/convert-sell.js'; 26 | export {default as SellAllTxData} from './tx-data/convert-sell-all.js'; 27 | export {default as BuyTxData} from './tx-data/convert-buy.js'; 28 | export {default as DeclareCandidacyTxData} from './tx-data/candidacy-declare.js'; 29 | export {default as SetCandidateOnTxData} from './tx-data/candidate-set-on.js'; 30 | export {default as SetCandidateOffTxData} from './tx-data/candidate-set-off.js'; 31 | export {default as EditCandidateTxData} from './tx-data/candidate-edit.js'; 32 | export {default as EditCandidatePublicKeyTxData} from './tx-data/candidate-edit-public-key.js'; 33 | export {default as DelegateTxData} from './tx-data/stake-delegate.js'; 34 | export {default as UnbondTxData} from './tx-data/stake-unbond.js'; 35 | export {default as CreateCoinTxData} from './tx-data/create-coin.js'; 36 | export {default as RecreateCoinTxData} from './tx-data/recreate-coin.js'; 37 | export {default as EditTickerOwnerTxData} from './tx-data/edit-ticker-owner.js'; 38 | export {default as CreateMultisigTxData} from './tx-data/create-multisig.js'; 39 | export {default as EditMultisigTxData} from './tx-data/edit-multisig.js'; 40 | export {default as SetHaltBlockTxData} from './tx-data/vote-halt-block.js'; 41 | export {default as PriceVoteTxData} from './tx-data/vote-price.js'; 42 | export {default as AddLiquidityTxData} from './tx-data/pool-add-liquidity.js'; 43 | export {default as RemoveLiquidityTxData} from './tx-data/pool-remove-liquidity.js'; 44 | export {default as BuyPoolTxData} from './tx-data/pool-buy.js'; 45 | export {default as SellPoolTxData} from './tx-data/pool-sell.js'; 46 | export {default as SellAllPoolTxData} from './tx-data/pool-sell-all.js'; 47 | export {default as EditCandidateCommissionTxData} from './tx-data/candidate-edit-commission.js'; 48 | export {default as MoveStakeTxData} from './tx-data/stake-move.js'; 49 | export {default as MintTokenTxData} from './tx-data/token-mint.js'; 50 | export {default as BurnTokenTxData} from './tx-data/token-burn.js'; 51 | export {default as CreateTokenTxData} from './tx-data/token-create.js'; 52 | export {default as RecreateTokenTxData} from './tx-data/token-recreate.js'; 53 | export {default as VoteCommissionTxData} from './tx-data/vote-commission.js'; 54 | export {default as VoteUpdateTxData} from './tx-data/vote-update.js'; 55 | export {default as CreatePoolTxData} from './tx-data/pool-create.js'; 56 | export {default as AddLimitOrderTxData} from './tx-data/limit-order-add.js'; 57 | export {default as RemoveLimitOrderTxData} from './tx-data/limit-order-remove.js'; 58 | export {default as LockStakeTxData} from './tx-data/stake-lock.js'; 59 | export {default as LockTxData} from './tx-data/lock.js'; 60 | -------------------------------------------------------------------------------- /src/link.js: -------------------------------------------------------------------------------- 1 | import {toBuffer as toBufferUtil} from 'ethereumjs-util/dist/bytes.js'; 2 | import {decode as rlpDecode} from 'rlp'; 3 | import {isHexPrefixed} from 'ethjs-util'; 4 | import {TxDataRedeemCheck, defineProperties} from 'minterjs-tx'; 5 | import {TX_TYPE, normalizeTxType} from 'minterjs-util'; 6 | import {ensureBufferData, decodeTxData} from './tx-data/index.js'; 7 | import RedeemCheckTxData from './tx-data/redeem-check.js'; 8 | import {bufferToInteger, integerToHexString} from './utils.js'; 9 | 10 | const DEFAULT_LINK_HOST = 'https://bip.to'; 11 | 12 | 13 | class Link { 14 | constructor(data) { 15 | data = data || {}; 16 | 17 | // Define Properties 18 | const fields = [{ 19 | name: 'type', 20 | length: 1, 21 | }, { 22 | name: 'data', 23 | alias: 'input', 24 | }, { 25 | name: 'payload', 26 | allowZero: true, 27 | default: Buffer.from([]), 28 | }, { 29 | name: 'nonce', 30 | length: 32, 31 | allowLess: true, 32 | }, { 33 | name: 'gasPrice', 34 | length: 32, 35 | allowLess: true, 36 | }, { 37 | name: 'gasCoin', 38 | length: 4, 39 | allowLess: true, 40 | storeNullAsArray: true, 41 | }]; 42 | 43 | /** 44 | * Returns the rlp encoding of the transaction 45 | * @method serialize 46 | * @return {Buffer} 47 | * @memberof Transaction 48 | * @name serialize 49 | */ 50 | // attached serialize 51 | defineProperties(this, fields, data); 52 | } 53 | } 54 | 55 | /** 56 | * @typedef {object} LinkParams 57 | * @property {number|string} [nonce] 58 | * @property {number|string} [gasPrice] 59 | * @property {number|string} [gasCoin] 60 | * @property {string|Buffer|TX_TYPE} type 61 | * @property {string|Buffer|TX_TYPE} [txType] - deprecated 62 | * @property {Buffer|object|TxData} data 63 | * @property {Buffer} [txData] - deprecated 64 | * @property {string} [payload] 65 | * @property {string} [message] - deprecated 66 | * @property {string} [password] 67 | */ 68 | 69 | /** 70 | * @param {LinkParams} txParams 71 | * @param {string} [linkHost] 72 | * @return {string} 73 | */ 74 | export function prepareLink(txParams = {}, linkHost = DEFAULT_LINK_HOST) { 75 | const {nonce, gasPrice, gasCoin, type, txType, data, txData, password} = txParams; 76 | 77 | const txProps = { 78 | nonce: nonce || nonce === 0 ? integerToHexString(nonce) : undefined, 79 | gasPrice: gasPrice || gasPrice === 0 ? integerToHexString(gasPrice) : undefined, 80 | gasCoin: gasCoin || gasCoin === 0 ? integerToHexString(gasCoin) : undefined, 81 | type: type || txType, 82 | data: ensureBufferData(data || txData, type || txType), 83 | }; 84 | 85 | // eslint-disable-next-line unicorn/consistent-destructuring 86 | let payload = txParams.message || txParams.payload; 87 | if (payload) { 88 | if (typeof payload === 'string') { 89 | payload = Buffer.from(payload, 'utf8'); 90 | } 91 | txProps.payload = payload; 92 | } 93 | 94 | // ensure no ending slash 95 | linkHost = linkHost.replace(/\/$/, ''); 96 | // ensure scheme 97 | if (linkHost.indexOf('://') === -1) { 98 | linkHost = `https://${linkHost}`; 99 | } 100 | 101 | const tx = new Link(txProps); 102 | let result = `${linkHost}/tx/${base64urlEncode(tx.serialize())}`; 103 | if (password) { 104 | result += `?p=${base64urlEncode(toBuffer(password))}`; 105 | } 106 | 107 | return result; 108 | } 109 | 110 | 111 | /** 112 | * @param {string} url 113 | * @param {object} [options] 114 | * @param {string} [options.address] 115 | * @param {string} [options.seedPhrase] 116 | * @param {string} [options.privateKey] 117 | * @param {boolean} [options.decodeCheck] 118 | * @return {TxParams} 119 | */ 120 | export function decodeLink(url, {address, seedPhrase, privateKey, decodeCheck} = {}) { 121 | const txBase64 = url.replace(/^.*\/tx\//, '').replace(/\?.*$/, ''); 122 | const txBytes = rlpDecode(base64urlDecode(txBase64)); 123 | const passwordBase64 = url.search(/[?&]p=/) >= 0 ? url.replace(/^.*[?&]p=/, '') : ''; 124 | const password = passwordBase64 ? Buffer.from(base64urlDecode(passwordBase64)) : ''; 125 | const tx = new Link(txBytes); 126 | const txType = normalizeTxType(tx.type); 127 | if (txType === TX_TYPE.REDEEM_CHECK && password) { 128 | if (!seedPhrase && !privateKey && !address) { 129 | throw new Error('address or seedPhrase or privateKey are required if link has password'); 130 | } 131 | 132 | // get check from data 133 | const {check} = new TxDataRedeemCheck(tx.data); 134 | // proof from password 135 | const txData = new RedeemCheckTxData({check}, {password, address, seedPhrase, privateKey}).serialize(); 136 | tx.data = txData; 137 | } 138 | const txData = decodeTxData(tx.type, tx.data, {decodeCheck}); 139 | 140 | return { 141 | nonce: tx.nonce.length > 0 ? bufferToInteger(tx.nonce) : undefined, 142 | gasPrice: tx.gasPrice.length > 0 ? bufferToInteger(tx.gasPrice) : undefined, 143 | // [] === undefined, === 0 144 | gasCoin: Array.isArray(tx.gasCoin) ? undefined : bufferToInteger(tx.gasCoin), 145 | type: txType, 146 | data: txData, 147 | payload: tx.payload.toString('utf8'), 148 | }; 149 | } 150 | 151 | /** 152 | * @param {ByteArray} byteArray 153 | */ 154 | function base64urlEncode(byteArray) { 155 | return Buffer.from(byteArray).toString('base64').replace(/\+/g, '-').replace(/\//g, '_') 156 | .replace(/=/g, ''); 157 | } 158 | 159 | /** 160 | * @param {string} base64urlString 161 | */ 162 | function base64urlDecode(base64urlString) { 163 | const padModulus = base64urlString.length % 4; 164 | const padLength = padModulus ? 4 - padModulus : 0; 165 | const pad = Array.from({length: padLength}, () => '=').join(''); 166 | return Buffer.from(base64urlString + pad, 'base64'); 167 | } 168 | 169 | /** 170 | * toBuffer which supports UTF8 strings 171 | * @param {ToBufferInputTypes} value 172 | * @return {Buffer} 173 | */ 174 | function toBuffer(value) { 175 | return typeof value === 'string' && !isHexPrefixed(value) ? Buffer.from(value, 'utf8') : toBufferUtil(value); 176 | } 177 | -------------------------------------------------------------------------------- /src/minter.js: -------------------------------------------------------------------------------- 1 | import MinterApi from './api/index.js'; 2 | import GetNonce from './api/get-nonce.js'; 3 | import GetCoinInfo from './api/get-coin-info.js'; 4 | import GetMinGasPrice from './api/get-min-gas-price.js'; 5 | import PostTx, {EnsureNonce} from './api/post-tx.js'; 6 | import PostSignedTx from './api/post-signed-tx.js'; 7 | import EstimateCoinSell from './api/estimate-coin-sell.js'; 8 | import EstimateCoinSellAll from './api/estimate-coin-sell-all.js'; 9 | import EstimateCoinBuy from './api/estimate-coin-buy.js'; 10 | import EstimateTxCommission from './api/estimate-tx-commission.js'; 11 | import {ReplaceCoinSymbol, ReplaceCoinSymbolByPath, GetCoinId, ReplaceCoinId, ReplaceCoinIdByPath, GetCoinSymbol} from './api/replace-coin.js'; 12 | import GetCommissionPrice from './api/get-commission-price.js'; 13 | import GetPoolInfo from './api/get-pool-info.js'; 14 | 15 | /** 16 | * @param {object} [options] 17 | * @param {string} [options.apiType] 18 | * @param {string} [options.chainId] 19 | * @param {string} [options.baseURL] 20 | * @constructor 21 | */ 22 | export default function Minter(options) { 23 | const apiInstance = new MinterApi(options); 24 | this.apiInstance = apiInstance; 25 | 26 | this.postTx = PostTx(apiInstance); 27 | this.postSignedTx = PostSignedTx(apiInstance); 28 | 29 | this.getNonce = GetNonce(apiInstance); 30 | this.ensureNonce = EnsureNonce(apiInstance); 31 | 32 | this.getCoinInfo = GetCoinInfo(apiInstance); 33 | 34 | this.getMinGasPrice = GetMinGasPrice(apiInstance); 35 | 36 | this.estimateCoinSell = EstimateCoinSell(apiInstance); 37 | this.estimateCoinSellAll = EstimateCoinSellAll(apiInstance); 38 | this.estimateCoinBuy = EstimateCoinBuy(apiInstance); 39 | this.estimateTxCommission = EstimateTxCommission(apiInstance); 40 | 41 | this.replaceCoinSymbol = ReplaceCoinSymbol(apiInstance); 42 | this.replaceCoinId = ReplaceCoinId(apiInstance); 43 | this.replaceCoinSymbolByPath = ReplaceCoinSymbolByPath(apiInstance); 44 | this.replaceCoinIdByPath = ReplaceCoinIdByPath(apiInstance); 45 | this.getCoinId = GetCoinId(apiInstance); 46 | this.getCoinSymbol = GetCoinSymbol(apiInstance); 47 | 48 | this.getPoolInfo = GetPoolInfo(apiInstance); 49 | 50 | this.getCommissionPrice = GetCommissionPrice(apiInstance); 51 | } 52 | -------------------------------------------------------------------------------- /src/tx-data/candidacy-declare.js: -------------------------------------------------------------------------------- 1 | import {TxDataDeclareCandidacy} from 'minterjs-tx'; 2 | // import TxDataDeclareCandidacy from 'minterjs-tx/src/tx-data/declare-candidacy.js'; 3 | import {convertToPip, toBuffer} from 'minterjs-util'; 4 | // import {convertToPip} from 'minterjs-util/src/converter'; 5 | // import {toBuffer} from 'minterjs-util/src/prefix'; 6 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, dataToAddress, dataToPublicKey, integerToHexString, validateAddress, validateAmount, validateUint, validatePublicKey} from '../utils.js'; 7 | 8 | /** 9 | * @param {object} txData 10 | * @param {string} txData.address 11 | * @param {string} txData.publicKey 12 | * @param {number|string} txData.commission 13 | * @param {number|string} txData.coin - coin id 14 | * @param {number|string} txData.stake 15 | * @param {TxOptions} [options] 16 | * @constructor 17 | */ 18 | export default function DeclareCandidacyTxData({address, publicKey, commission, coin, stake}, options = {}) { 19 | if (!options.disableValidation) { 20 | validateAddress(address, 'address'); 21 | validatePublicKey(publicKey, 'publicKey'); 22 | validateUint(commission, 'commission'); 23 | validateUint(coin, 'coin'); 24 | validateAmount(stake, 'stake'); 25 | } 26 | 27 | this.address = address; 28 | this.publicKey = publicKey; 29 | this.commission = commission; 30 | this.coin = coin; 31 | this.stake = stake; 32 | 33 | this.txData = new TxDataDeclareCandidacy({ 34 | address: toBuffer(address), 35 | publicKey: toBuffer(publicKey), 36 | commission: integerToHexString(commission), 37 | coin: integerToHexString(coin), 38 | stake: `0x${convertToPip(stake, 'hex')}`, 39 | }); 40 | 41 | proxyNestedTxData(this); 42 | } 43 | 44 | /** 45 | * @param {object} txData 46 | * @param {Buffer|string} txData.address 47 | * @param {Buffer|string} txData.publicKey 48 | * @param {Buffer|string} txData.commission 49 | * @param {Buffer|string} txData.coin 50 | * @param {Buffer|string} txData.stake 51 | * @param {TxOptions} [options] 52 | * @return {DeclareCandidacyTxData} 53 | */ 54 | DeclareCandidacyTxData.fromBufferFields = function fromBufferFields({address, publicKey, commission, coin, stake}, options = {}) { 55 | return new DeclareCandidacyTxData({ 56 | address: dataToAddress(address), 57 | publicKey: dataToPublicKey(publicKey), 58 | commission: dataToInteger(commission), 59 | coin: dataToInteger(coin), 60 | stake: dataPipToAmount(stake), 61 | }, options); 62 | }; 63 | 64 | /** 65 | * @param {Buffer|string} data 66 | * @return {DeclareCandidacyTxData} 67 | */ 68 | DeclareCandidacyTxData.fromRlp = function fromRlp(data) { 69 | return DeclareCandidacyTxData.fromBufferFields(new TxDataDeclareCandidacy(data)); 70 | }; 71 | -------------------------------------------------------------------------------- /src/tx-data/candidate-edit-commission.js: -------------------------------------------------------------------------------- 1 | import {TxDataEditCandidateCommission} from 'minterjs-tx'; 2 | import {toBuffer} from 'minterjs-util'; 3 | import {dataToInteger, dataToPublicKey, integerToHexString, proxyNestedTxData, validatePublicKey, validateUint} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {string} txData.publicKey 8 | * @param {number|string} txData.commission 9 | * @param {TxOptions} [options] 10 | * @constructor 11 | */ 12 | export default function EditCandidateCommissionTxData({publicKey, commission}, options = {}) { 13 | if (!options.disableValidation) { 14 | validatePublicKey(publicKey, 'publicKey'); 15 | validateUint(commission, 'commission'); 16 | } 17 | 18 | this.publicKey = publicKey; 19 | this.commission = commission; 20 | 21 | this.txData = new TxDataEditCandidateCommission({ 22 | publicKey: toBuffer(publicKey), 23 | commission: integerToHexString(commission), 24 | }); 25 | 26 | proxyNestedTxData(this); 27 | } 28 | 29 | /** 30 | * @param {object} txData 31 | * @param {Buffer|string} txData.publicKey 32 | * @param {Buffer|string} txData.commission 33 | * @param {TxOptions} [options] 34 | * @return {EditCandidateCommissionTxData} 35 | */ 36 | EditCandidateCommissionTxData.fromBufferFields = function fromBufferFields({publicKey, commission}, options = {}) { 37 | return new EditCandidateCommissionTxData({ 38 | publicKey: dataToPublicKey(publicKey), 39 | commission: dataToInteger(commission), 40 | }, options); 41 | }; 42 | 43 | /** 44 | * @param {Buffer|string} data 45 | * @return {EditCandidateCommissionTxData} 46 | */ 47 | EditCandidateCommissionTxData.fromRlp = function fromRlp(data) { 48 | return EditCandidateCommissionTxData.fromBufferFields(new TxDataEditCandidateCommission(data)); 49 | }; 50 | -------------------------------------------------------------------------------- /src/tx-data/candidate-edit-public-key.js: -------------------------------------------------------------------------------- 1 | import {TxDataEditCandidatePublicKey} from 'minterjs-tx'; 2 | import {toBuffer} from 'minterjs-util'; 3 | import {dataToPublicKey, proxyNestedTxData, validatePublicKey} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {string} txData.publicKey 8 | * @param {string} txData.newPublicKey 9 | * @param {TxOptions} [options] 10 | * @constructor 11 | */ 12 | export default function EditCandidatePublicKeyTxData({publicKey, newPublicKey}, options = {}) { 13 | if (!options.disableValidation) { 14 | validatePublicKey(publicKey, 'publicKey'); 15 | validatePublicKey(newPublicKey, 'newPublicKey'); 16 | } 17 | 18 | this.publicKey = publicKey; 19 | this.newPublicKey = newPublicKey; 20 | 21 | this.txData = new TxDataEditCandidatePublicKey({ 22 | publicKey: toBuffer(publicKey), 23 | newPublicKey: toBuffer(newPublicKey), 24 | }); 25 | 26 | proxyNestedTxData(this); 27 | } 28 | 29 | /** 30 | * @param {object} txData 31 | * @param {Buffer|string} txData.publicKey 32 | * @param {Buffer|string} txData.newPublicKey 33 | * @param {TxOptions} [options] 34 | * @return {EditCandidatePublicKeyTxData} 35 | */ 36 | EditCandidatePublicKeyTxData.fromBufferFields = function fromBufferFields({publicKey, newPublicKey}, options = {}) { 37 | return new EditCandidatePublicKeyTxData({ 38 | publicKey: dataToPublicKey(publicKey), 39 | newPublicKey: dataToPublicKey(newPublicKey), 40 | }, options); 41 | }; 42 | 43 | /** 44 | * @param {Buffer|string} data 45 | * @return {EditCandidatePublicKeyTxData} 46 | */ 47 | EditCandidatePublicKeyTxData.fromRlp = function fromRlp(data) { 48 | return EditCandidatePublicKeyTxData.fromBufferFields(new TxDataEditCandidatePublicKey(data)); 49 | }; 50 | -------------------------------------------------------------------------------- /src/tx-data/candidate-edit.js: -------------------------------------------------------------------------------- 1 | import {TxDataEditCandidate} from 'minterjs-tx'; 2 | // import TxDataEditCandidate from 'minterjs-tx/src/tx-data/edit-candidate.js'; 3 | import {toBuffer} from 'minterjs-util'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import {dataToAddress, dataToPublicKey, proxyNestedTxData, validateAddress, validatePublicKey} from '../utils.js'; 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {string} txData.publicKey 10 | * @param {string} txData.rewardAddress 11 | * @param {string} txData.ownerAddress 12 | * @param {string} txData.controlAddress 13 | * @param {TxOptions} [options] 14 | * @constructor 15 | */ 16 | export default function EditCandidateTxData({publicKey, rewardAddress, ownerAddress, controlAddress}, options = {}) { 17 | if (!options.disableValidation) { 18 | validatePublicKey(publicKey, 'publicKey'); 19 | validateAddress(rewardAddress, 'rewardAddress'); 20 | validateAddress(ownerAddress, 'ownerAddress'); 21 | validateAddress(controlAddress, 'controlAddress'); 22 | } 23 | 24 | this.publicKey = publicKey; 25 | this.rewardAddress = rewardAddress; 26 | this.ownerAddress = ownerAddress; 27 | this.controlAddress = controlAddress; 28 | 29 | this.txData = new TxDataEditCandidate({ 30 | publicKey: toBuffer(publicKey), 31 | rewardAddress: toBuffer(rewardAddress), 32 | ownerAddress: toBuffer(ownerAddress), 33 | controlAddress: toBuffer(controlAddress), 34 | }); 35 | 36 | proxyNestedTxData(this); 37 | } 38 | 39 | /** 40 | * @param {object} txData 41 | * @param {Buffer|string} txData.publicKey 42 | * @param {Buffer|string} txData.rewardAddress 43 | * @param {Buffer|string} txData.ownerAddress 44 | * @param {Buffer|string} txData.controlAddress 45 | * @param {TxOptions} [options] 46 | * @return {EditCandidateTxData} 47 | */ 48 | EditCandidateTxData.fromBufferFields = function fromBufferFields({publicKey, rewardAddress, ownerAddress, controlAddress}, options = {}) { 49 | return new EditCandidateTxData({ 50 | publicKey: dataToPublicKey(publicKey), 51 | rewardAddress: dataToAddress(rewardAddress), 52 | ownerAddress: dataToAddress(ownerAddress), 53 | controlAddress: dataToAddress(controlAddress), 54 | }, options); 55 | }; 56 | 57 | /** 58 | * @param {Buffer|string} data 59 | * @return {EditCandidateTxData} 60 | */ 61 | EditCandidateTxData.fromRlp = function fromRlp(data) { 62 | return EditCandidateTxData.fromBufferFields(new TxDataEditCandidate(data)); 63 | }; 64 | -------------------------------------------------------------------------------- /src/tx-data/candidate-set-off.js: -------------------------------------------------------------------------------- 1 | export {default} from './candidate-set-on.js'; 2 | -------------------------------------------------------------------------------- /src/tx-data/candidate-set-on.js: -------------------------------------------------------------------------------- 1 | import {TxDataSetCandidateOn} from 'minterjs-tx'; 2 | // import TxDataSetCandidateOn from 'minterjs-tx/src/tx-data/set-candidate-on.js'; 3 | import {toBuffer} from 'minterjs-util'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import {dataToPublicKey, proxyNestedTxData, validatePublicKey} from '../utils.js'; 6 | 7 | /** 8 | * @param {string} publicKey 9 | * @param {TxOptions} [options] 10 | * @constructor 11 | */ 12 | export default function SetCandidateOnTxData({publicKey}, options = {}) { 13 | if (!options.disableValidation) { 14 | validatePublicKey(publicKey, 'publicKey'); 15 | } 16 | 17 | this.publicKey = publicKey; 18 | 19 | this.txData = new TxDataSetCandidateOn({ 20 | publicKey: toBuffer(publicKey), 21 | }); 22 | 23 | proxyNestedTxData(this); 24 | } 25 | 26 | /** 27 | * @param {Buffer|string} publicKey 28 | * @param {TxOptions} [options] 29 | * @return {SetCandidateOnTxData} 30 | */ 31 | SetCandidateOnTxData.fromBufferFields = function fromBufferFields({publicKey}, options = {}) { 32 | return new SetCandidateOnTxData({ 33 | publicKey: dataToPublicKey(publicKey), 34 | }, options); 35 | }; 36 | 37 | /** 38 | * @param {Buffer|string} data 39 | * @return {SetCandidateOnTxData} 40 | */ 41 | SetCandidateOnTxData.fromRlp = function fromRlp(data) { 42 | return SetCandidateOnTxData.fromBufferFields(new TxDataSetCandidateOn(data)); 43 | }; 44 | -------------------------------------------------------------------------------- /src/tx-data/convert-buy.js: -------------------------------------------------------------------------------- 1 | import {TxDataBuy} from 'minterjs-tx'; 2 | import {convertToPip, COIN_MAX_AMOUNT} from 'minterjs-util'; 3 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 4 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 5 | 6 | /** 7 | * @param {object} txData 8 | * @param {number|string} txData.coinToSell - coin id 9 | * @param {number|string} txData.coinToBuy - coin id 10 | * @param {number|string} txData.valueToBuy 11 | * @param {number|string} [txData.maximumValueToSell] 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function BuyTxData({coinToSell, coinToBuy, valueToBuy, maximumValueToSell = COIN_MAX_AMOUNT}, options = {}) { 16 | if (!options.disableValidation) { 17 | validateUint(coinToSell, 'coinToSell'); 18 | validateUint(coinToBuy, 'coinToBuy'); 19 | validateAmount(valueToBuy, 'valueToBuy'); 20 | validateAmount(maximumValueToSell, 'maximumValueToSell'); 21 | } 22 | 23 | this.coinToSell = coinToSell; 24 | this.coinToBuy = coinToBuy; 25 | this.valueToBuy = valueToBuy; 26 | this.maximumValueToSell = maximumValueToSell; 27 | 28 | this.txData = new TxDataBuy({ 29 | coinToSell: integerToHexString(coinToSell), 30 | coinToBuy: integerToHexString(coinToBuy), 31 | valueToBuy: `0x${convertToPip(valueToBuy, 'hex')}`, 32 | maximumValueToSell: `0x${convertToPip(maximumValueToSell, 'hex')}`, 33 | }); 34 | 35 | proxyNestedTxData(this); 36 | } 37 | 38 | /** 39 | * @param {object} txData 40 | * @param {Buffer|string} txData.coinToSell 41 | * @param {Buffer|string} txData.valueToBuy 42 | * @param {Buffer|string} txData.coinToBuy 43 | * @param {Buffer|string} txData.maximumValueToSell 44 | * @param {TxOptions} [options] 45 | * @return {BuyTxData} 46 | */ 47 | BuyTxData.fromBufferFields = function fromBufferFields({coinToSell, valueToBuy, coinToBuy, maximumValueToSell}, options = {}) { 48 | return new BuyTxData({ 49 | coinToSell: dataToInteger(coinToSell), 50 | coinToBuy: dataToInteger(coinToBuy), 51 | valueToBuy: dataPipToAmount(valueToBuy), 52 | maximumValueToSell: dataPipToAmount(maximumValueToSell), 53 | }, options); 54 | }; 55 | 56 | /** 57 | * @param {Buffer|string} data 58 | * @return {BuyTxData} 59 | */ 60 | BuyTxData.fromRlp = function fromRlp(data) { 61 | return BuyTxData.fromBufferFields(new TxDataBuy(data)); 62 | }; 63 | -------------------------------------------------------------------------------- /src/tx-data/convert-sell-all.js: -------------------------------------------------------------------------------- 1 | import {TxDataSellAll} from 'minterjs-tx'; 2 | // import TxDataSellAll from 'minterjs-tx/src/tx-data/sell-all.js'; 3 | import {convertToPip} from 'minterjs-util'; 4 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 5 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {number|string} txData.coinToSell - coin id 10 | * @param {number|string} txData.coinToBuy - coin id 11 | * @param {number|string} [txData.minimumValueToBuy=0] 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function SellAllTxData({coinToSell, coinToBuy, minimumValueToBuy = 0}, options = {}) { 16 | if (!options.disableValidation) { 17 | validateUint(coinToSell, 'coinToSell'); 18 | validateUint(coinToBuy, 'coinToBuy'); 19 | validateAmount(minimumValueToBuy, 'minimumValueToBuy'); 20 | } 21 | 22 | this.coinToSell = coinToSell; 23 | this.coinToBuy = coinToBuy; 24 | this.minimumValueToBuy = minimumValueToBuy; 25 | 26 | this.txData = new TxDataSellAll({ 27 | coinToSell: integerToHexString(coinToSell), 28 | coinToBuy: integerToHexString(coinToBuy), 29 | minimumValueToBuy: `0x${convertToPip(minimumValueToBuy, 'hex')}`, 30 | }); 31 | 32 | proxyNestedTxData(this); 33 | } 34 | 35 | /** 36 | * @param {object} txData 37 | * @param {Buffer|string} txData.coinToSell 38 | * @param {Buffer|string} txData.coinToBuy 39 | * @param {Buffer|string} txData.minimumValueToBuy 40 | * @param {TxOptions} [options] 41 | * @return {SellAllTxData} 42 | */ 43 | SellAllTxData.fromBufferFields = function fromBufferFields({coinToSell, coinToBuy, minimumValueToBuy}, options = {}) { 44 | return new SellAllTxData({ 45 | coinToSell: dataToInteger(coinToSell), 46 | coinToBuy: dataToInteger(coinToBuy), 47 | minimumValueToBuy: dataPipToAmount(minimumValueToBuy), 48 | }, options); 49 | }; 50 | 51 | /** 52 | * @param {Buffer|string} data 53 | * @return {SellAllTxData} 54 | */ 55 | SellAllTxData.fromRlp = function fromRlp(data) { 56 | return SellAllTxData.fromBufferFields(new TxDataSellAll(data)); 57 | }; 58 | -------------------------------------------------------------------------------- /src/tx-data/convert-sell.js: -------------------------------------------------------------------------------- 1 | import {TxDataSell} from 'minterjs-tx'; 2 | // import TxDataSell from 'minterjs-tx/src/tx-data/sell.js'; 3 | // import {TX_TYPE} from 'minterjs-tx/src/tx-types.js'; 4 | import {convertToPip} from 'minterjs-util'; 5 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 6 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 7 | 8 | /** 9 | * @param {object} txData 10 | * @param {number|string} txData.coinToSell - coin id 11 | * @param {number|string} txData.coinToBuy - coin id 12 | * @param {number|string} txData.valueToSell 13 | * @param {number|string} [txData.minimumValueToBuy=0] 14 | * @param {TxOptions} [options] 15 | * @constructor 16 | */ 17 | export default function SellTxData({coinToSell, coinToBuy, valueToSell, minimumValueToBuy = 0}, options = {}) { 18 | if (!options.disableValidation) { 19 | validateUint(coinToSell, 'coinToSell'); 20 | validateUint(coinToBuy, 'coinToBuy'); 21 | validateAmount(valueToSell, 'valueToSell'); 22 | validateAmount(minimumValueToBuy, 'minimumValueToBuy'); 23 | } 24 | 25 | this.coinToSell = coinToSell; 26 | this.coinToBuy = coinToBuy; 27 | this.valueToSell = valueToSell; 28 | this.minimumValueToBuy = minimumValueToBuy; 29 | 30 | this.txData = new TxDataSell({ 31 | coinToSell: integerToHexString(coinToSell), 32 | coinToBuy: integerToHexString(coinToBuy), 33 | valueToSell: `0x${convertToPip(valueToSell, 'hex')}`, 34 | minimumValueToBuy: `0x${convertToPip(minimumValueToBuy, 'hex')}`, 35 | }); 36 | 37 | proxyNestedTxData(this); 38 | } 39 | 40 | /** 41 | * @param {object} txData 42 | * @param {Buffer|string} txData.coinToSell 43 | * @param {Buffer|string} txData.valueToSell 44 | * @param {Buffer|string} txData.coinToBuy 45 | * @param {Buffer|string} txData.minimumValueToBuy 46 | * @param {TxOptions} [options] 47 | * @return {SellTxData} 48 | */ 49 | SellTxData.fromBufferFields = function fromBufferFields({coinToSell, valueToSell, coinToBuy, minimumValueToBuy}, options = {}) { 50 | return new SellTxData({ 51 | coinToSell: dataToInteger(coinToSell), 52 | coinToBuy: dataToInteger(coinToBuy), 53 | valueToSell: dataPipToAmount(valueToSell), 54 | minimumValueToBuy: dataPipToAmount(minimumValueToBuy), 55 | }, options); 56 | }; 57 | 58 | /** 59 | * @param {Buffer|string} data 60 | * @return {SellTxData} 61 | */ 62 | SellTxData.fromRlp = function fromRlp(data) { 63 | return SellTxData.fromBufferFields(new TxDataSell(data)); 64 | }; 65 | -------------------------------------------------------------------------------- /src/tx-data/create-coin.js: -------------------------------------------------------------------------------- 1 | import {TxDataCreateCoin} from 'minterjs-tx'; 2 | // import TxDataCreateCoin from 'minterjs-tx/src/tx-data/create-coin.js'; 3 | // import {coinToBuffer} from 'minterjs-tx/src/helpers.js'; 4 | import {convertToPip, toBuffer, coinToBuffer, bufferToCoin, COIN_MAX_MAX_SUPPLY} from 'minterjs-util'; 5 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 6 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateTicker, validateMaxSupply} from '../utils.js'; 7 | 8 | /** 9 | * @param {object} txData 10 | * @param {string} [txData.name] 11 | * @param {string} txData.symbol 12 | * @param {number|string} txData.initialAmount 13 | * @param {number|string} txData.initialReserve 14 | * @param {number|string} txData.constantReserveRatio 15 | * @param {number|string} [txData.maxSupply] 16 | * @param {TxOptions} [options] 17 | * @constructor 18 | */ 19 | export default function CreateCoinTxData({name = '', symbol, initialAmount, initialReserve, constantReserveRatio, maxSupply = COIN_MAX_MAX_SUPPLY}, options = {}) { 20 | if (!options.disableValidation) { 21 | validateTicker(symbol, 'symbol'); 22 | validateAmount(initialAmount, 'initialAmount'); 23 | validateAmount(initialReserve, 'initialReserve'); 24 | validateMaxSupply(maxSupply, initialAmount); 25 | } 26 | 27 | this.name = name; 28 | this.symbol = symbol; 29 | this.initialAmount = initialAmount; 30 | this.initialReserve = initialReserve; 31 | this.constantReserveRatio = constantReserveRatio; 32 | this.maxSupply = maxSupply; 33 | 34 | this.txData = new TxDataCreateCoin({ 35 | name: Buffer.from(name.toString(), 'utf8'), 36 | symbol: coinToBuffer(symbol), 37 | initialAmount: `0x${convertToPip(initialAmount, 'hex')}`, 38 | initialReserve: `0x${convertToPip(initialReserve, 'hex')}`, 39 | constantReserveRatio: integerToHexString(constantReserveRatio), 40 | maxSupply: `0x${convertToPip(maxSupply, 'hex')}`, 41 | }, {forceDefaultValues: true}); 42 | 43 | proxyNestedTxData(this); 44 | } 45 | 46 | /** 47 | * @param {object} txData 48 | * @param {Buffer|string} txData.name 49 | * @param {Buffer|string} txData.symbol 50 | * @param {Buffer|string|number} txData.initialAmount 51 | * @param {Buffer|string|number} txData.initialReserve 52 | * @param {Buffer|string|number} txData.constantReserveRatio 53 | * @param {number|string|number} txData.maxSupply 54 | * @param {TxOptions} [options] 55 | * @return {CreateCoinTxData} 56 | */ 57 | CreateCoinTxData.fromBufferFields = function fromBufferFields({name, symbol, initialAmount, initialReserve, constantReserveRatio, maxSupply}, options = {}) { 58 | return new CreateCoinTxData({ 59 | name: toBuffer(name).toString('utf8'), 60 | symbol: bufferToCoin(toBuffer(symbol)), 61 | initialAmount: dataPipToAmount(initialAmount), 62 | initialReserve: dataPipToAmount(initialReserve), 63 | constantReserveRatio: dataToInteger(constantReserveRatio), 64 | maxSupply: dataPipToAmount(maxSupply), 65 | }, options); 66 | }; 67 | 68 | /** 69 | * @param {Buffer|string} data 70 | * @return {CreateCoinTxData} 71 | */ 72 | CreateCoinTxData.fromRlp = function fromRlp(data) { 73 | return CreateCoinTxData.fromBufferFields(new TxDataCreateCoin(data)); 74 | }; 75 | -------------------------------------------------------------------------------- /src/tx-data/create-multisig.js: -------------------------------------------------------------------------------- 1 | import {TxDataCreateMultisig} from 'minterjs-tx'; 2 | // import TxDataCreateMultisig from 'minterjs-tx/src/tx-data/create-multisig.js'; 3 | import {addressToString, toBuffer} from 'minterjs-util'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import {proxyNestedTxData, bufferToInteger, integerToHexString, validateAddress, validateUintArray, validateUint} from '../utils.js'; 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {Array} txData.addresses 10 | * @param {Array} txData.weights 11 | * @param {number|string} txData.threshold 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function CreateMultisigTxData({addresses, weights, threshold}, options = {}) { 16 | if (!options.disableValidation) { 17 | validateUintArray(weights, 'weights'); 18 | validateUint(threshold); 19 | } 20 | 21 | this.addresses = addresses; 22 | this.weights = weights; 23 | this.threshold = threshold; 24 | 25 | if (!Array.isArray(addresses)) { 26 | throw new TypeError('Field `addresses` is not an array'); 27 | } 28 | if (addresses.length > 32) { 29 | throw new Error('Invalid `addresses` count, it must not be greater than 32'); 30 | } 31 | if (weights.length !== addresses.length) { 32 | throw new Error('Invalid `weights` count, it must be equal to addresses count'); 33 | } 34 | addresses.forEach((address, index) => { 35 | try { 36 | validateAddress(address, `addresses[${index}]`); 37 | } catch (error) { 38 | throw new Error(`Field \`addresses\` contains invalid address at index: ${index}. ${error.message}`); 39 | } 40 | }); 41 | 42 | weights.forEach((weight, index) => { 43 | if (weight > 1023 || weight < 0) { 44 | throw new Error(`\`weights\` field contains invalid weight at index: ${index}, it should be between 0 and 1023`); 45 | } 46 | }); 47 | 48 | this.txData = new TxDataCreateMultisig({ 49 | addresses: addresses.map((address) => toBuffer(address)), 50 | weights: weights.map((weight) => integerToHexString(weight)), 51 | threshold: integerToHexString(threshold), 52 | }); 53 | 54 | proxyNestedTxData(this); 55 | } 56 | 57 | /** 58 | * @param {object} txData 59 | * @param {Array} txData.addresses 60 | * @param {Array} txData.weights 61 | * @param {Buffer|string} txData.threshold 62 | * @param {TxOptions} [options] 63 | * @return {CreateMultisigTxData} 64 | */ 65 | CreateMultisigTxData.fromBufferFields = function fromBufferFields({addresses, weights, threshold}, options = {}) { 66 | return new CreateMultisigTxData({ 67 | // @TODO replace with dataToXXX methods? 68 | addresses: addresses.map((item) => addressToString(item)), 69 | weights: weights.map((item) => bufferToInteger(item)), 70 | threshold: bufferToInteger(threshold), 71 | }, options); 72 | }; 73 | 74 | /** 75 | * @param {Buffer|string} data 76 | * @return {CreateMultisigTxData} 77 | */ 78 | CreateMultisigTxData.fromRlp = function fromRlp(data) { 79 | return CreateMultisigTxData.fromBufferFields(new TxDataCreateMultisig(data)); 80 | }; 81 | -------------------------------------------------------------------------------- /src/tx-data/edit-multisig.js: -------------------------------------------------------------------------------- 1 | import {TxDataEditMultisig} from 'minterjs-tx'; 2 | import {addressToString, toBuffer} from 'minterjs-util'; 3 | import {proxyNestedTxData, bufferToInteger, integerToHexString, validateAddress, validateUint, validateUintArray} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {Array} txData.addresses 8 | * @param {Array} txData.weights 9 | * @param {number|string} txData.threshold 10 | * @param {TxOptions} [options] 11 | * @constructor 12 | */ 13 | export default function EditMultisigTxData({addresses, weights, threshold}, options = {}) { 14 | if (!options.disableValidation) { 15 | validateUintArray(weights, 'weights'); 16 | validateUint(threshold); 17 | } 18 | 19 | this.addresses = addresses; 20 | this.weights = weights; 21 | this.threshold = threshold; 22 | 23 | if (!Array.isArray(addresses)) { 24 | throw new TypeError('Field `addresses` is not an array'); 25 | } 26 | if (addresses.length > 32) { 27 | throw new Error('Invalid `addresses` count, it must not be greater than 32'); 28 | } 29 | if (weights.length !== addresses.length) { 30 | throw new Error('Invalid `weights` count, it must be equal to addresses count'); 31 | } 32 | addresses.forEach((address, index) => { 33 | try { 34 | validateAddress(address, `addresses[${index}]`); 35 | } catch (error) { 36 | throw new Error(`Field \`addresses\` contains invalid address at index: ${index}. ${error.message}`); 37 | } 38 | }); 39 | 40 | weights.forEach((weight, index) => { 41 | if (weight > 1023 || weight < 0) { 42 | throw new Error(`\`weights\` field contains invalid weight at index: ${index}, it should be between 0 and 1023`); 43 | } 44 | }); 45 | 46 | // sort arrays so different ordered lists will produce same transaction hash 47 | const list = addresses.map((item, index) => { 48 | return { 49 | address: item, 50 | weight: weights[index], 51 | }; 52 | }); 53 | list.sort(function sortListItem(a, b) { 54 | if (a.address > b.address) { 55 | return 1; 56 | } 57 | if (a.address < b.address) { 58 | return -1; 59 | } 60 | return 0; 61 | }); 62 | addresses = list.map((item) => item.address); 63 | weights = list.map((item) => item.weight); 64 | 65 | this.txData = new TxDataEditMultisig({ 66 | addresses: addresses.map((address) => toBuffer(address)), 67 | weights: weights.map((weight) => integerToHexString(weight)), 68 | threshold: integerToHexString(threshold), 69 | }); 70 | 71 | proxyNestedTxData(this); 72 | } 73 | 74 | /** 75 | * @param {object} txData 76 | * @param {Array} txData.addresses 77 | * @param {Array} txData.weights 78 | * @param {Buffer|string} txData.threshold 79 | * @param {TxOptions} [options] 80 | * @return {EditMultisigTxData} 81 | */ 82 | EditMultisigTxData.fromBufferFields = function fromBufferFields({addresses, weights, threshold}, options = {}) { 83 | return new EditMultisigTxData({ 84 | // @TODO replace with dataToXXX methods? 85 | addresses: addresses.map((item) => addressToString(item)), 86 | weights: weights.map((item) => bufferToInteger(item)), 87 | threshold: bufferToInteger(threshold), 88 | }, options); 89 | }; 90 | 91 | /** 92 | * @param {Buffer|string} data 93 | * @return {EditMultisigTxData} 94 | */ 95 | EditMultisigTxData.fromRlp = function fromRlp(data) { 96 | return EditMultisigTxData.fromBufferFields(new TxDataEditMultisig(data)); 97 | }; 98 | -------------------------------------------------------------------------------- /src/tx-data/edit-ticker-owner.js: -------------------------------------------------------------------------------- 1 | import {TxDataEditTickerOwner} from 'minterjs-tx'; 2 | import {toBuffer, coinToBuffer, bufferToCoin} from 'minterjs-util'; 3 | import {dataToAddress, proxyNestedTxData, validateAddress, validateTicker} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {string} txData.symbol 8 | * @param {string} txData.newOwner 9 | * @param {TxOptions} [options] 10 | * @constructor 11 | */ 12 | export default function EditTickerOwnerTxData({symbol, newOwner}, options = {}) { 13 | if (!options.disableValidation) { 14 | validateTicker(symbol, 'symbol'); 15 | validateAddress(newOwner, 'newOwner'); 16 | } 17 | 18 | this.symbol = symbol; 19 | this.newOwner = newOwner; 20 | 21 | this.txData = new TxDataEditTickerOwner({ 22 | symbol: coinToBuffer(symbol), 23 | newOwner: toBuffer(newOwner), 24 | }); 25 | 26 | proxyNestedTxData(this); 27 | } 28 | 29 | /** 30 | * @param {object} txData 31 | * @param {Buffer|string} txData.symbol 32 | * @param {Buffer|string} txData.newOwner 33 | * @param {TxOptions} [options] 34 | * @return {EditTickerOwnerTxData} 35 | */ 36 | EditTickerOwnerTxData.fromBufferFields = function fromBufferFields({symbol, newOwner}, options = {}) { 37 | return new EditTickerOwnerTxData({ 38 | symbol: bufferToCoin(toBuffer(symbol)), 39 | newOwner: dataToAddress(newOwner), 40 | }, options); 41 | }; 42 | 43 | /** 44 | * @param {Buffer|string} data 45 | * @return {EditTickerOwnerTxData} 46 | */ 47 | EditTickerOwnerTxData.fromRlp = function fromRlp(data) { 48 | return EditTickerOwnerTxData.fromBufferFields(new TxDataEditTickerOwner(data)); 49 | }; 50 | -------------------------------------------------------------------------------- /src/tx-data/limit-order-add.js: -------------------------------------------------------------------------------- 1 | import {TxDataAddLimitOrder} from 'minterjs-tx'; 2 | // import TxDataSell from 'minterjs-tx/src/tx-data/sell.js'; 3 | // import {TX_TYPE} from 'minterjs-tx/src/tx-types.js'; 4 | import {convertToPip} from 'minterjs-util'; 5 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 6 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 7 | 8 | /** 9 | * @param {object} txData 10 | * @param {number|string} txData.coinToSell - coin id 11 | * @param {number|string} txData.coinToBuy - coin id 12 | * @param {number|string} txData.valueToSell 13 | * @param {number|string} txData.valueToBuy 14 | * @param {TxOptions} [options] 15 | * @constructor 16 | */ 17 | export default function AddLimitOrderTxData({coinToSell, coinToBuy, valueToSell, valueToBuy = 0}, options = {}) { 18 | if (!options.disableValidation) { 19 | validateUint(coinToSell, 'coinToSell'); 20 | validateUint(coinToBuy, 'coinToBuy'); 21 | validateAmount(valueToSell, 'valueToSell'); 22 | validateAmount(valueToBuy, 'valueToBuy'); 23 | } 24 | 25 | this.coinToSell = coinToSell; 26 | this.coinToBuy = coinToBuy; 27 | this.valueToSell = valueToSell; 28 | this.valueToBuy = valueToBuy; 29 | 30 | this.txData = new TxDataAddLimitOrder({ 31 | coinToSell: integerToHexString(coinToSell), 32 | coinToBuy: integerToHexString(coinToBuy), 33 | valueToSell: `0x${convertToPip(valueToSell, 'hex')}`, 34 | valueToBuy: `0x${convertToPip(valueToBuy, 'hex')}`, 35 | }); 36 | 37 | proxyNestedTxData(this); 38 | } 39 | 40 | /** 41 | * @param {object} txData 42 | * @param {Buffer|string} txData.coinToSell 43 | * @param {Buffer|string} txData.valueToSell 44 | * @param {Buffer|string} txData.coinToBuy 45 | * @param {Buffer|string} txData.valueToBuy 46 | * @param {TxOptions} [options] 47 | * @return {AddLimitOrderTxData} 48 | */ 49 | AddLimitOrderTxData.fromBufferFields = function fromBufferFields({coinToSell, valueToSell, coinToBuy, valueToBuy}, options = {}) { 50 | // @TODO should validation be done here? 51 | /* 52 | if (!valueToSell && valueToSell !== 0) { 53 | throw new Error('Invalid valueToSell'); 54 | } 55 | if (!valueToBuy && valueToBuy !== 0) { 56 | throw new Error('Invalid valueToBuy'); 57 | } 58 | */ 59 | 60 | return new AddLimitOrderTxData({ 61 | coinToSell: dataToInteger(coinToSell), 62 | coinToBuy: dataToInteger(coinToBuy), 63 | valueToSell: dataPipToAmount(valueToSell), 64 | valueToBuy: dataPipToAmount(valueToBuy), 65 | }, options); 66 | }; 67 | 68 | /** 69 | * @param {Buffer|string} data 70 | * @return {AddLimitOrderTxData} 71 | */ 72 | AddLimitOrderTxData.fromRlp = function fromRlp(data) { 73 | return AddLimitOrderTxData.fromBufferFields(new TxDataAddLimitOrder(data)); 74 | }; 75 | -------------------------------------------------------------------------------- /src/tx-data/limit-order-remove.js: -------------------------------------------------------------------------------- 1 | import {TxDataRemoveLimitOrder} from 'minterjs-tx'; 2 | import {dataToInteger, integerToHexString, proxyNestedTxData, validateUint} from '../utils.js'; 3 | 4 | 5 | /** 6 | * @param {number|string} id 7 | * @param {TxOptions} [options] 8 | * @constructor 9 | */ 10 | export default function RemoveLimitOrderTxData({id}, options = {}) { 11 | if (!options.disableValidation) { 12 | validateUint(id, 'height'); 13 | } 14 | 15 | this.id = id; 16 | 17 | this.txData = new TxDataRemoveLimitOrder({ 18 | id: integerToHexString(id), 19 | }); 20 | 21 | proxyNestedTxData(this); 22 | } 23 | 24 | /** 25 | * @param {Buffer|string|number} id 26 | * @param {TxOptions} [options] 27 | * @return {RemoveLimitOrderTxData} 28 | */ 29 | RemoveLimitOrderTxData.fromBufferFields = function fromBufferFields({id}, options = {}) { 30 | return new RemoveLimitOrderTxData({ 31 | id: dataToInteger(id), 32 | }, options); 33 | }; 34 | 35 | /** 36 | * @param {Buffer|string} data 37 | * @return {RemoveLimitOrderTxData} 38 | */ 39 | RemoveLimitOrderTxData.fromRlp = function fromRlp(data) { 40 | return RemoveLimitOrderTxData.fromBufferFields(new TxDataRemoveLimitOrder(data)); 41 | }; 42 | -------------------------------------------------------------------------------- /src/tx-data/lock.js: -------------------------------------------------------------------------------- 1 | import {TxDataLock} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 4 | import {dataToInteger, dataPipToAmount, integerToHexString, proxyNestedTxData, validateUint, validateAmount} from '../utils.js'; 5 | 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {number|string} txData.dueBlock 10 | * @param {number|string} txData.value 11 | * @param {number|string} txData.coin - coin id 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function LockTxData({dueBlock = 0, value = 0, coin}, options = {}) { 16 | if (!options.disableValidation) { 17 | validateUint(dueBlock, 'dueBlock'); 18 | validateUint(coin, 'coin'); 19 | validateAmount(value, 'value'); 20 | } 21 | 22 | this.dueBlock = dueBlock; 23 | this.value = value; 24 | this.coin = coin; 25 | 26 | this.txData = new TxDataLock({ 27 | dueBlock: integerToHexString(dueBlock), 28 | coin: integerToHexString(coin), 29 | value: `0x${convertToPip(value, 'hex')}`, 30 | }); 31 | 32 | proxyNestedTxData(this); 33 | } 34 | 35 | /** 36 | * @param {object} txData 37 | * @param {Buffer|string|number} txData.dueBlock 38 | * @param {Buffer|string|number} txData.value 39 | * @param {Buffer|string|number} txData.coin 40 | * @param {TxOptions} [options] 41 | * @return {LockTxData} 42 | */ 43 | LockTxData.fromBufferFields = function fromBufferFields({dueBlock, value, coin}, options = {}) { 44 | return new LockTxData({ 45 | dueBlock: dataToInteger(dueBlock), 46 | coin: dataToInteger(coin), 47 | value: dataPipToAmount(value), 48 | }, options); 49 | }; 50 | 51 | /** 52 | * @param {Buffer|string} data 53 | * @return {LockTxData} 54 | */ 55 | LockTxData.fromRlp = function fromRlp(data) { 56 | return LockTxData.fromBufferFields(new TxDataLock(data)); 57 | }; 58 | -------------------------------------------------------------------------------- /src/tx-data/multisend.js: -------------------------------------------------------------------------------- 1 | import {TxDataMultisend} from 'minterjs-tx'; 2 | // import TxDataMultisend from 'minterjs-tx/src/tx-data/create-coin.js'; 3 | import {convertToPip, toBuffer} from 'minterjs-util'; 4 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 5 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 6 | import SendTxData from './send.js'; 7 | import {proxyNestedTxData, integerToHexString, validateAddress, validateAmount, validateUint} from '../utils.js'; 8 | 9 | /** 10 | * @param {object} txData 11 | * @param {Array} txData.list 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function MultisendTxData({list}, options = {}) { 16 | if (!options.disableValidation) { 17 | if (!Array.isArray(list)) { 18 | throw new TypeError('Field `list` is not an array'); 19 | } 20 | list.forEach((item, index) => { 21 | try { 22 | validateAddress(item.to, `list[${index}].to`); 23 | validateUint(item.coin, `list[${index}].coin`); 24 | validateAmount(item.value, `list[${index}].value`); 25 | } catch (error) { 26 | throw new Error(`Field \`list\` contains invalid item at index ${index}. ${error.message}`); 27 | } 28 | }); 29 | } 30 | 31 | this.list = list; 32 | 33 | this.txData = new TxDataMultisend({ 34 | list: list.map((item) => { 35 | return { 36 | to: toBuffer(item.to), 37 | coin: integerToHexString(item.coin), 38 | value: `0x${convertToPip(item.value, 'hex')}`, 39 | }; 40 | }), 41 | }); 42 | 43 | proxyNestedTxData(this); 44 | } 45 | 46 | 47 | /** 48 | * @param {Array} list 49 | * @param {TxOptions} [options] 50 | * @return {MultisendTxData} 51 | */ 52 | MultisendTxData.fromBufferFields = function fromBufferFields({list}, options = {}) { 53 | return new MultisendTxData({ 54 | list: list.map((item) => SendTxData.fromRlp(item)), 55 | }, options); 56 | }; 57 | 58 | /** 59 | * @param {Buffer|string} data 60 | * @return {MultisendTxData} 61 | */ 62 | MultisendTxData.fromRlp = function fromRlp(data) { 63 | return MultisendTxData.fromBufferFields(new TxDataMultisend(data)); 64 | }; 65 | -------------------------------------------------------------------------------- /src/tx-data/pool-add-liquidity.js: -------------------------------------------------------------------------------- 1 | import {TxDataAddLiquidity} from 'minterjs-tx'; 2 | import {convertToPip, COIN_MAX_AMOUNT} from 'minterjs-util'; 3 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {number|string} txData.coin0 - coin id 8 | * @param {number|string} txData.coin1 - coin id 9 | * @param {number|string} txData.volume0 10 | * @param {number|string} [txData.maximumVolume1] 11 | * @param {TxOptions} [options] 12 | * @constructor 13 | */ 14 | export default function AddLiquidityTxData({coin0, coin1, volume0, maximumVolume1 = COIN_MAX_AMOUNT}, options = {}) { 15 | if (!options.disableValidation) { 16 | validateUint(coin0, 'coin0'); 17 | validateUint(coin1, 'coin1'); 18 | validateAmount(volume0, 'volume0'); 19 | validateAmount(maximumVolume1, 'maximumVolume1'); 20 | } 21 | 22 | this.coin0 = coin0; 23 | this.coin1 = coin1; 24 | this.volume0 = volume0; 25 | this.maximumVolume1 = maximumVolume1; 26 | 27 | this.txData = new TxDataAddLiquidity({ 28 | coin0: integerToHexString(coin0), 29 | coin1: integerToHexString(coin1), 30 | volume0: `0x${convertToPip(volume0, 'hex')}`, 31 | maximumVolume1: `0x${convertToPip(maximumVolume1, 'hex')}`, 32 | }); 33 | 34 | proxyNestedTxData(this); 35 | } 36 | 37 | /** 38 | * @param {object} txData 39 | * @param {Buffer|string} txData.coin0 40 | * @param {Buffer|string} txData.volume0 41 | * @param {Buffer|string} txData.coin1 42 | * @param {Buffer|string} txData.maximumVolume1 43 | * @param {TxOptions} [options] 44 | * @return {AddLiquidityTxData} 45 | */ 46 | AddLiquidityTxData.fromBufferFields = function fromBufferFields({coin0, volume0, coin1, maximumVolume1}, options = {}) { 47 | return new AddLiquidityTxData({ 48 | coin0: dataToInteger(coin0), 49 | coin1: dataToInteger(coin1), 50 | volume0: dataPipToAmount(volume0), 51 | maximumVolume1: dataPipToAmount(maximumVolume1), 52 | }, options); 53 | }; 54 | 55 | /** 56 | * @param {Buffer|string} data 57 | * @return {AddLiquidityTxData} 58 | */ 59 | AddLiquidityTxData.fromRlp = function fromRlp(data) { 60 | return AddLiquidityTxData.fromBufferFields(new TxDataAddLiquidity(data)); 61 | }; 62 | -------------------------------------------------------------------------------- /src/tx-data/pool-buy.js: -------------------------------------------------------------------------------- 1 | import {TxDataBuySwapPool} from 'minterjs-tx'; 2 | import {convertToPip, COIN_MAX_AMOUNT} from 'minterjs-util'; 3 | import {proxyNestedTxData, bufferToInteger, integerToHexString, dataPipToAmount, validateAmount, validateUintArray} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {Array} txData.coins - list of coin id 8 | * @param {number|string} txData.valueToBuy 9 | * @param {number|string} [txData.maximumValueToSell] 10 | * @param {TxOptions} [options] 11 | * @constructor 12 | */ 13 | export default function BuyPoolTxData({coins, valueToBuy, maximumValueToSell = COIN_MAX_AMOUNT}, options = {}) { 14 | if (!options.disableValidation) { 15 | validateUintArray(coins, 'coins'); 16 | validateAmount(valueToBuy, 'valueToBuy'); 17 | validateAmount(maximumValueToSell, 'maximumValueToSell'); 18 | } 19 | 20 | this.coins = coins; 21 | this.valueToBuy = valueToBuy; 22 | this.maximumValueToSell = maximumValueToSell; 23 | 24 | this.txData = new TxDataBuySwapPool({ 25 | coins: coins.map((coin) => integerToHexString(coin)), 26 | valueToBuy: `0x${convertToPip(valueToBuy, 'hex')}`, 27 | maximumValueToSell: `0x${convertToPip(maximumValueToSell, 'hex')}`, 28 | }); 29 | 30 | proxyNestedTxData(this); 31 | } 32 | 33 | /** 34 | * @param {object} txData 35 | * @param {Array} txData.coins 36 | * @param {Buffer|string} txData.valueToBuy 37 | * @param {Buffer|string} txData.maximumValueToSell 38 | * @param {TxOptions} [options] 39 | * @return {BuyPoolTxData} 40 | */ 41 | BuyPoolTxData.fromBufferFields = function fromBufferFields({coins, valueToBuy, maximumValueToSell}, options = {}) { 42 | return new BuyPoolTxData({ 43 | coins: coins.map((item) => bufferToInteger(item)), 44 | valueToBuy: dataPipToAmount(valueToBuy), 45 | maximumValueToSell: dataPipToAmount(maximumValueToSell), 46 | }, options); 47 | }; 48 | 49 | /** 50 | * @param {Buffer|string} data 51 | * @return {BuyPoolTxData} 52 | */ 53 | BuyPoolTxData.fromRlp = function fromRlp(data) { 54 | return BuyPoolTxData.fromBufferFields(new TxDataBuySwapPool(data)); 55 | }; 56 | -------------------------------------------------------------------------------- /src/tx-data/pool-create.js: -------------------------------------------------------------------------------- 1 | import {TxDataCreateSwapPool} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {number|string} txData.coin0 - coin id 8 | * @param {number|string} txData.coin1 - coin id 9 | * @param {number|string} txData.volume0 10 | * @param {number|string} txData.volume1 11 | * @param {TxOptions} [options] 12 | * @constructor 13 | */ 14 | export default function CreatePoolTxData({coin0, coin1, volume0, volume1}, options = {}) { 15 | if (!options.disableValidation) { 16 | validateUint(coin0, 'coin0'); 17 | validateUint(coin1, 'coin1'); 18 | validateAmount(volume0, 'volume0'); 19 | validateAmount(volume1, 'volume1'); 20 | } 21 | 22 | // swap values to sort by id ascending (make tx hash independent of coin order) 23 | if (Number(coin0) > Number(coin1)) { 24 | [coin0, coin1] = [coin1, coin0]; 25 | [volume0, volume1] = [volume1, volume0]; 26 | } 27 | 28 | this.coin0 = coin0; 29 | this.coin1 = coin1; 30 | this.volume0 = volume0; 31 | this.volume1 = volume1; 32 | 33 | this.txData = new TxDataCreateSwapPool({ 34 | coin0: integerToHexString(coin0), 35 | coin1: integerToHexString(coin1), 36 | volume0: `0x${convertToPip(volume0, 'hex')}`, 37 | volume1: `0x${convertToPip(volume1, 'hex')}`, 38 | }); 39 | 40 | proxyNestedTxData(this); 41 | } 42 | 43 | /** 44 | * @param {object} txData 45 | * @param {Buffer|string} txData.coin0 46 | * @param {Buffer|string} txData.volume0 47 | * @param {Buffer|string} txData.coin1 48 | * @param {Buffer|string} txData.volume1 49 | * @param {TxOptions} [options] 50 | * @return {CreatePoolTxData} 51 | */ 52 | CreatePoolTxData.fromBufferFields = function fromBufferFields({coin0, volume0, coin1, volume1}, options = {}) { 53 | return new CreatePoolTxData({ 54 | coin0: dataToInteger(coin0), 55 | coin1: dataToInteger(coin1), 56 | volume0: dataPipToAmount(volume0), 57 | volume1: dataPipToAmount(volume1), 58 | }, options); 59 | }; 60 | 61 | /** 62 | * @param {Buffer|string} data 63 | * @return {CreatePoolTxData} 64 | */ 65 | CreatePoolTxData.fromRlp = function fromRlp(data) { 66 | return CreatePoolTxData.fromBufferFields(new TxDataCreateSwapPool(data)); 67 | }; 68 | -------------------------------------------------------------------------------- /src/tx-data/pool-remove-liquidity.js: -------------------------------------------------------------------------------- 1 | import {TxDataRemoveLiquidity} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateUint} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {number|string} txData.coin0 - coin id 8 | * @param {number|string} txData.coin1 - coin id 9 | * @param {number|string} txData.liquidity - volume of shares to be withdrawn from the pool 10 | * @param {number|string} [txData.minimumVolume0] 11 | * @param {number|string} [txData.minimumVolume1] 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function RemoveLiquidityTxData({coin0, coin1, liquidity, minimumVolume0 = 0, minimumVolume1 = 0}, options = {}) { 16 | if (!options.disableValidation) { 17 | validateUint(coin0, 'coin0'); 18 | validateUint(coin1, 'coin1'); 19 | validateAmount(liquidity, 'liquidity'); 20 | validateAmount(minimumVolume0, 'minimumVolume0'); 21 | validateAmount(minimumVolume1, 'minimumVolume1'); 22 | } 23 | 24 | this.coin0 = coin0; 25 | this.coin1 = coin1; 26 | this.liquidity = liquidity; 27 | this.minimumVolume0 = minimumVolume0; 28 | this.minimumVolume1 = minimumVolume1; 29 | 30 | this.txData = new TxDataRemoveLiquidity({ 31 | coin0: integerToHexString(coin0), 32 | coin1: integerToHexString(coin1), 33 | liquidity: `0x${convertToPip(liquidity, 'hex')}`, 34 | minimumVolume0: `0x${convertToPip(minimumVolume0, 'hex')}`, 35 | minimumVolume1: `0x${convertToPip(minimumVolume1, 'hex')}`, 36 | }); 37 | 38 | proxyNestedTxData(this); 39 | } 40 | 41 | /** 42 | * @param {object} txData 43 | * @param {Buffer|string} txData.coin0 44 | * @param {Buffer|string} txData.coin1 45 | * @param {Buffer|string} txData.liquidity 46 | * @param {Buffer|string} txData.minimumVolume0 47 | * @param {Buffer|string} txData.minimumVolume1 48 | * @param {TxOptions} [options] 49 | * @return {RemoveLiquidityTxData} 50 | */ 51 | RemoveLiquidityTxData.fromBufferFields = function fromBufferFields({coin0, minimumVolume0, coin1, liquidity, minimumVolume1}, options = {}) { 52 | return new RemoveLiquidityTxData({ 53 | coin0: dataToInteger(coin0), 54 | coin1: dataToInteger(coin1), 55 | liquidity: dataPipToAmount(liquidity), 56 | minimumVolume0: dataPipToAmount(minimumVolume0), 57 | minimumVolume1: dataPipToAmount(minimumVolume1), 58 | }, options); 59 | }; 60 | 61 | /** 62 | * @param {Buffer|string} data 63 | * @return {RemoveLiquidityTxData} 64 | */ 65 | RemoveLiquidityTxData.fromRlp = function fromRlp(data) { 66 | return RemoveLiquidityTxData.fromBufferFields(new TxDataRemoveLiquidity(data)); 67 | }; 68 | -------------------------------------------------------------------------------- /src/tx-data/pool-sell-all.js: -------------------------------------------------------------------------------- 1 | import {TxDataSellAllSwapPool} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | import {proxyNestedTxData, bufferToInteger, integerToHexString, dataPipToAmount, validateAmount, validateUintArray} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {Array} txData.coins - list of coin id 8 | * @param {number|string} [txData.minimumValueToBuy=0] 9 | * @param {TxOptions} [options] 10 | * @constructor 11 | */ 12 | export default function SellAllPoolTxData({coins, minimumValueToBuy = 0}, options = {}) { 13 | if (!options.disableValidation) { 14 | validateUintArray(coins, 'coins'); 15 | validateAmount(minimumValueToBuy, 'minimumValueToBuy'); 16 | } 17 | 18 | this.coins = coins; 19 | this.minimumValueToBuy = minimumValueToBuy; 20 | 21 | this.txData = new TxDataSellAllSwapPool({ 22 | coins: coins.map((coin) => integerToHexString(coin)), 23 | minimumValueToBuy: `0x${convertToPip(minimumValueToBuy, 'hex')}`, 24 | }); 25 | 26 | proxyNestedTxData(this); 27 | } 28 | 29 | /** 30 | * @param {object} txData 31 | * @param {Array} txData.coins 32 | * @param {Buffer|string} txData.minimumValueToBuy 33 | * @param {TxOptions} [options] 34 | * @return {SellAllPoolTxData} 35 | */ 36 | SellAllPoolTxData.fromBufferFields = function fromBufferFields({coins, minimumValueToBuy}, options = {}) { 37 | return new SellAllPoolTxData({ 38 | coins: coins.map((item) => bufferToInteger(item)), 39 | minimumValueToBuy: dataPipToAmount(minimumValueToBuy), 40 | }, options); 41 | }; 42 | 43 | /** 44 | * @param {Buffer|string} data 45 | * @return {SellAllPoolTxData} 46 | */ 47 | SellAllPoolTxData.fromRlp = function fromRlp(data) { 48 | return SellAllPoolTxData.fromBufferFields(new TxDataSellAllSwapPool(data)); 49 | }; 50 | -------------------------------------------------------------------------------- /src/tx-data/pool-sell.js: -------------------------------------------------------------------------------- 1 | import {TxDataSellSwapPool} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | import {proxyNestedTxData, bufferToInteger, integerToHexString, dataPipToAmount, validateAmount, validateUintArray} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {Array} txData.coins - list of coin id 8 | * @param {number|string} txData.valueToSell 9 | * @param {number|string} [txData.minimumValueToBuy=0] 10 | * @param {TxOptions} [options] 11 | * @constructor 12 | */ 13 | export default function SellPoolTxData({coins, valueToSell, minimumValueToBuy = 0}, options = {}) { 14 | if (!options.disableValidation) { 15 | validateUintArray(coins, 'coins'); 16 | validateAmount(valueToSell, 'valueToSell'); 17 | validateAmount(minimumValueToBuy, 'minimumValueToBuy'); 18 | } 19 | 20 | this.coins = coins; 21 | this.valueToSell = valueToSell; 22 | this.minimumValueToBuy = minimumValueToBuy; 23 | 24 | this.txData = new TxDataSellSwapPool({ 25 | coins: coins.map((coin) => integerToHexString(coin)), 26 | valueToSell: `0x${convertToPip(valueToSell, 'hex')}`, 27 | minimumValueToBuy: `0x${convertToPip(minimumValueToBuy, 'hex')}`, 28 | }); 29 | 30 | proxyNestedTxData(this); 31 | } 32 | 33 | /** 34 | * @param {object} txData 35 | * @param {Array} txData.coins 36 | * @param {Buffer|string} txData.valueToSell 37 | * @param {Buffer|string} txData.minimumValueToBuy 38 | * @param {TxOptions} [options] 39 | * @return {SellPoolTxData} 40 | */ 41 | SellPoolTxData.fromBufferFields = function fromBufferFields({coins, valueToSell, minimumValueToBuy}, options = {}) { 42 | // @TODO should validation be done here? 43 | /* 44 | if (!valueToSell && valueToSell !== 0) { 45 | throw new Error('Invalid valueToSell'); 46 | } 47 | */ 48 | 49 | return new SellPoolTxData({ 50 | coins: coins.map((item) => bufferToInteger(item)), 51 | valueToSell: dataPipToAmount(valueToSell), 52 | minimumValueToBuy: dataPipToAmount(minimumValueToBuy), 53 | }, options); 54 | }; 55 | 56 | /** 57 | * @param {Buffer|string} data 58 | * @return {SellPoolTxData} 59 | */ 60 | SellPoolTxData.fromRlp = function fromRlp(data) { 61 | return SellPoolTxData.fromBufferFields(new TxDataSellSwapPool(data)); 62 | }; 63 | -------------------------------------------------------------------------------- /src/tx-data/recreate-coin.js: -------------------------------------------------------------------------------- 1 | import {TxDataRecreateCoin} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer, coinToBuffer, bufferToCoin, COIN_MAX_MAX_SUPPLY} from 'minterjs-util'; 3 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, integerToHexString, validateAmount, validateTicker, validateMaxSupply} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {string} [txData.name] 8 | * @param {string} txData.symbol 9 | * @param {number|string} txData.initialAmount 10 | * @param {number|string} txData.initialReserve 11 | * @param {number|string} txData.constantReserveRatio 12 | * @param {number|string} [txData.maxSupply] 13 | * @param {TxOptions} [options] 14 | * @constructor 15 | */ 16 | export default function RecreateCoinTxData({name = '', symbol, initialAmount, initialReserve, constantReserveRatio, maxSupply = COIN_MAX_MAX_SUPPLY}, options = {}) { 17 | if (!options.disableValidation) { 18 | validateTicker(symbol, 'symbol'); 19 | validateAmount(initialAmount, 'initialAmount'); 20 | validateAmount(initialReserve, 'initialReserve'); 21 | validateMaxSupply(maxSupply, initialAmount); 22 | } 23 | 24 | this.name = name; 25 | this.symbol = symbol; 26 | this.initialAmount = initialAmount; 27 | this.initialReserve = initialReserve; 28 | this.constantReserveRatio = constantReserveRatio; 29 | this.maxSupply = maxSupply; 30 | 31 | this.txData = new TxDataRecreateCoin({ 32 | name: Buffer.from(name.toString(), 'utf8'), 33 | symbol: coinToBuffer(symbol), 34 | initialAmount: `0x${convertToPip(initialAmount, 'hex')}`, 35 | initialReserve: `0x${convertToPip(initialReserve, 'hex')}`, 36 | constantReserveRatio: integerToHexString(constantReserveRatio), 37 | maxSupply: `0x${convertToPip(maxSupply, 'hex')}`, 38 | }); 39 | 40 | proxyNestedTxData(this); 41 | } 42 | 43 | /** 44 | * @param {object} txData 45 | * @param {Buffer|string} txData.name 46 | * @param {Buffer|string} txData.symbol 47 | * @param {Buffer|string|number} txData.initialAmount 48 | * @param {Buffer|string|number} txData.initialReserve 49 | * @param {Buffer|string|number} txData.constantReserveRatio 50 | * @param {number|string|number} txData.maxSupply 51 | * @param {TxOptions} [options] 52 | * @return {RecreateCoinTxData} 53 | */ 54 | RecreateCoinTxData.fromBufferFields = function fromBufferFields({name, symbol, initialAmount, initialReserve, constantReserveRatio, maxSupply}, options = {}) { 55 | return new RecreateCoinTxData({ 56 | name: toBuffer(name).toString('utf8'), 57 | symbol: bufferToCoin(toBuffer(symbol)), 58 | initialAmount: dataPipToAmount(initialAmount), 59 | initialReserve: dataPipToAmount(initialReserve), 60 | constantReserveRatio: dataToInteger(constantReserveRatio), 61 | maxSupply: dataPipToAmount(maxSupply), 62 | }, options); 63 | }; 64 | 65 | /** 66 | * @param {Buffer|string} data 67 | * @return {RecreateCoinTxData} 68 | */ 69 | RecreateCoinTxData.fromRlp = function fromRlp(data) { 70 | return RecreateCoinTxData.fromBufferFields(new TxDataRecreateCoin(data)); 71 | }; 72 | -------------------------------------------------------------------------------- /src/tx-data/redeem-check.js: -------------------------------------------------------------------------------- 1 | import secp256k1 from 'secp256k1'; 2 | import {sha256, rlphash} from 'ethereumjs-util/dist/hash.js'; 3 | import {walletFromMnemonic, walletFromPrivateKey} from 'minterjs-wallet'; 4 | import {TxDataRedeemCheck} from 'minterjs-tx'; 5 | // import TxDataRedeemCheck from 'minterjs-tx/src/tx-data/redeem-check.js'; 6 | import {toBuffer, checkToString} from 'minterjs-util'; 7 | import {proxyNestedTxData, validateCheck} from '../utils.js'; 8 | 9 | 10 | /** 11 | * @param {object} txData 12 | * @param {ByteArray} txData.check 13 | * @param {ByteArray} [txData.proof] 14 | * @param {TxOptions} [options] 15 | * @constructor 16 | */ 17 | export default function RedeemCheckTxData({check, proof}, options = {}) { 18 | if (!options.disableValidation) { 19 | validateCheck(check, 'check'); 20 | } 21 | 22 | // eslint-disable-next-line prefer-rest-params 23 | if (!options.password && arguments[0].password) { 24 | // eslint-disable-next-line prefer-rest-params 25 | options.password = arguments[0].password; 26 | // eslint-disable-next-line no-console 27 | console.warn('Check password in tx data is deprecated. Pass it as field in the second argument.'); 28 | } 29 | // eslint-disable-next-line prefer-rest-params 30 | if (!options.privateKey && arguments[0].privateKey) { 31 | // eslint-disable-next-line prefer-rest-params 32 | options.privateKey = arguments[0].privateKey; 33 | // eslint-disable-next-line no-console 34 | console.warn('Private key in tx data is deprecated. Pass it as field in the second argument.'); 35 | } 36 | this.check = checkToString(check); 37 | 38 | if (proof) { 39 | proof = toBuffer(proof); 40 | } else if (options.address || options.privateKey || options.seedPhrase) { 41 | proof = getProofWithRecovery(options); 42 | } 43 | 44 | this.txData = new TxDataRedeemCheck({ 45 | check: toBuffer(check), 46 | proof, 47 | }); 48 | this.proof = proof ? `0x${proof.toString('hex')}` : undefined; 49 | 50 | proxyNestedTxData(this); 51 | } 52 | 53 | /** 54 | * @param {object} txData 55 | * @param {Buffer|string} txData.check 56 | * @param {Buffer|string} txData.proof 57 | * @param {TxOptions} [options] 58 | * @return {RedeemCheckTxData} 59 | */ 60 | RedeemCheckTxData.fromBufferFields = function fromBufferFields({check, proof}, options = {}) { 61 | return new RedeemCheckTxData({ 62 | check, 63 | proof, 64 | }, options); 65 | }; 66 | 67 | /** 68 | * @param {Buffer|string} data 69 | * @return {RedeemCheckTxData} 70 | */ 71 | RedeemCheckTxData.fromRlp = function fromRlp(data) { 72 | return RedeemCheckTxData.fromBufferFields(new TxDataRedeemCheck(data)); 73 | }; 74 | 75 | /** 76 | * @param {TxOptions} options 77 | * @param {ByteArray} options.password 78 | * @param {ByteArray} [options.address] 79 | * @param {ByteArray} [options.privateKey] 80 | * @param {string} [options.seedPhrase] 81 | * @return {ArrayBuffer|Buffer} 82 | */ 83 | function getProofWithRecovery({password, address, privateKey, seedPhrase}) { 84 | let addressBuffer; 85 | if (address) { 86 | addressBuffer = toBuffer(address); 87 | } else if (privateKey) { 88 | privateKey = toBuffer(privateKey); 89 | addressBuffer = walletFromPrivateKey(privateKey).getAddress(); 90 | } else if (seedPhrase) { 91 | addressBuffer = walletFromMnemonic(seedPhrase).getAddress(); 92 | } else { 93 | throw new Error('No address nor seed phrase nor private key given to generate proof'); 94 | } 95 | const addressHash = rlphash([ 96 | addressBuffer, 97 | ]); 98 | 99 | // ensure Buffer 100 | password = typeof password === 'string' ? Buffer.from(password, 'utf8') : toBuffer(password); 101 | 102 | const passwordBuffer = sha256(password); 103 | const proof = secp256k1.ecdsaSign(addressHash, passwordBuffer); 104 | const proofWithRecovery = Buffer.alloc(65); 105 | proofWithRecovery.set(proof.signature, 0); 106 | proofWithRecovery[64] = proof.recid; 107 | 108 | return proofWithRecovery; 109 | } 110 | -------------------------------------------------------------------------------- /src/tx-data/send.js: -------------------------------------------------------------------------------- 1 | import {TxDataSend} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer} from 'minterjs-util'; 3 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import {dataToInteger, dataPipToAmount, dataToAddress, integerToHexString, proxyNestedTxData, validateAddress, validateUint, validateAmount} from '../utils.js'; 6 | 7 | 8 | /** 9 | * @param {object} txData 10 | * @param {string} txData.to 11 | * @param {number|string} txData.value 12 | * @param {number|string} txData.coin - coin id 13 | * @param {TxOptions} [options] 14 | * @constructor 15 | */ 16 | export default function SendTxData({to, value = 0, coin}, options = {}) { 17 | if (!options.disableValidation) { 18 | validateAddress(to, 'to'); 19 | validateUint(coin, 'coin'); 20 | validateAmount(value, 'value'); 21 | } 22 | 23 | this.to = to; 24 | this.value = value; 25 | this.coin = coin; 26 | 27 | this.txData = new TxDataSend({ 28 | to: toBuffer(to), 29 | coin: integerToHexString(coin), 30 | value: `0x${convertToPip(value, 'hex')}`, 31 | }); 32 | 33 | proxyNestedTxData(this); 34 | } 35 | 36 | /** 37 | * @param {object} txData 38 | * @param {Buffer|string} txData.to 39 | * @param {Buffer|string|number} txData.value 40 | * @param {Buffer|string|number} txData.coin 41 | * @param {TxOptions} [options] 42 | * @return {SendTxData} 43 | */ 44 | SendTxData.fromBufferFields = function fromBufferFields({to, value, coin}, options = {}) { 45 | return new SendTxData({ 46 | to: dataToAddress(to), 47 | coin: dataToInteger(coin), 48 | value: dataPipToAmount(value), 49 | }, options); 50 | }; 51 | 52 | /** 53 | * @param {Buffer|string} data 54 | * @return {SendTxData} 55 | */ 56 | SendTxData.fromRlp = function fromRlp(data) { 57 | return SendTxData.fromBufferFields(new TxDataSend(data)); 58 | }; 59 | -------------------------------------------------------------------------------- /src/tx-data/stake-delegate.js: -------------------------------------------------------------------------------- 1 | import {TxDataDelegate} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer} from 'minterjs-util'; 3 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, dataToPublicKey, validateAmount, validateUint, validatePublicKey, integerToHexString} from '../utils.js'; 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {string} txData.publicKey 10 | * @param {number|string} txData.coin - coin id 11 | * @param {number|string} txData.stake 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function DelegateTxData({publicKey, coin, stake}, options = {}) { 16 | if (!options.disableValidation) { 17 | validatePublicKey(publicKey, 'publicKey'); 18 | validateUint(coin, 'coin'); 19 | validateAmount(stake, 'stake'); 20 | } 21 | 22 | this.publicKey = publicKey; 23 | this.coin = coin; 24 | this.stake = stake; 25 | 26 | this.txData = new TxDataDelegate({ 27 | publicKey: toBuffer(publicKey), 28 | coin: integerToHexString(coin), 29 | stake: `0x${convertToPip(stake, 'hex')}`, 30 | }); 31 | 32 | proxyNestedTxData(this); 33 | } 34 | 35 | 36 | /** 37 | * @param {object} txData 38 | * @param {Buffer|string} txData.publicKey 39 | * @param {Buffer|string} txData.stake 40 | * @param {Buffer|string} txData.coin 41 | * @param {TxOptions} [options] 42 | * @return {DelegateTxData} 43 | */ 44 | DelegateTxData.fromBufferFields = function fromBufferFields({publicKey, coin, stake}, options = {}) { 45 | return new DelegateTxData({ 46 | publicKey: dataToPublicKey(publicKey), 47 | coin: dataToInteger(coin), 48 | stake: dataPipToAmount(stake), 49 | }, options); 50 | }; 51 | 52 | /** 53 | * @param {Buffer|string} data 54 | * @return {DelegateTxData} 55 | */ 56 | DelegateTxData.fromRlp = function fromRlp(data) { 57 | return DelegateTxData.fromBufferFields(new TxDataDelegate(data)); 58 | }; 59 | -------------------------------------------------------------------------------- /src/tx-data/stake-lock.js: -------------------------------------------------------------------------------- 1 | import {TxDataLockStake} from 'minterjs-tx'; 2 | import {proxyNestedTxData} from '../utils.js'; 3 | 4 | /** 5 | * @constructor 6 | */ 7 | export default function LockStakeTxData(/* {}, options */) { 8 | this.txData = new TxDataLockStake({}); 9 | 10 | proxyNestedTxData(this); 11 | } 12 | 13 | 14 | /** 15 | * @return {LockStakeTxData} 16 | */ 17 | LockStakeTxData.fromBufferFields = function fromBufferFields() { 18 | return new LockStakeTxData({}); 19 | }; 20 | 21 | /** 22 | * @param {Buffer|string} [data] 23 | * @return {LockStakeTxData} 24 | */ 25 | LockStakeTxData.fromRlp = function fromRlp(data) { 26 | return LockStakeTxData.fromBufferFields(new TxDataLockStake(data)); 27 | }; 28 | -------------------------------------------------------------------------------- /src/tx-data/stake-move.js: -------------------------------------------------------------------------------- 1 | import {TxDataMoveStake} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer} from 'minterjs-util'; 3 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import { proxyNestedTxData, dataToInteger, dataPipToAmount, dataToPublicKey, validateAmount, validateUint, validatePublicKey, integerToHexString} from '../utils.js'; 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {string} txData.from 10 | * @param {string} txData.to 11 | * @param {number|string} txData.coin - coin id 12 | * @param {number|string} txData.stake 13 | * @param {TxOptions} [options] 14 | * @constructor 15 | */ 16 | export default function MoveStakeTxData({from, to, coin, stake}, options = {}) { 17 | if (!options.disableValidation) { 18 | validatePublicKey(from, 'from'); 19 | validatePublicKey(to, 'to'); 20 | validateUint(coin, 'coin'); 21 | validateAmount(stake, 'stake'); 22 | } 23 | 24 | this.from = from; 25 | this.to = to; 26 | this.coin = coin; 27 | this.stake = stake; 28 | 29 | this.txData = new TxDataMoveStake({ 30 | from: toBuffer(from), 31 | to: toBuffer(to), 32 | coin: integerToHexString(coin), 33 | stake: `0x${convertToPip(stake, 'hex')}`, 34 | }); 35 | 36 | proxyNestedTxData(this); 37 | } 38 | 39 | 40 | /** 41 | * @param {object} txData 42 | * @param {Buffer|string} txData.from 43 | * @param {Buffer|string} txData.to 44 | * @param {Buffer|string} txData.stake 45 | * @param {Buffer|string} txData.coin 46 | * @param {TxOptions} [options] 47 | * @return {MoveStakeTxData} 48 | */ 49 | MoveStakeTxData.fromBufferFields = function fromBufferFields({from, to, coin, stake}, options = {}) { 50 | return new MoveStakeTxData({ 51 | from: dataToPublicKey(from), 52 | to: dataToPublicKey(to), 53 | coin: dataToInteger(coin), 54 | stake: dataPipToAmount(stake), 55 | }, options); 56 | }; 57 | 58 | /** 59 | * @param {Buffer|string} data 60 | * @return {MoveStakeTxData} 61 | */ 62 | MoveStakeTxData.fromRlp = function fromRlp(data) { 63 | return MoveStakeTxData.fromBufferFields(new TxDataMoveStake(data)); 64 | }; 65 | -------------------------------------------------------------------------------- /src/tx-data/stake-unbond.js: -------------------------------------------------------------------------------- 1 | import {TxDataUnbond} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer} from 'minterjs-util'; 3 | // import {convertToPip} from 'minterjs-util/src/converter.js'; 4 | // import {toBuffer} from 'minterjs-util/src/prefix.js'; 5 | import {proxyNestedTxData, dataToInteger, dataPipToAmount, dataToPublicKey, validateAmount, validateUint, validatePublicKey, integerToHexString} from '../utils.js'; 6 | 7 | /** 8 | * @param {object} txData 9 | * @param {string} txData.publicKey 10 | * @param {number|string} txData.coin - coin id 11 | * @param {number|string} txData.stake 12 | * @param {TxOptions} [options] 13 | * @constructor 14 | */ 15 | export default function UnbondTxData({publicKey, coin, stake}, options = {}) { 16 | if (!options.disableValidation) { 17 | validatePublicKey(publicKey, 'publicKey'); 18 | validateUint(coin, 'coin'); 19 | validateAmount(stake, 'stake'); 20 | } 21 | 22 | this.publicKey = publicKey; 23 | this.coin = coin; 24 | this.stake = stake; 25 | 26 | this.txData = new TxDataUnbond({ 27 | publicKey: toBuffer(publicKey), 28 | coin: integerToHexString(coin), 29 | stake: `0x${convertToPip(stake, 'hex')}`, 30 | }); 31 | 32 | proxyNestedTxData(this); 33 | } 34 | 35 | 36 | /** 37 | * @param {object} txData 38 | * @param {Buffer|string} txData.publicKey 39 | * @param {Buffer|string} txData.stake 40 | * @param {Buffer|string} txData.coin 41 | * @param {TxOptions} [options] 42 | * @return {UnbondTxData} 43 | */ 44 | UnbondTxData.fromBufferFields = function fromBufferFields({publicKey, coin, stake}, options = {}) { 45 | return new UnbondTxData({ 46 | publicKey: dataToPublicKey(publicKey), 47 | coin: dataToInteger(coin), 48 | stake: dataPipToAmount(stake), 49 | }, options); 50 | }; 51 | 52 | /** 53 | * @param {Buffer|string} data 54 | * @return {UnbondTxData} 55 | */ 56 | UnbondTxData.fromRlp = function fromRlp(data) { 57 | return UnbondTxData.fromBufferFields(new TxDataUnbond(data)); 58 | }; 59 | -------------------------------------------------------------------------------- /src/tx-data/token-burn.js: -------------------------------------------------------------------------------- 1 | import {TxDataBurnToken} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | import {dataToInteger, dataPipToAmount, integerToHexString, proxyNestedTxData, validateUint, validateAmount} from '../utils.js'; 4 | 5 | 6 | /** 7 | * @param {object} txData 8 | * @param {number|string} txData.value 9 | * @param {number|string} txData.coin - coin id 10 | * @param {TxOptions} [options] 11 | * @constructor 12 | */ 13 | export default function BurnTokenTxData({value = 0, coin}, options = {}) { 14 | if (!options.disableValidation) { 15 | validateUint(coin, 'coin'); 16 | validateAmount(value, 'value'); 17 | } 18 | 19 | this.value = value; 20 | this.coin = coin; 21 | 22 | this.txData = new TxDataBurnToken({ 23 | coin: integerToHexString(coin), 24 | value: `0x${convertToPip(value, 'hex')}`, 25 | }); 26 | 27 | proxyNestedTxData(this); 28 | } 29 | 30 | /** 31 | * @param {object} txData 32 | * @param {Buffer|string|number} txData.value 33 | * @param {Buffer|string|number} txData.coin 34 | * @param {TxOptions} [options] 35 | * @return {BurnTokenTxData} 36 | */ 37 | BurnTokenTxData.fromBufferFields = function fromBufferFields({value, coin}, options = {}) { 38 | return new BurnTokenTxData({ 39 | coin: dataToInteger(coin), 40 | value: dataPipToAmount(value), 41 | }, options); 42 | }; 43 | 44 | /** 45 | * @param {Buffer|string} data 46 | * @return {BurnTokenTxData} 47 | */ 48 | BurnTokenTxData.fromRlp = function fromRlp(data) { 49 | return BurnTokenTxData.fromBufferFields(new TxDataBurnToken(data)); 50 | }; 51 | -------------------------------------------------------------------------------- /src/tx-data/token-create.js: -------------------------------------------------------------------------------- 1 | import {TxDataCreateToken} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer, coinToBuffer, bufferToCoin, COIN_MAX_MAX_SUPPLY} from 'minterjs-util'; 3 | import {dataPipToAmount, proxyNestedTxData, validateAmount, validateTicker, validateMaxSupply, validateBoolean, bufferToBoolean} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {string} [txData.name] 8 | * @param {string} txData.symbol 9 | * @param {number|string} txData.initialAmount 10 | * @param {number|string} [txData.maxSupply] 11 | * @param {boolean} txData.mintable 12 | * @param {boolean} txData.burnable 13 | * @param {TxOptions} [options] 14 | * @constructor 15 | */ 16 | export default function CreateTokenTxData({name = '', symbol, initialAmount, maxSupply = COIN_MAX_MAX_SUPPLY, mintable, burnable}, options = {}) { 17 | if (!options.disableValidation) { 18 | validateTicker(symbol, 'symbol'); 19 | validateAmount(initialAmount, 'initialAmount'); 20 | validateMaxSupply(maxSupply, initialAmount); 21 | validateBoolean(mintable, 'mintable'); 22 | validateBoolean(burnable, 'burnable'); 23 | } 24 | 25 | this.name = name; 26 | this.symbol = symbol; 27 | this.initialAmount = initialAmount; 28 | this.maxSupply = maxSupply; 29 | this.mintable = mintable; 30 | this.burnable = burnable; 31 | 32 | this.txData = new TxDataCreateToken({ 33 | name: Buffer.from(name.toString(), 'utf8'), 34 | symbol: coinToBuffer(symbol), 35 | initialAmount: `0x${convertToPip(initialAmount, 'hex')}`, 36 | maxSupply: `0x${convertToPip(maxSupply, 'hex')}`, 37 | mintable: mintable ? '0x01' : '0x00', 38 | burnable: burnable ? '0x01' : '0x00', 39 | }); 40 | 41 | proxyNestedTxData(this); 42 | } 43 | 44 | /** 45 | * @param {object} txData 46 | * @param {Buffer|string} txData.name 47 | * @param {Buffer|string} txData.symbol 48 | * @param {Buffer|string|number} txData.initialAmount 49 | * @param {Buffer|string|number} txData.maxSupply 50 | * @param {Buffer|string} txData.mintable 51 | * @param {Buffer|string} txData.burnable 52 | * @param {TxOptions} [options] 53 | * @return {CreateTokenTxData} 54 | */ 55 | CreateTokenTxData.fromBufferFields = function fromBufferFields({name, symbol, initialAmount, maxSupply, mintable, burnable}, options = {}) { 56 | return new CreateTokenTxData({ 57 | name: toBuffer(name).toString('utf8'), 58 | symbol: bufferToCoin(toBuffer(symbol)), 59 | initialAmount: dataPipToAmount(initialAmount), 60 | maxSupply: dataPipToAmount(maxSupply), 61 | mintable: bufferToBoolean(toBuffer(mintable)), 62 | burnable: bufferToBoolean(toBuffer(burnable)), 63 | }, options); 64 | }; 65 | 66 | /** 67 | * @param {Buffer|string} data 68 | * @return {CreateTokenTxData} 69 | */ 70 | CreateTokenTxData.fromRlp = function fromRlp(data) { 71 | return CreateTokenTxData.fromBufferFields(new TxDataCreateToken(data)); 72 | }; 73 | -------------------------------------------------------------------------------- /src/tx-data/token-mint.js: -------------------------------------------------------------------------------- 1 | import {TxDataMintToken} from 'minterjs-tx'; 2 | import {convertToPip} from 'minterjs-util'; 3 | import {dataToInteger, dataPipToAmount, integerToHexString, proxyNestedTxData, validateUint, validateAmount} from '../utils.js'; 4 | 5 | 6 | /** 7 | * @param {object} txData 8 | * @param {number|string} txData.value 9 | * @param {number|string} txData.coin - coin id 10 | * @param {TxOptions} [options] 11 | * @constructor 12 | */ 13 | export default function MintTokenTxData({value = 0, coin}, options = {}) { 14 | if (!options.disableValidation) { 15 | validateUint(coin, 'coin'); 16 | validateAmount(value, 'value'); 17 | } 18 | 19 | this.value = value; 20 | this.coin = coin; 21 | 22 | this.txData = new TxDataMintToken({ 23 | coin: integerToHexString(coin), 24 | value: `0x${convertToPip(value, 'hex')}`, 25 | }); 26 | 27 | proxyNestedTxData(this); 28 | } 29 | 30 | /** 31 | * @param {object} txData 32 | * @param {Buffer|string|number} txData.value 33 | * @param {Buffer|string|number} txData.coin 34 | * @param {TxOptions} [options] 35 | * @return {MintTokenTxData} 36 | */ 37 | MintTokenTxData.fromBufferFields = function fromBufferFields({value, coin}, options = {}) { 38 | return new MintTokenTxData({ 39 | coin: dataToInteger(coin), 40 | value: dataPipToAmount(value), 41 | }, options); 42 | }; 43 | 44 | /** 45 | * @param {Buffer|string} data 46 | * @return {MintTokenTxData} 47 | */ 48 | MintTokenTxData.fromRlp = function fromRlp(data) { 49 | return MintTokenTxData.fromBufferFields(new TxDataMintToken(data)); 50 | }; 51 | -------------------------------------------------------------------------------- /src/tx-data/token-recreate.js: -------------------------------------------------------------------------------- 1 | import {TxDataRecreateToken} from 'minterjs-tx'; 2 | import {convertToPip, toBuffer, coinToBuffer, bufferToCoin, COIN_MAX_MAX_SUPPLY} from 'minterjs-util'; 3 | import {proxyNestedTxData, dataPipToAmount, validateAmount, validateTicker, validateMaxSupply, validateBoolean, bufferToBoolean} from '../utils.js'; 4 | 5 | /** 6 | * @param {object} txData 7 | * @param {string} [txData.name] 8 | * @param {string} txData.symbol 9 | * @param {number|string} txData.initialAmount 10 | * @param {number|string} [txData.maxSupply] 11 | * @param {boolean} txData.mintable 12 | * @param {boolean} txData.burnable 13 | * @param {TxOptions} [options] 14 | * @constructor 15 | */ 16 | export default function RecreateTokenTxData({name = '', symbol, initialAmount, maxSupply = COIN_MAX_MAX_SUPPLY, mintable, burnable}, options = {}) { 17 | if (!options.disableValidation) { 18 | validateTicker(symbol, 'symbol'); 19 | validateAmount(initialAmount, 'initialAmount'); 20 | validateMaxSupply(maxSupply, initialAmount); 21 | validateBoolean(mintable, 'mintable'); 22 | validateBoolean(burnable, 'burnable'); 23 | } 24 | 25 | this.name = name; 26 | this.symbol = symbol; 27 | this.initialAmount = initialAmount; 28 | this.maxSupply = maxSupply; 29 | this.mintable = mintable; 30 | this.burnable = burnable; 31 | 32 | this.txData = new TxDataRecreateToken({ 33 | name: Buffer.from(name.toString(), 'utf8'), 34 | symbol: coinToBuffer(symbol), 35 | initialAmount: `0x${convertToPip(initialAmount, 'hex')}`, 36 | maxSupply: `0x${convertToPip(maxSupply, 'hex')}`, 37 | mintable: mintable ? '0x01' : '0x00', 38 | burnable: burnable ? '0x01' : '0x00', 39 | }); 40 | 41 | proxyNestedTxData(this); 42 | } 43 | 44 | /** 45 | * @param {object} txData 46 | * @param {Buffer|string} txData.name 47 | * @param {Buffer|string} txData.symbol 48 | * @param {Buffer|string|number} txData.initialAmount 49 | * @param {Buffer|string|number} txData.maxSupply 50 | * @param {Buffer|string} txData.mintable 51 | * @param {Buffer|string} txData.burnable 52 | * @param {TxOptions} [options] 53 | * @return {RecreateTokenTxData} 54 | */ 55 | RecreateTokenTxData.fromBufferFields = function fromBufferFields({name, symbol, initialAmount, maxSupply, mintable, burnable}, options = {}) { 56 | return new RecreateTokenTxData({ 57 | name: toBuffer(name).toString('utf8'), 58 | symbol: bufferToCoin(toBuffer(symbol)), 59 | initialAmount: dataPipToAmount(initialAmount), 60 | maxSupply: dataPipToAmount(maxSupply), 61 | mintable: bufferToBoolean(toBuffer(mintable)), 62 | burnable: bufferToBoolean(toBuffer(burnable)), 63 | }, options); 64 | }; 65 | 66 | /** 67 | * @param {Buffer|string} data 68 | * @return {RecreateTokenTxData} 69 | */ 70 | RecreateTokenTxData.fromRlp = function fromRlp(data) { 71 | return RecreateTokenTxData.fromBufferFields(new TxDataRecreateToken(data)); 72 | }; 73 | -------------------------------------------------------------------------------- /src/tx-data/vote-halt-block.js: -------------------------------------------------------------------------------- 1 | import {TxDataSetHaltBlock} from 'minterjs-tx'; 2 | import {toBuffer} from 'minterjs-util'; 3 | import {dataToInteger, dataToPublicKey, integerToHexString, proxyNestedTxData, validateUint, validatePublicKey} from '../utils.js'; 4 | 5 | 6 | /** 7 | * @param {object} txData 8 | * @param {string} txData.publicKey 9 | * @param {number|string} txData.height 10 | * @param {TxOptions} [options] 11 | * @constructor 12 | */ 13 | export default function VoteHaltBlockTxData({publicKey, height}, options = {}) { 14 | if (!options.disableValidation) { 15 | validatePublicKey(publicKey, 'publicKey'); 16 | validateUint(height, 'height'); 17 | } 18 | 19 | this.publicKey = publicKey; 20 | this.height = height; 21 | 22 | this.txData = new TxDataSetHaltBlock({ 23 | publicKey: toBuffer(publicKey), 24 | height: integerToHexString(height), 25 | }); 26 | 27 | proxyNestedTxData(this); 28 | } 29 | 30 | /** 31 | * @param {object} txData 32 | * @param {Buffer|string} txData.publicKey 33 | * @param {Buffer|string|number} txData.height 34 | * @param {TxOptions} [options] 35 | * @return {VoteHaltBlockTxData} 36 | */ 37 | VoteHaltBlockTxData.fromBufferFields = function fromBufferFields({publicKey, height}, options = {}) { 38 | return new VoteHaltBlockTxData({ 39 | publicKey: dataToPublicKey(publicKey), 40 | height: dataToInteger(height), 41 | }, options); 42 | }; 43 | 44 | /** 45 | * @param {Buffer|string} data 46 | * @return {VoteHaltBlockTxData} 47 | */ 48 | VoteHaltBlockTxData.fromRlp = function fromRlp(data) { 49 | return VoteHaltBlockTxData.fromBufferFields(new TxDataSetHaltBlock(data)); 50 | }; 51 | -------------------------------------------------------------------------------- /src/tx-data/vote-price.js: -------------------------------------------------------------------------------- 1 | import {TxDataPriceVote} from 'minterjs-tx'; 2 | import {dataToInteger, integerToHexString, proxyNestedTxData, validateUint} from '../utils.js'; 3 | 4 | 5 | /** 6 | * @param {object} txTata 7 | * @param {number|string} txTata.price 8 | * @param {TxOptions} [options] 9 | * @constructor 10 | */ 11 | export default function PriceVoteTxData({price}, options = {}) { 12 | if (!options.disableValidation) { 13 | validateUint(price, 'price'); 14 | } 15 | 16 | this.price = price; 17 | 18 | this.txData = new TxDataPriceVote({ 19 | price: integerToHexString(price), 20 | }); 21 | 22 | proxyNestedTxData(this); 23 | } 24 | 25 | /** 26 | * @param {Buffer|string|number} price 27 | * @param {TxOptions} [options] 28 | * @return {PriceVoteTxData} 29 | */ 30 | PriceVoteTxData.fromBufferFields = function fromBufferFields({price}, options = {}) { 31 | return new PriceVoteTxData({ 32 | price: dataToInteger(price), 33 | }, options); 34 | }; 35 | 36 | /** 37 | * @param {Buffer|string} data 38 | * @return {PriceVoteTxData} 39 | */ 40 | PriceVoteTxData.fromRlp = function fromRlp(data) { 41 | return PriceVoteTxData.fromBufferFields(new TxDataPriceVote(data)); 42 | }; 43 | -------------------------------------------------------------------------------- /src/tx-data/vote-update.js: -------------------------------------------------------------------------------- 1 | import {TxDataVoteUpdate} from 'minterjs-tx'; 2 | import {toBuffer} from 'minterjs-util'; 3 | import {dataToInteger, dataToPublicKey, integerToHexString, proxyNestedTxData, validateUint, validatePublicKey} from '../utils.js'; 4 | 5 | 6 | /** 7 | * @param {object} txData 8 | * @param {string} txData.version 9 | * @param {string} txData.publicKey 10 | * @param {number|string} txData.height 11 | * @param {TxOptions} [options] 12 | * @constructor 13 | */ 14 | export default function VoteUpdateTxData({version, publicKey, height}, options = {}) { 15 | if (!options.disableValidation) { 16 | validatePublicKey(publicKey, 'publicKey'); 17 | validateUint(height, 'height'); 18 | } 19 | 20 | this.version = version; 21 | this.publicKey = publicKey; 22 | this.height = height; 23 | 24 | this.txData = new TxDataVoteUpdate({ 25 | version: Buffer.from(version.toString(), 'utf8'), 26 | publicKey: toBuffer(publicKey), 27 | height: integerToHexString(height), 28 | }); 29 | 30 | proxyNestedTxData(this); 31 | } 32 | 33 | /** 34 | * @param {object} txTata 35 | * @param {Buffer|string} txTata.version 36 | * @param {Buffer|string} txTata.publicKey 37 | * @param {Buffer|string|number} txTata.height 38 | * @param {TxOptions} [options] 39 | * @return {VoteUpdateTxData} 40 | */ 41 | VoteUpdateTxData.fromBufferFields = function fromBufferFields({version, publicKey, height}, options = {}) { 42 | return new VoteUpdateTxData({ 43 | version: toBuffer(version).toString('utf8'), 44 | publicKey: dataToPublicKey(publicKey), 45 | height: dataToInteger(height), 46 | }, options); 47 | }; 48 | 49 | /** 50 | * @param {Buffer|string} data 51 | * @return {VoteUpdateTxData} 52 | */ 53 | VoteUpdateTxData.fromRlp = function fromRlp(data) { 54 | return VoteUpdateTxData.fromBufferFields(new TxDataVoteUpdate(data)); 55 | }; 56 | -------------------------------------------------------------------------------- /src/tx-decorator/candidacy-declare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateDeclareCandidacyTxParams(params) { 6 | if (params.gasCoin === undefined) { 7 | params.gasCoin = params.data.coin; 8 | } 9 | 10 | return params; 11 | } 12 | -------------------------------------------------------------------------------- /src/tx-decorator/convert-buy-pool.js: -------------------------------------------------------------------------------- 1 | export {default} from './convert-sell-pool.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/convert-buy.js: -------------------------------------------------------------------------------- 1 | export {default} from './convert-sell.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/convert-sell-all-pool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateSellAllSwapPoolTxParams(params) { 6 | // force gasCoin to be same as coin to sell 7 | params.gasCoin = params.data.coins[0]; 8 | 9 | return params; 10 | } 11 | -------------------------------------------------------------------------------- /src/tx-decorator/convert-sell-all.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateSellTxParams(params) { 6 | // force gasCoin to be same as coinToSell 7 | params.gasCoin = params.data.coinToSell; 8 | 9 | return params; 10 | } 11 | -------------------------------------------------------------------------------- /src/tx-decorator/convert-sell-pool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateSellSwapPoolTxParams(params) { 6 | if (params.gasCoin === undefined) { 7 | params.gasCoin = params.data.coins[0]; 8 | } 9 | 10 | return params; 11 | } 12 | -------------------------------------------------------------------------------- /src/tx-decorator/convert-sell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateSellTxParams(params) { 6 | if (params.gasCoin === undefined) { 7 | params.gasCoin = params.data.coinToSell; 8 | } 9 | 10 | return params; 11 | } 12 | -------------------------------------------------------------------------------- /src/tx-decorator/index.js: -------------------------------------------------------------------------------- 1 | import {TX_TYPE, normalizeTxType} from 'minterjs-util'; 2 | import decorateSendTxParams from './send.js'; 3 | import decorateSellTxParams from './convert-sell.js'; 4 | import decorateBuyTxParams from './convert-buy.js'; 5 | import decorateSellAllTxParams from './convert-sell-all.js'; 6 | import decorateSellSwapPoolTxParams from './convert-sell-pool.js'; 7 | import decorateBuySwapPoolTxParams from './convert-buy-pool.js'; 8 | import decorateSellAllSwapPoolTxParams from './convert-sell-all-pool.js'; 9 | import decorateCreateSwapPoolTxParams from './pool-create.js'; 10 | import decorateAddLiquidityTxParams from './pool-add-liquidity.js'; 11 | import decorateAddLimitOrderTxParams from './limit-order-add.js'; 12 | import decorateDeclareCandidacyTxParams from './candidacy-declare.js'; 13 | import decorateDelegateTxParams from './stake-delegate.js'; 14 | // import decorateUnbondTxParams from './stake-unbond.js'; 15 | import decorateMoveStakeTxParams from './stake-move.js'; 16 | import decorateBurnTokenTxParams from './token-burn.js'; 17 | import decorateRedeemCheckTxParams from './redeem-check.js'; 18 | import decorateLockTxParams from './lock.js'; 19 | 20 | const noop = (x) => x; 21 | 22 | /** 23 | * @param {TxParams} txParams 24 | * @param {object} [options] 25 | * @param {boolean} [options.setGasCoinAsCoinToSpend] 26 | * @return {TxParams} 27 | */ 28 | export default function decorateTxParams(txParams, {setGasCoinAsCoinToSpend} = {}) { 29 | const txType = normalizeTxType(txParams.type || txParams.txType); 30 | 31 | const TX_PARAMS_DECORATOR = { 32 | [TX_TYPE.SEND]: setGasCoinAsCoinToSpend ? decorateSendTxParams : noop, 33 | [TX_TYPE.MULTISEND]: noop, 34 | [TX_TYPE.SELL]: setGasCoinAsCoinToSpend ? decorateSellTxParams : noop, 35 | [TX_TYPE.BUY]: setGasCoinAsCoinToSpend ? decorateBuyTxParams : noop, 36 | [TX_TYPE.SELL_ALL]: decorateSellAllTxParams, 37 | [TX_TYPE.CREATE_COIN]: noop, 38 | [TX_TYPE.DECLARE_CANDIDACY]: setGasCoinAsCoinToSpend ? decorateDeclareCandidacyTxParams : noop, 39 | [TX_TYPE.EDIT_CANDIDATE]: noop, 40 | [TX_TYPE.EDIT_CANDIDATE_PUBLIC_KEY]: noop, 41 | [TX_TYPE.SET_CANDIDATE_ON]: noop, 42 | [TX_TYPE.SET_CANDIDATE_OFF]: noop, 43 | [TX_TYPE.DELEGATE]: setGasCoinAsCoinToSpend ? decorateDelegateTxParams : noop, 44 | [TX_TYPE.UNBOND]: noop, // decorateUnbondTxParams, 45 | [TX_TYPE.REDEEM_CHECK]: decorateRedeemCheckTxParams, 46 | [TX_TYPE.CREATE_MULTISIG]: noop, 47 | [TX_TYPE.SET_HALT_BLOCK]: noop, 48 | [TX_TYPE.RECREATE_COIN]: noop, 49 | [TX_TYPE.EDIT_TICKER_OWNER]: noop, 50 | [TX_TYPE.EDIT_MULTISIG]: noop, 51 | [TX_TYPE.PRICE_VOTE]: noop, 52 | [TX_TYPE.EDIT_CANDIDATE_PUBLIC_KEY]: noop, 53 | [TX_TYPE.ADD_LIQUIDITY]: setGasCoinAsCoinToSpend ? decorateAddLiquidityTxParams : noop, 54 | [TX_TYPE.REMOVE_LIQUIDITY]: noop, 55 | [TX_TYPE.BUY_SWAP_POOL]: setGasCoinAsCoinToSpend ? decorateBuySwapPoolTxParams : noop, 56 | [TX_TYPE.SELL_SWAP_POOL]: setGasCoinAsCoinToSpend ? decorateSellSwapPoolTxParams : noop, 57 | [TX_TYPE.SELL_ALL_SWAP_POOL]: decorateSellAllSwapPoolTxParams, 58 | [TX_TYPE.EDIT_CANDIDATE_COMMISSION]: noop, 59 | [TX_TYPE.MOVE_STAKE]: setGasCoinAsCoinToSpend ? decorateMoveStakeTxParams : noop, 60 | [TX_TYPE.MINT_TOKEN]: noop, 61 | [TX_TYPE.BURN_TOKEN]: setGasCoinAsCoinToSpend ? decorateBurnTokenTxParams : noop, 62 | [TX_TYPE.CREATE_TOKEN]: noop, 63 | [TX_TYPE.RECREATE_TOKEN]: noop, 64 | [TX_TYPE.VOTE_COMMISSION]: noop, 65 | [TX_TYPE.VOTE_UPDATE]: noop, 66 | [TX_TYPE.CREATE_SWAP_POOL]: setGasCoinAsCoinToSpend ? decorateCreateSwapPoolTxParams : noop, 67 | [TX_TYPE.ADD_LIMIT_ORDER]: setGasCoinAsCoinToSpend ? decorateAddLimitOrderTxParams : noop, 68 | [TX_TYPE.REMOVE_LIMIT_ORDER]: noop, 69 | [TX_TYPE.LOCK_STAKE]: noop, 70 | [TX_TYPE.LOCK]: setGasCoinAsCoinToSpend ? decorateLockTxParams : noop, 71 | }; 72 | 73 | return TX_PARAMS_DECORATOR[txType](txParams); 74 | } 75 | -------------------------------------------------------------------------------- /src/tx-decorator/limit-order-add.js: -------------------------------------------------------------------------------- 1 | export {default} from './convert-sell.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/lock.js: -------------------------------------------------------------------------------- 1 | export {default} from './send.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/pool-add-liquidity.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateAddLiquidityTxParams(params) { 6 | if (params.gasCoin === undefined) { 7 | params.gasCoin = params.data.coin0; 8 | } 9 | 10 | return params; 11 | } 12 | -------------------------------------------------------------------------------- /src/tx-decorator/pool-create.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateCreateSwapPoolTxParams(params) { 6 | if (params.gasCoin === undefined) { 7 | params.gasCoin = params.data.coin0; 8 | } 9 | 10 | return params; 11 | } 12 | -------------------------------------------------------------------------------- /src/tx-decorator/redeem-check.js: -------------------------------------------------------------------------------- 1 | import {getGasCoinFromCheck} from '../check.js'; 2 | import RedeemCheckTxData from '../tx-data/redeem-check.js'; 3 | 4 | /** 5 | * @param {TxParams} params 6 | * @return {TxParams} 7 | */ 8 | export default function decorateRedeemCheckTxParams(params) { 9 | const check = params.data.check || RedeemCheckTxData.fromRlp(params.data).check; 10 | params.gasCoin = getGasCoinFromCheck(check); 11 | 12 | // only gasPrice: 1 is allowed by blockchain 13 | params.gasPrice = 1; 14 | 15 | return params; 16 | } 17 | -------------------------------------------------------------------------------- /src/tx-decorator/send.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {TxParams} params 3 | * @return {TxParams} 4 | */ 5 | export default function decorateSendTxParams(params) { 6 | if (params.gasCoin === undefined) { 7 | params.gasCoin = params.data.coin; 8 | } 9 | 10 | return params; 11 | } 12 | -------------------------------------------------------------------------------- /src/tx-decorator/stake-delegate.js: -------------------------------------------------------------------------------- 1 | export {default} from './candidacy-declare.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/stake-move.js: -------------------------------------------------------------------------------- 1 | export {default} from './candidacy-declare.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/stake-unbond.js: -------------------------------------------------------------------------------- 1 | export {default} from './candidacy-declare.js'; 2 | -------------------------------------------------------------------------------- /src/tx-decorator/token-burn.js: -------------------------------------------------------------------------------- 1 | export {default} from './send.js'; 2 | -------------------------------------------------------------------------------- /src/variables.js: -------------------------------------------------------------------------------- 1 | export const API_TYPE_GATE = 'gate'; 2 | export const API_TYPE_NODE = 'node'; 3 | /** 4 | * @enum {string} 5 | */ 6 | export const ESTIMATE_SWAP_TYPE = { 7 | OPTIMAL: 'optimal', 8 | POOL: 'pool', 9 | BANCOR: 'bancor', 10 | }; 11 | -------------------------------------------------------------------------------- /test/api/get-coin-info.test.js: -------------------------------------------------------------------------------- 1 | import {ensureCustomCoin, logError} from '~/test/test-utils.js'; 2 | import {ENV_DATA, minterGate, minterNode} from './variables'; 3 | 4 | beforeAll(async () => { 5 | await ensureCustomCoin(); 6 | }, 30000); 7 | 8 | describe('GetCoinInfo', () => { 9 | test('should work gate', () => { 10 | expect.assertions(1); 11 | 12 | return minterGate.getCoinInfo(ENV_DATA.customCoin) 13 | .then((coinInfo) => { 14 | expect(coinInfo.id).toBeGreaterThan(0); 15 | }) 16 | .catch((error) => { 17 | logError(error); 18 | throw error; 19 | }); 20 | }, 30000); 21 | 22 | test('should work node', () => { 23 | expect.assertions(1); 24 | 25 | return minterNode.getCoinInfo(ENV_DATA.customCoin) 26 | .then((coinInfo) => { 27 | expect(coinInfo.id).toBeGreaterThan(0); 28 | }) 29 | .catch((error) => { 30 | logError(error); 31 | throw error; 32 | }); 33 | }, 30000); 34 | }); 35 | 36 | describe('GetCoinInfo by ID', () => { 37 | test('should work gate', () => { 38 | expect.assertions(1); 39 | 40 | return minterGate.getCoinInfo(0) 41 | .then((coinInfo) => { 42 | expect(coinInfo.symbol === 'MNT' || coinInfo.symbol === 'BIP').toBeTruthy(); 43 | }) 44 | .catch((error) => { 45 | logError(error); 46 | throw error; 47 | }); 48 | }, 30000); 49 | 50 | test('should work node', () => { 51 | expect.assertions(1); 52 | 53 | return minterNode.getCoinInfo(0) 54 | .then((coinInfo) => { 55 | expect(coinInfo.symbol === 'MNT' || coinInfo.symbol === 'BIP').toBeTruthy(); 56 | }) 57 | .catch((error) => { 58 | logError(error); 59 | throw error; 60 | }); 61 | }, 30000); 62 | }); 63 | -------------------------------------------------------------------------------- /test/api/get-commission-price.test.js: -------------------------------------------------------------------------------- 1 | import {FeePrice, TX_TYPE} from 'minterjs-util'; 2 | import {logError} from '~/test/test-utils.js'; 3 | import {minterGate, minterNode} from './variables.js'; 4 | 5 | const API_TYPE_LIST = [ 6 | { 7 | ...minterNode, 8 | toString() { 9 | return 'node'; 10 | }, 11 | }, 12 | { 13 | ...minterGate, 14 | toString() { 15 | return 'gate'; 16 | }, 17 | }, 18 | ]; 19 | 20 | 21 | describe('GetCommissionPrice', () => { 22 | test.each(API_TYPE_LIST)('should work %s', (apiType) => { 23 | expect.assertions(2); 24 | 25 | return apiType.getCommissionPrice() 26 | .then((commissionData) => { 27 | const feePrice = new FeePrice(commissionData); 28 | function getFeeValue() { 29 | // eslint-disable-next-line prefer-rest-params 30 | return parseFloat(feePrice.getFeeValue(...arguments)); 31 | } 32 | 33 | expect(getFeeValue(TX_TYPE.SEND)).toBeGreaterThan(0); 34 | expect(getFeeValue(TX_TYPE.CREATE_COIN, {coinSymbolLength: 3})).toBeGreaterThan(getFeeValue(TX_TYPE.CREATE_COIN, {coinSymbolLength: 7})); 35 | }) 36 | .catch((error) => { 37 | logError(error); 38 | throw error; 39 | }); 40 | }, 30000); 41 | }); 42 | -------------------------------------------------------------------------------- /test/api/get-min-gas-price.test.js: -------------------------------------------------------------------------------- 1 | import {logError} from '~/test/test-utils.js'; 2 | import {minterGate, minterNode} from './variables'; 3 | 4 | 5 | describe('GetMinGasPrice', () => { 6 | test('should work gate', () => { 7 | expect.assertions(1); 8 | 9 | return minterGate.getMinGasPrice() 10 | .then((gasPrice) => { 11 | expect(gasPrice).toBeGreaterThan(0); 12 | }) 13 | .catch((error) => { 14 | logError(error); 15 | throw error; 16 | }); 17 | }, 30000); 18 | 19 | test('should work node', () => { 20 | expect.assertions(1); 21 | 22 | return minterNode.getMinGasPrice() 23 | .then((gasPrice) => { 24 | expect(Number(gasPrice)).toBeGreaterThan(0); 25 | }) 26 | .catch((error) => { 27 | logError(error); 28 | throw error; 29 | }); 30 | }, 30000); 31 | }); 32 | -------------------------------------------------------------------------------- /test/api/get-nonce.test.js: -------------------------------------------------------------------------------- 1 | import {logError} from '~/test/test-utils.js'; 2 | import {ENV_DATA, minterGate, minterNode} from './variables'; 3 | 4 | 5 | describe('GetNonce', () => { 6 | test('should work gate', () => { 7 | expect.assertions(1); 8 | 9 | return minterGate.getNonce(ENV_DATA.address) 10 | .then((nonce) => { 11 | expect(nonce).toBeGreaterThan(0); 12 | }) 13 | .catch((error) => { 14 | logError(error); 15 | }); 16 | }, 30000); 17 | 18 | test('should work node', () => { 19 | expect.assertions(1); 20 | 21 | return minterNode.getNonce(ENV_DATA.address) 22 | .then((nonce) => { 23 | expect(nonce).toBeGreaterThan(0); 24 | }) 25 | .catch((error) => { 26 | logError(error); 27 | }); 28 | }, 30000); 29 | }); 30 | -------------------------------------------------------------------------------- /test/api/get-pool-info.test.js: -------------------------------------------------------------------------------- 1 | import {logError} from '~/test/test-utils.js'; 2 | import {minterGate, minterNode} from './variables.js'; 3 | 4 | const API_TYPE_LIST = [ 5 | { 6 | ...minterNode, 7 | toString() { 8 | return 'node'; 9 | }, 10 | }, 11 | { 12 | ...minterGate, 13 | toString() { 14 | return 'gate'; 15 | }, 16 | }, 17 | ]; 18 | 19 | 20 | describe('GetPoolInfo', () => { 21 | test.each(API_TYPE_LIST)('should work %s', (apiType) => { 22 | expect.assertions(1); 23 | 24 | // @TODO get proper pool pair 25 | return apiType.getPoolInfo(0, 1993) 26 | .then((poolInfo) => { 27 | expect(Number(poolInfo.amount0)).toBeGreaterThan(0); 28 | }) 29 | .catch((error) => { 30 | logError(error); 31 | throw error; 32 | }); 33 | }, 30000); 34 | 35 | test.each(API_TYPE_LIST)('should work coin symbol %s', (apiType) => { 36 | expect.assertions(1); 37 | 38 | // @TODO get proper pool pair 39 | return apiType.getPoolInfo('MNT', 'USDTE') 40 | .then((poolInfo) => { 41 | expect(Number(poolInfo.amount0)).toBeGreaterThan(0); 42 | }) 43 | .catch((error) => { 44 | logError(error); 45 | throw error; 46 | }); 47 | }, 30000); 48 | }); 49 | -------------------------------------------------------------------------------- /test/api/variables.js: -------------------------------------------------------------------------------- 1 | import {walletFromMnemonic} from 'minterjs-wallet'; 2 | import {Minter, API_TYPE_GATE, API_TYPE_NODE} from '~/src'; 3 | 4 | // mnemonic: exercise fantasy smooth enough arrive steak demise donkey true employ jealous decide blossom bind someone 5 | // private: 5fa3a8b186f6cc2d748ee2d8c0eb7a905a7b73de0f2c34c5e7857c3b46f187da 6 | // address: Mx7633980c000139dd3bd24a3f54e06474fa941e16 7 | 8 | // qa.gate-api.minter.network wallets with 1 000 000 000 9 | // "Mxeeda61bbe9929bf883af6b22f5796e4b92563ba4" // puzzle feed enlist rack cliff divert exist bind swamp kiwi casino pull 10 | // "Mx634550aa7dc347d5e60888da2529c56f1818e403" // air model item valley auction bullet crisp always erosion paper orient fog 11 | // "Mx49ca5b11f0055347df169985c0b70914150bb567" // erupt level forum warrior mutual wrap this elephant destroy trim habit annual 12 | 13 | const ENV_TESTNET = 'testnet'; 14 | const ENV_QA_TESTNET = 'qa'; 15 | const ENV_NEXT_TESTNET = 'next'; 16 | const TESTNET_MENMONIC = 'exercise fantasy smooth enough arrive steak demise donkey true employ jealous decide blossom bind someone'; 17 | const TESTNET_MENMONIC_2 = 'balance exist engage bargain slab genuine urge tooth critic slab admit coyote'; 18 | const QA_MNEMONIC = 'puzzle feed enlist rack cliff divert exist bind swamp kiwi casino pull'; 19 | const QA_MNEMONIC_2 = 'air model item valley auction bullet crisp always erosion paper orient fog'; 20 | const NEXT_MNEMONIC = 'toss disease race hour social anger oblige squeeze grant novel gown reveal'; 21 | // const CHILI_MNEMONIC_2 = 'measure enhance jealous amateur object cash reflect blood lab dawn oxygen garage'; 22 | 23 | const ENV_SETTINGS = { 24 | [ENV_TESTNET]: { 25 | nodeBaseUrl: 'https://node-api.testnet.minter.network/v2/', 26 | gateBaseUrl: 'https://gate-api.testnet.minter.network/api/v2/', 27 | mnemonic: TESTNET_MENMONIC, 28 | // 5fa3a8b186f6cc2d748ee2d8c0eb7a905a7b73de0f2c34c5e7857c3b46f187da 29 | privateKey: walletFromMnemonic(TESTNET_MENMONIC).getPrivateKeyString(), 30 | address: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 31 | mnemonic2: TESTNET_MENMONIC_2, 32 | privateKey2: walletFromMnemonic(TESTNET_MENMONIC_2).getPrivateKeyString(), 33 | address2: 'Mx116932f4353d643ac2410714f74fc1dfbc9c4053', 34 | customCoin: 'TESTCOIN01', 35 | }, 36 | [ENV_QA_TESTNET]: { 37 | nodeBaseUrl: 'https://qa.node-api.minter.network/', 38 | gateBaseUrl: 'https://qa.gate-api.minter.network/api/v1/', 39 | mnemonic: QA_MNEMONIC, 40 | privateKey: walletFromMnemonic(QA_MNEMONIC).getPrivateKeyString(), 41 | address: 'Mxeeda61bbe9929bf883af6b22f5796e4b92563ba4', 42 | mnemonic2: QA_MNEMONIC_2, 43 | privateKey2: walletFromMnemonic(QA_MNEMONIC_2).getPrivateKeyString(), 44 | address2: 'Mx634550aa7dc347d5e60888da2529c56f1818e403', 45 | customCoin: 'TESTCOIN01', 46 | }, 47 | [ENV_NEXT_TESTNET]: { 48 | nodeBaseUrl: 'https://node-api.toronet.minter.network/v2/', 49 | gateBaseUrl: 'https://gate-api.toronet.minter.network/api/v2/', 50 | mnemonic: QA_MNEMONIC, 51 | privateKey: walletFromMnemonic(QA_MNEMONIC).getPrivateKeyString(), 52 | address: 'Mxeeda61bbe9929bf883af6b22f5796e4b92563ba4', 53 | mnemonic2: QA_MNEMONIC_2, 54 | privateKey2: walletFromMnemonic(QA_MNEMONIC_2).getPrivateKeyString(), 55 | address2: 'Mx634550aa7dc347d5e60888da2529c56f1818e403', 56 | customCoin: 'TESTCOIN01', 57 | }, 58 | }; 59 | 60 | // select environment 61 | const currentEnv = ENV_TESTNET; 62 | export const ENV_DATA = ENV_SETTINGS[currentEnv]; 63 | 64 | 65 | export const minterNode = new Minter({apiType: API_TYPE_NODE, baseURL: ENV_DATA.nodeBaseUrl, timeout: 25000}); 66 | export const minterGate = new Minter({apiType: API_TYPE_GATE, baseURL: ENV_DATA.gateBaseUrl, timeout: 25000}); 67 | -------------------------------------------------------------------------------- /test/check.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable jest/no-export */ 2 | 3 | import {issueCheck, decodeCheck, getGasCoinFromCheck} from '~/src'; 4 | 5 | 6 | export const VALID_CHECK = 'Mcf8973101830f423f80888ac7230489e8000080b84199953f49ef0ed10d971b8df2c018e7699cd749feca03cad9d03f32a8992d77ab6c818d770466500b41165c18a1826662fb0d45b3a9193fcacc13a4131702e017011ba069f7cfdead0ea971e9f3e7b060463e10929ccf2f4309b8145c0916f51f4c5040a025767d4ea835ee8fc2a096b8f99717ef65627cad5e99c2427e34a9928881ba34'; 7 | // gasCoin: 5 8 | export const VALID_CHECK_WITH_CUSTOM_GAS_COIN = 'Mcf8973101830f423f80888ac7230489e8000005b841b0fe6d3805fae9f38bafefb74d0f61302fb37a20f0e9337871bef91c7423277646555dcb425fbb1ec35eda8a304bda41e9242dd55cb62a48e9b14a07262bc0d3011ba0ec85458016f3ba8de03000cc0a417836da4d0ae4013be482dce89285e04e559ca065b129e4d743a193774bf287a6421f9d39e23177d8bf603b236be337811be10a'; 9 | export const checkParams = { 10 | privateKey: '0x2919c43d5c712cae66f869a524d9523999998d51157dc40ac4d8d80a7602ce02', 11 | password: 'pass', 12 | nonce: '1', 13 | chainId: '1', 14 | coin: '0', 15 | value: '10', 16 | gasCoin: '0', 17 | dueBlock: '999999', 18 | }; 19 | 20 | describe('issueCheck()', () => { 21 | test('should work', () => { 22 | const check = issueCheck(checkParams); 23 | expect(check).toEqual(VALID_CHECK); 24 | }); 25 | 26 | test('should accept buffer private key', () => { 27 | const check = issueCheck({ 28 | ...checkParams, 29 | privateKey: Buffer.from(checkParams.privateKey.substr(2), 'hex'), 30 | }); 31 | expect(check).toEqual(VALID_CHECK); 32 | }); 33 | 34 | test('should work with custom gasCoin', () => { 35 | expect(issueCheck({ 36 | ...checkParams, 37 | gasCoin: '5', 38 | })).toEqual(VALID_CHECK_WITH_CUSTOM_GAS_COIN); 39 | }); 40 | 41 | test('default dueBlock: 999999', () => { 42 | expect(issueCheck({ 43 | ...checkParams, 44 | dueBlock: undefined, 45 | })).toEqual(issueCheck({ 46 | ...checkParams, 47 | dueBlock: 999999999, 48 | })); 49 | }); 50 | 51 | test('default chainId: 1', () => { 52 | expect(issueCheck({ 53 | ...checkParams, 54 | chainId: undefined, 55 | })).toEqual(issueCheck({ 56 | ...checkParams, 57 | chainId: 1, 58 | })); 59 | }); 60 | 61 | test('default gasCoin: 0 (base coin)', () => { 62 | expect(issueCheck({ 63 | ...checkParams, 64 | gasCoin: undefined, 65 | })).toEqual(issueCheck({ 66 | ...checkParams, 67 | gasCoin: '0', 68 | })); 69 | }); 70 | 71 | test('numeric nonce should be treated as string', () => { 72 | expect(issueCheck({ 73 | ...checkParams, 74 | nonce: 123, 75 | })).toEqual(issueCheck({ 76 | ...checkParams, 77 | nonce: '123', 78 | })); 79 | }); 80 | 81 | test('should throw on invalid dueBlock', () => { 82 | expect(() => issueCheck({ 83 | ...checkParams, 84 | dueBlock: '123asd', 85 | })).toThrow(); 86 | }); 87 | 88 | test('should throw on invalid value', () => { 89 | expect(() => issueCheck({ 90 | ...checkParams, 91 | value: '123asd', 92 | })).toThrow(); 93 | }); 94 | 95 | test('should throw with invalid gasCoin', () => { 96 | expect(() => issueCheck({ 97 | ...checkParams, 98 | gasCoin: true, 99 | })).toThrow(); 100 | }); 101 | 102 | test('should throw with string gasCoin', () => { 103 | expect(() => issueCheck({ 104 | ...checkParams, 105 | gasCoin: 'AA', 106 | })).toThrow(); 107 | }); 108 | }); 109 | 110 | describe('decodeCheck()', () => { 111 | const checkParamsWithoutSensitiveData = Object.assign({}, checkParams); 112 | delete checkParamsWithoutSensitiveData.password; 113 | delete checkParamsWithoutSensitiveData.privateKey; 114 | 115 | test('should work', () => { 116 | expect(decodeCheck(VALID_CHECK)).toEqual(checkParamsWithoutSensitiveData); 117 | }); 118 | 119 | test('should not lose precision', () => { 120 | const bigValue = '123456789012345.123456789012345678'; 121 | const check = issueCheck({...checkParams, value: bigValue}); 122 | expect(decodeCheck(check).value).toEqual(bigValue); 123 | }); 124 | }); 125 | 126 | describe('getGasCoinFromCheck()', () => { 127 | test('should work', () => { 128 | const check = issueCheck(checkParams); 129 | expect(getGasCoinFromCheck(check)).toEqual('0'); 130 | }); 131 | }); 132 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/test-utils.js: -------------------------------------------------------------------------------- 1 | // @TODO replace with .fields 2 | // eslint-disable-next-line import/prefer-default-export 3 | import {TX_TYPE} from 'minterjs-util'; 4 | import {ENV_DATA, minterGate, minterNode} from '~/test/api/variables.js'; 5 | 6 | export function clearData(dirtyData) { 7 | // eslint-disable-next-line no-unused-vars 8 | const {raw, serialize, txData, fields, ...data} = dirtyData; 9 | Object.keys(data).forEach((key) => { 10 | data[key] = data[key].toString(); 11 | }); 12 | 13 | return data; 14 | } 15 | 16 | const ensureCoinPromiseList = {}; 17 | 18 | /** 19 | * @param {string} [coinSymbol] 20 | * @param {string} [privateKey] 21 | * @return {Promise} 22 | */ 23 | export function ensureCustomCoin({coinSymbol, privateKey} = {}) { 24 | coinSymbol = coinSymbol || ENV_DATA.customCoin; 25 | privateKey = privateKey || ENV_DATA.privateKey; 26 | 27 | // ensure custom coin exists 28 | const txParams = { 29 | chainId: 2, 30 | type: TX_TYPE.CREATE_COIN, 31 | data: { 32 | name: coinSymbol, 33 | symbol: coinSymbol, 34 | initialAmount: 5000, 35 | initialReserve: 20000, 36 | constantReserveRatio: 50, 37 | }, 38 | }; 39 | 40 | if (ensureCoinPromiseList[coinSymbol]) { 41 | return ensureCoinPromiseList[coinSymbol]; 42 | } 43 | 44 | ensureCoinPromiseList[coinSymbol] = minterGate.postTx(txParams, {privateKey}) 45 | .catch((error) => { 46 | if (error.response?.data?.error?.message !== 'Coin already exists') { 47 | logError(error); 48 | } 49 | return minterGate.replaceCoinSymbol({ 50 | chainId: 2, 51 | type: TX_TYPE.SELL, 52 | data: { 53 | coinToBuy: coinSymbol, 54 | coinToSell: 'MNT', 55 | valueToSell: 15000, 56 | }, 57 | }); 58 | }) 59 | .then((sellTxParams) => { 60 | return minterGate.postTx(sellTxParams, {privateKey}); 61 | }) 62 | .catch((error) => { 63 | logError(error); 64 | }); 65 | 66 | return ensureCoinPromiseList[coinSymbol]; 67 | } 68 | 69 | const MAX_VALIDATOR_COUNT = 100; 70 | // -2 to declare two our new validators 71 | const LAST_VALIDATOR_NUMBER = MAX_VALIDATOR_COUNT - 2; 72 | 73 | /** 74 | * @return {Promise} 75 | */ 76 | export function getValidatorMinStake() { 77 | return minterNode.apiInstance.get('candidates') 78 | .then((response) => { 79 | const list = response.data.candidates 80 | .sort((a, b) => b.total_stake - a.total_stake); 81 | 82 | if (list.length <= LAST_VALIDATOR_NUMBER) { 83 | return 0; 84 | } 85 | // -2 to declare two our new validators 86 | const validator = list[LAST_VALIDATOR_NUMBER - 1]; 87 | 88 | return Math.ceil(validator.total_stake * 10 ** -18) + 1; 89 | }); 90 | } 91 | 92 | export function logError(error) { 93 | const cleanError = new Error(error.message); 94 | let axiosRequest; 95 | if (error.config) { 96 | axiosRequest = { 97 | fullUrl: error.config.baseURL + error.config.url, 98 | method: error.config.method, 99 | data: error.config.data, 100 | }; 101 | } 102 | console.log(cleanError); 103 | console.log(error?.response?.data ? {data: error.response.data, errorData: error.response.data.error?.data, axiosRequest} : error); 104 | } 105 | 106 | /** 107 | * Promisify setTimeout 108 | * @param {number} time - milliseconds 109 | * @return {Promise} 110 | */ 111 | export function wait(time) { 112 | return new Promise((resolve) => { 113 | setTimeout(resolve, time); 114 | }); 115 | } 116 | -------------------------------------------------------------------------------- /test/tx-data/candidacy-declare.test.js: -------------------------------------------------------------------------------- 1 | import {DeclareCandidacyTxData} from '~/src'; 2 | 3 | describe('DeclareCandidacyTxData', () => { 4 | const txParamsData = { 5 | address: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 6 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 7 | commission: '10', 8 | coin: '0', 9 | stake: '100', 10 | }; 11 | const txData = new DeclareCandidacyTxData(txParamsData).serialize(); 12 | 13 | test('.fromRlp', () => { 14 | const params = DeclareCandidacyTxData.fromRlp(txData).fields; 15 | expect(params) 16 | .toEqual(txParamsData); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/tx-data/candidate-edit-commission.test.js: -------------------------------------------------------------------------------- 1 | import {EditCandidateCommissionTxData} from '~/src'; 2 | 3 | describe('EditCandidateCommissionTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | commission: '10', 7 | }; 8 | const txData = new EditCandidateCommissionTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = EditCandidateCommissionTxData.fromRlp(txData).fields; 12 | expect(params) 13 | .toEqual(txParamsData); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/tx-data/candidate-edit-public-key.test.js: -------------------------------------------------------------------------------- 1 | import {EditCandidatePublicKeyTxData} from '~/src'; 2 | 3 | describe('EditCandidatePublicKeyTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | newPublicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a4', 7 | }; 8 | const txData = new EditCandidatePublicKeyTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = EditCandidatePublicKeyTxData.fromRlp(txData).fields; 12 | expect(params) 13 | .toEqual(txParamsData); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/tx-data/candidate-edit.test.js: -------------------------------------------------------------------------------- 1 | import {EditCandidateTxData} from '~/src'; 2 | 3 | describe('EditCandidateTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | rewardAddress: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 7 | ownerAddress: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 8 | controlAddress: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 9 | }; 10 | const txData = new EditCandidateTxData(txParamsData).serialize(); 11 | 12 | test('.fromRlp', () => { 13 | const params = EditCandidateTxData.fromRlp(txData).fields; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/tx-data/candidate-set-off.test.js: -------------------------------------------------------------------------------- 1 | import {SetCandidateOffTxData} from '~/src'; 2 | 3 | describe('SetCandidateOffTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | }; 7 | const txData = new SetCandidateOffTxData(txParamsData).serialize(); 8 | 9 | test('.fromRlp', () => { 10 | const params = SetCandidateOffTxData.fromRlp(txData).fields; 11 | expect(params) 12 | .toEqual(txParamsData); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/tx-data/candidate-set-on.test.js: -------------------------------------------------------------------------------- 1 | import {SetCandidateOnTxData} from '~/src'; 2 | 3 | describe('SetCandidateOnTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | }; 7 | const txData = new SetCandidateOnTxData(txParamsData).serialize(); 8 | 9 | test('.fromRlp', () => { 10 | const params = SetCandidateOnTxData.fromRlp(txData).fields; 11 | expect(params) 12 | .toEqual(txParamsData); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/tx-data/convert-buy.test.js: -------------------------------------------------------------------------------- 1 | import {BuyTxData} from '~/src'; 2 | import {clearData} from '~/test/test-utils.js'; 3 | 4 | describe('BuyTxData', () => { 5 | const txParamsData = { 6 | coinToSell: '0', 7 | coinToBuy: '1', 8 | valueToBuy: '20', 9 | }; 10 | const txData = new BuyTxData(txParamsData).serialize(); 11 | 12 | test('.fromRlp', () => { 13 | const params = BuyTxData.fromRlp(txData).fields; 14 | delete params.maximumValueToSell; 15 | expect(params) 16 | .toEqual(txParamsData); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/tx-data/convert-sell-all.test.js: -------------------------------------------------------------------------------- 1 | import {SellAllTxData} from '~/src'; 2 | 3 | describe('SellAllTxData', () => { 4 | const txParamsData = { 5 | coinToSell: '0', 6 | coinToBuy: '1', 7 | }; 8 | const txData = new SellAllTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = SellAllTxData.fromRlp(txData).fields; 12 | delete params.minimumValueToBuy; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-data/convert-sell.test.js: -------------------------------------------------------------------------------- 1 | import {SellTxData} from '~/src'; 2 | 3 | describe('SellTxData', () => { 4 | const txParamsData = { 5 | coinToSell: '0', 6 | coinToBuy: '1', 7 | valueToSell: '20', 8 | }; 9 | const txData = new SellTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = SellTxData.fromRlp(txData).fields; 13 | delete params.minimumValueToBuy; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/tx-data/create-coin.test.js: -------------------------------------------------------------------------------- 1 | import {CreateCoinTxData} from '~/src'; 2 | 3 | describe('CreateCoinTxData', () => { 4 | const txParamsData = { 5 | name: 'My Coin', 6 | symbol: 'MYCOIN', 7 | initialAmount: '5', 8 | constantReserveRatio: '10', 9 | initialReserve: '20', 10 | maxSupply: '1000000000000000', 11 | 12 | }; 13 | const txData = new CreateCoinTxData(txParamsData).serialize(); 14 | 15 | test('.fromRlp', () => { 16 | const params = CreateCoinTxData.fromRlp(txData).fields; 17 | expect(params) 18 | .toEqual(txParamsData); 19 | }); 20 | 21 | test('empty name', () => { 22 | expect(new CreateCoinTxData({...txParamsData, name: undefined}).serialize()) 23 | .toEqual(new CreateCoinTxData({...txParamsData, name: ''}).serialize()); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/create-multisig.test.js: -------------------------------------------------------------------------------- 1 | import {CreateMultisigTxData} from '~/src'; 2 | 3 | describe('CreateMultisigTxData', () => { 4 | const txParamsData = { 5 | addresses: ['Mxee81347211c72524338f9680072af90744333146', 'Mxee81347211c72524338f9680072af90744333145', 'Mxee81347211c72524338f9680072af90744333144'], 6 | weights: ['1', '3', '5'], 7 | threshold: '7', 8 | }; 9 | const txData = new CreateMultisigTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = CreateMultisigTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-data/edit-multisig.test.js: -------------------------------------------------------------------------------- 1 | import {EditMultisigTxData} from '~/src'; 2 | 3 | describe('EditMultisigTxData', () => { 4 | const txParamsData = { 5 | addresses: ['Mxee81347211c72524338f9680072af90744333144', 'Mxee81347211c72524338f9680072af90744333145', 'Mxee81347211c72524338f9680072af90744333146'], 6 | weights: ['5', '3', '1'], 7 | threshold: '7', 8 | }; 9 | const txData = new EditMultisigTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = EditMultisigTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | 17 | test('is sorted', () => { 18 | const data1 = new EditMultisigTxData({ 19 | addresses: ['Mx1111111111111111111111111111111111111111', 'Mx2222222222222222222222222222222222222222'], 20 | weights: ['1', '3'], 21 | threshold: '7', 22 | }).serializeToString(); 23 | const data2 = new EditMultisigTxData({ 24 | addresses: ['Mx2222222222222222222222222222222222222222', 'Mx1111111111111111111111111111111111111111'], 25 | weights: ['3', '1'], 26 | threshold: '7', 27 | }).serializeToString(); 28 | 29 | expect(data1).toEqual(data2); 30 | }); 31 | 32 | test('same as minterjs-tx', () => { 33 | expect(new EditMultisigTxData({ 34 | addresses: ['Mxee81347211c72524338f9680072af90744333144', 'Mxee81347211c72524338f9680072af90744333145', 'Mxee81347211c72524338f9680072af90744333146'], 35 | weights: [5, 3, 1], 36 | threshold: 1023, 37 | }).serialize()) 38 | .toEqual(Buffer.from([248, 72, 130, 3, 255, 195, 5, 3, 1, 248, 63, 148, 238, 129, 52, 114, 17, 199, 37, 36, 51, 143, 150, 128, 7, 42, 249, 7, 68, 51, 49, 68, 148, 238, 129, 52, 114, 17, 199, 37, 36, 51, 143, 150, 128, 7, 42, 249, 7, 68, 51, 49, 69, 148, 238, 129, 52, 114, 17, 199, 37, 36, 51, 143, 150, 128, 7, 42, 249, 7, 68, 51, 49, 70])); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/tx-data/edit-ticker-owner.test.js: -------------------------------------------------------------------------------- 1 | import {EditTickerOwnerTxData} from '~/src'; 2 | 3 | describe('RecreateCoinTxData', () => { 4 | const txParamsData = { 5 | symbol: 'MYCOIN', 6 | newOwner: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 7 | 8 | }; 9 | const txData = new EditTickerOwnerTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = EditTickerOwnerTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-data/index.test.js: -------------------------------------------------------------------------------- 1 | import {TX_TYPE} from 'minterjs-util'; 2 | import {getTxData} from '~/src'; 3 | 4 | describe('getTxData', () => { 5 | test.each(Object.values(TX_TYPE))('getTxData %s', (txType) => { 6 | // console.log(tx); 7 | expect(typeof getTxData(txType)).toBe('function'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/tx-data/limit-order-add.test.js: -------------------------------------------------------------------------------- 1 | import {AddLimitOrderTxData} from '~/src'; 2 | 3 | describe('AddLimitOrderTxData', () => { 4 | const txParamsData = { 5 | coinToSell: '0', 6 | coinToBuy: '1', 7 | valueToSell: '20', 8 | valueToBuy: '20', 9 | }; 10 | const txData = new AddLimitOrderTxData(txParamsData).serialize(); 11 | 12 | test('.fromRlp', () => { 13 | const params = AddLimitOrderTxData.fromRlp(txData).fields; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/tx-data/limit-order-remove.test.js: -------------------------------------------------------------------------------- 1 | import {RemoveLimitOrderTxData} from '~/src'; 2 | 3 | describe('RemoveLimitOrderTxData', () => { 4 | const txParamsData = { 5 | id: '123456789', 6 | }; 7 | const txData = new RemoveLimitOrderTxData(txParamsData).serialize(); 8 | 9 | test('.fromRlp', () => { 10 | const params = RemoveLimitOrderTxData.fromRlp(txData).fields; 11 | expect(params) 12 | .toEqual(txParamsData); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/tx-data/lock.test.js: -------------------------------------------------------------------------------- 1 | import {LockTxData} from '~/src'; 2 | 3 | describe('LockTxData', () => { 4 | const txParamsData = { 5 | dueBlock: '123', 6 | value: '10', 7 | coin: '0', 8 | }; 9 | const txData = new LockTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = LockTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | 17 | test('should throw on invalid amount', () => { 18 | expect(() => { 19 | const data = new LockTxData({ 20 | ...txParamsData, 21 | value: '123asd', 22 | }); 23 | }).toThrow(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/multisend.test.js: -------------------------------------------------------------------------------- 1 | import {MultisendTxData} from '~/src'; 2 | 3 | describe('MultisendTxData', () => { 4 | const txParamsData = { 5 | list: [ 6 | { 7 | value: '0.1', 8 | coin: '0', 9 | to: 'Mxfe60014a6e9ac91618f5d1cab3fd58cded61ee99', 10 | }, 11 | { 12 | value: '0.2', 13 | coin: '0', 14 | to: 'Mxddab6281766ad86497741ff91b6b48fe85012e3c', 15 | }, 16 | ], 17 | }; 18 | const txData = new MultisendTxData(txParamsData).serialize(); 19 | 20 | test('.fromRlp', () => { 21 | const params = MultisendTxData.fromRlp(txData).fields; 22 | expect(params) 23 | .toEqual(txParamsData); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/pool-add-liquidity.test.js: -------------------------------------------------------------------------------- 1 | import {AddLiquidityTxData} from '~/src'; 2 | 3 | describe('AddLiquidityTxData', () => { 4 | const txParamsData = { 5 | coin0: '0', 6 | coin1: '1', 7 | volume0: '20', 8 | }; 9 | const txData = new AddLiquidityTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = AddLiquidityTxData.fromRlp(txData).fields; 13 | delete params.maximumVolume1; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/tx-data/pool-buy.test.js: -------------------------------------------------------------------------------- 1 | import {BuyPoolTxData} from '~/src'; 2 | import {clearData} from '~/test/test-utils.js'; 3 | 4 | describe('BuyPoolTxData', () => { 5 | const txParamsData = { 6 | coins: ['1', '0'], 7 | valueToBuy: '20', 8 | }; 9 | const txData = new BuyPoolTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = BuyPoolTxData.fromRlp(txData).fields; 13 | delete params.maximumValueToSell; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/tx-data/pool-create.test.js: -------------------------------------------------------------------------------- 1 | import {CreatePoolTxData} from '~/src'; 2 | 3 | describe('CreatePoolTxData', () => { 4 | const txParamsData = { 5 | coin0: '0', 6 | coin1: '1', 7 | volume0: '20', 8 | volume1: '120', 9 | }; 10 | const txData = new CreatePoolTxData(txParamsData).serialize(); 11 | 12 | test('.fromRlp', () => { 13 | const params = CreatePoolTxData.fromRlp(txData).fields; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | 18 | test('independent of coins order', () => { 19 | const reversedTxData = new CreatePoolTxData({ 20 | coin0: txParamsData.coin1, 21 | coin1: txParamsData.coin0, 22 | volume0: txParamsData.volume1, 23 | volume1: txParamsData.volume0, 24 | }).serialize(); 25 | 26 | expect(txData) 27 | .toEqual(reversedTxData); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/tx-data/pool-remove-liquidity.test.js: -------------------------------------------------------------------------------- 1 | import {RemoveLiquidityTxData} from '~/src'; 2 | 3 | describe('RemoveLiquidityTxData', () => { 4 | const txParamsData = { 5 | coin0: '0', 6 | coin1: '1', 7 | liquidity: '20', 8 | }; 9 | const txData = new RemoveLiquidityTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = RemoveLiquidityTxData.fromRlp(txData).fields; 13 | delete params.minimumVolume0; 14 | delete params.minimumVolume1; 15 | expect(params) 16 | .toEqual(txParamsData); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/tx-data/pool-sell-all.test.js: -------------------------------------------------------------------------------- 1 | import {SellAllPoolTxData} from '~/src'; 2 | 3 | describe('SellAllPoolTxData', () => { 4 | const txParamsData = { 5 | coins: ['0', '1'], 6 | }; 7 | const txData = new SellAllPoolTxData(txParamsData).serialize(); 8 | 9 | test('.fromRlp', () => { 10 | const params = SellAllPoolTxData.fromRlp(txData).fields; 11 | delete params.minimumValueToBuy; 12 | expect(params) 13 | .toEqual(txParamsData); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/tx-data/pool-sell.test.js: -------------------------------------------------------------------------------- 1 | import {SellPoolTxData} from '~/src'; 2 | 3 | describe('SellPoolTxData', () => { 4 | const txParamsData = { 5 | coins: ['0', '1'], 6 | valueToSell: '20', 7 | }; 8 | const txData = new SellPoolTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = SellPoolTxData.fromRlp(txData).fields; 12 | delete params.minimumValueToBuy; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-data/recreate-coin.test.js: -------------------------------------------------------------------------------- 1 | import {RecreateCoinTxData} from '~/src'; 2 | 3 | describe('RecreateCoinTxData', () => { 4 | const txParamsData = { 5 | name: 'My Coin', 6 | symbol: 'MYCOIN', 7 | initialAmount: '5', 8 | constantReserveRatio: '10', 9 | initialReserve: '20', 10 | maxSupply: '1000000000000000', 11 | 12 | }; 13 | const txData = new RecreateCoinTxData(txParamsData).serialize(); 14 | 15 | test('.fromRlp', () => { 16 | const params = RecreateCoinTxData.fromRlp(txData).fields; 17 | expect(params) 18 | .toEqual(txParamsData); 19 | }); 20 | 21 | test('empty name', () => { 22 | expect(new RecreateCoinTxData({...txParamsData, name: undefined}).serialize()) 23 | .toEqual(new RecreateCoinTxData({...txParamsData, name: ''}).serialize()); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/redeem-check.test.js: -------------------------------------------------------------------------------- 1 | import {privateToAddress} from 'ethereumjs-util/dist/account.js'; 2 | import {RedeemCheckTxData} from '~/src'; 3 | 4 | describe('RedeemCheckTxData', () => { 5 | // exercise fantasy smooth enough arrive steak demise donkey true employ jealous decide blossom bind someone 6 | const privateKey = '0x5fa3a8b186f6cc2d748ee2d8c0eb7a905a7b73de0f2c34c5e7857c3b46f187da'; 7 | const check = 'Mcf8ab3101830f423f8a4d4e5400000000000000888ac7230489e800008a4d4e5400000000000000b841f69950a210196529f47df938f7af84958cdb336daf304616c37ef8bebca324910910f046e2ff999a7f2ab564bd690c1102ab65a20e0f27b57a93854339b60837011ba00a07cbf311148a6b62c1d1b34a5e0c2b6931a0547ede8b9dfb37aedff4480622a023ac93f7173ca41499624f06dfdd58c4e65d1279ea526777c194ddb623d57027'; 8 | const proof = '0x0497ea588f0fc2bd448de76d03a74cf371269e10ac1a02765fb5fa37c29f67e0348fb3faacd3370b8809401e7d562d8943f3642ce96667188d3c344e8e5bff6d01'; 9 | const password = 'pass'; 10 | const txParamsData = {check, proof}; 11 | 12 | test('.fromRlp (proof)', () => { 13 | const txData = new RedeemCheckTxData({check, proof}).serialize(); 14 | const params = RedeemCheckTxData.fromRlp(txData).fields; 15 | 16 | expect(params) 17 | .toEqual(txParamsData); 18 | }); 19 | 20 | test('.fromRlp (password with privateKey)', () => { 21 | const txData = new RedeemCheckTxData({check}, {password, privateKey}).serialize(); 22 | const params = RedeemCheckTxData.fromRlp(txData).fields; 23 | 24 | expect(params) 25 | .toEqual(txParamsData); 26 | }); 27 | 28 | test('.fromRlp (password with address)', () => { 29 | const address = privateToAddress(Buffer.from(privateKey.substr(2), 'hex')); 30 | const txData = new RedeemCheckTxData({check}, {password, address}).serialize(); 31 | const params = RedeemCheckTxData.fromRlp(txData).fields; 32 | 33 | expect(params) 34 | .toEqual(txParamsData); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/tx-data/send.test.js: -------------------------------------------------------------------------------- 1 | import {prepareSignedTx, SendTxData} from '~/src'; 2 | 3 | describe('SendTxData', () => { 4 | const txParamsData = { 5 | to: 'Mx7633980c000139dd3bd24a3f54e06474fa941e16', 6 | value: '10', 7 | coin: '0', 8 | }; 9 | const txData = new SendTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = SendTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | 17 | test('should throw on invalid amount', () => { 18 | expect(() => { 19 | const data = new SendTxData({ 20 | ...txParamsData, 21 | value: '123asd', 22 | }); 23 | }).toThrow(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/stake-delegate.test.js: -------------------------------------------------------------------------------- 1 | import {DelegateTxData} from '~/src'; 2 | 3 | describe('DelegateTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | coin: '0', 7 | stake: '100', 8 | }; 9 | const txData = new DelegateTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = DelegateTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-data/stake-lock.test.js: -------------------------------------------------------------------------------- 1 | import {LockStakeTxData} from '~/src'; 2 | 3 | describe('LockStakeTxData', () => { 4 | const txParamsData = { 5 | }; 6 | const txData = new LockStakeTxData(txParamsData).serialize(); 7 | 8 | test('.fromRlp', () => { 9 | const params = LockStakeTxData.fromRlp(txData).fields; 10 | expect(params) 11 | .toEqual(txParamsData); 12 | }); 13 | 14 | test('work without arguments', () => { 15 | expect(new LockStakeTxData(txParamsData).serialize()) 16 | .toEqual(new LockStakeTxData().serialize()); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/tx-data/stake-move.test.js: -------------------------------------------------------------------------------- 1 | import {MoveStakeTxData} from '~/src'; 2 | 3 | describe('MoveStakeTxData', () => { 4 | const txParamsData = { 5 | from: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | to: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a4', 7 | coin: '0', 8 | stake: '100', 9 | }; 10 | const txData = new MoveStakeTxData(txParamsData).serialize(); 11 | 12 | test('.fromRlp', () => { 13 | const params = MoveStakeTxData.fromRlp(txData).fields; 14 | expect(params) 15 | .toEqual(txParamsData); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/tx-data/stake-unbond.test.js: -------------------------------------------------------------------------------- 1 | import {UnbondTxData} from '~/src'; 2 | 3 | describe('UnbondTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | coin: '0', 7 | stake: '100', 8 | }; 9 | const txData = new UnbondTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = UnbondTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-data/token-burn.test.js: -------------------------------------------------------------------------------- 1 | import {BurnTokenTxData} from '~/src'; 2 | 3 | describe('BurnTokenTxData', () => { 4 | const txParamsData = { 5 | value: '10', 6 | coin: '0', 7 | }; 8 | const txData = new BurnTokenTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = BurnTokenTxData.fromRlp(txData).fields; 12 | expect(params) 13 | .toEqual(txParamsData); 14 | }); 15 | 16 | test('should throw on invalid amount', () => { 17 | expect(() => { 18 | const data = new BurnTokenTxData({ 19 | ...txParamsData, 20 | value: '123asd', 21 | }); 22 | }).toThrow(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/tx-data/token-create.test.js: -------------------------------------------------------------------------------- 1 | import {CreateTokenTxData} from '~/src'; 2 | 3 | describe('CreateTokenTxData', () => { 4 | const txParamsData = { 5 | name: 'My Coin', 6 | symbol: 'MYCOIN', 7 | initialAmount: '5', 8 | maxSupply: '1000000000000000', 9 | mintable: true, 10 | burnable: true, 11 | 12 | }; 13 | const txData = new CreateTokenTxData(txParamsData).serialize(); 14 | 15 | test('.fromRlp', () => { 16 | const params = CreateTokenTxData.fromRlp(txData).fields; 17 | expect(params) 18 | .toEqual(txParamsData); 19 | }); 20 | 21 | test('empty name', () => { 22 | expect(new CreateTokenTxData({...txParamsData, name: undefined}).serialize()) 23 | .toEqual(new CreateTokenTxData({...txParamsData, name: ''}).serialize()); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/token-mint.test.js: -------------------------------------------------------------------------------- 1 | import {MintTokenTxData} from '~/src'; 2 | 3 | describe('MintTokenTxData', () => { 4 | const txParamsData = { 5 | value: '10', 6 | coin: '0', 7 | }; 8 | const txData = new MintTokenTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = MintTokenTxData.fromRlp(txData).fields; 12 | expect(params) 13 | .toEqual(txParamsData); 14 | }); 15 | 16 | test('should throw on invalid amount', () => { 17 | expect(() => { 18 | const data = new MintTokenTxData({ 19 | ...txParamsData, 20 | value: '123asd', 21 | }); 22 | }).toThrow(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/tx-data/token-recreate.test.js: -------------------------------------------------------------------------------- 1 | import {RecreateTokenTxData} from '~/src'; 2 | 3 | describe('RecreateTokenTxData', () => { 4 | const txParamsData = { 5 | name: 'My Coin', 6 | symbol: 'MYCOIN', 7 | initialAmount: '5', 8 | maxSupply: '1000000000000000', 9 | mintable: true, 10 | burnable: true, 11 | 12 | }; 13 | const txData = new RecreateTokenTxData(txParamsData).serialize(); 14 | 15 | test('.fromRlp', () => { 16 | const params = RecreateTokenTxData.fromRlp(txData).fields; 17 | expect(params) 18 | .toEqual(txParamsData); 19 | }); 20 | 21 | test('empty name', () => { 22 | expect(new RecreateTokenTxData({...txParamsData, name: undefined}).serialize()) 23 | .toEqual(new RecreateTokenTxData({...txParamsData, name: ''}).serialize()); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/tx-data/vote-commission.test.js: -------------------------------------------------------------------------------- 1 | import {VoteCommissionTxData} from '~/src'; 2 | 3 | describe('VoteCommissionTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | height: '123456789', 7 | coin: '0', 8 | payloadByte: '12', 9 | send: '12', 10 | buyBancor: '12', 11 | sellBancor: '12', 12 | sellAllBancor: '12', 13 | buyPoolBase: '12', 14 | sellPoolBase: '12', 15 | sellAllPoolBase: '12', 16 | buyPoolDelta: '12', 17 | sellPoolDelta: '12', 18 | sellAllPoolDelta: '12', 19 | createTicker3: '12', 20 | createTicker4: '12', 21 | createTicker5: '12', 22 | createTicker6: '12', 23 | createTicker7to10: '12', 24 | createCoin: '12', 25 | createToken: '12', 26 | recreateCoin: '12', 27 | recreateToken: '12', 28 | declareCandidacy: '12', 29 | delegate: '12', 30 | unbond: '12', 31 | redeemCheck: '12', 32 | setCandidateOn: '12', 33 | setCandidateOff: '12', 34 | createMultisig: '12', 35 | multisendBase: '12', 36 | multisendDelta: '12', 37 | editCandidate: '12', 38 | setHaltBlock: '12', 39 | editTickerOwner: '12', 40 | editMultisig: '12', 41 | // priceVote: '12', 42 | editCandidatePublicKey: '12', 43 | addLiquidity: '12', 44 | removeLiquidity: '12', 45 | editCandidateCommission: '12', 46 | burnToken: '12', 47 | mintToken: '12', 48 | voteCommission: '12', 49 | voteUpdate: '12', 50 | createSwapPool: '12', 51 | failedTx: '12', 52 | addLimitOrder: '12', 53 | removeLimitOrder: '12', 54 | moveStake: '12', 55 | lockStake: '12', 56 | lock: '12', 57 | }; 58 | const txData = new VoteCommissionTxData(txParamsData).serialize(); 59 | 60 | test('.fromRlp', () => { 61 | const params = VoteCommissionTxData.fromRlp(txData).fields; 62 | expect(params) 63 | .toEqual(txParamsData); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/tx-data/vote-halt-block.test.js: -------------------------------------------------------------------------------- 1 | import {SetHaltBlockTxData} from '~/src'; 2 | 3 | describe('VoteHaltBlockTxData', () => { 4 | const txParamsData = { 5 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 6 | height: '123456789', 7 | }; 8 | const txData = new SetHaltBlockTxData(txParamsData).serialize(); 9 | 10 | test('.fromRlp', () => { 11 | const params = SetHaltBlockTxData.fromRlp(txData).fields; 12 | expect(params) 13 | .toEqual(txParamsData); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/tx-data/vote-price.test.js: -------------------------------------------------------------------------------- 1 | import {PriceVoteTxData} from '~/src'; 2 | 3 | describe('PriceVoteTxData', () => { 4 | const txParamsData = { 5 | price: '123456789', 6 | }; 7 | const txData = new PriceVoteTxData(txParamsData).serialize(); 8 | 9 | test('.fromRlp', () => { 10 | const params = PriceVoteTxData.fromRlp(txData).fields; 11 | expect(params) 12 | .toEqual(txParamsData); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/tx-data/vote-update.test.js: -------------------------------------------------------------------------------- 1 | import {VoteUpdateTxData} from '~/src'; 2 | 3 | describe('VoteUpdateTxData', () => { 4 | const txParamsData = { 5 | version: '0.0.1', 6 | publicKey: 'Mpf9e036839a29f7fba2d5394bd489eda927ccb95acc99e506e688e4888082b3a3', 7 | height: '123456789', 8 | }; 9 | const txData = new VoteUpdateTxData(txParamsData).serialize(); 10 | 11 | test('.fromRlp', () => { 12 | const params = VoteUpdateTxData.fromRlp(txData).fields; 13 | expect(params) 14 | .toEqual(txParamsData); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tx-decorator/index.test.js: -------------------------------------------------------------------------------- 1 | test('decorateTxParams', () => { 2 | // @TODO test only src and not test builds 3 | }); 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "skipLibCheck": true, 7 | "lib": [ 8 | "ESNext", 9 | "ESNext.AsyncIterable", 10 | "DOM" 11 | ], 12 | "esModuleInterop": true, 13 | "allowJs": true, 14 | "checkJs": true, 15 | // "sourceMap": true, 16 | "strict": false, 17 | "noImplicitThis": true, 18 | "noEmit": true, 19 | "allowImportingTsExtensions": true, 20 | "resolveJsonModule": true, 21 | "baseUrl": ".", 22 | }, 23 | "include": [ 24 | "src/**/*", 25 | ], 26 | "exclude": [ 27 | "node_modules" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | resolve: { 3 | // for WebStorm 4 | alias: { 5 | '~': path.resolve(__dirname), 6 | }, 7 | }, 8 | }; --------------------------------------------------------------------------------