diff --git a/.gitmodules b/.gitmodules new file mode 100644 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "web/cashtab/xec-js"] + path = web/cashtab/xec-js + url = /home/ethan/bitcoin-abc/web/cashtab/src/xec-js diff --git a/web/cashtab/package-lock.json b/web/cashtab/package-lock.json --- a/web/cashtab/package-lock.json +++ b/web/cashtab/package-lock.json @@ -18,6 +18,7 @@ "@testing-library/user-event": "^13.5.0", "@zxing/library": "0.8.0", "antd": "^4.9.3", + "assert": "^2.0.0", "babel-jest": "^27.4.2", "babel-loader": "^8.2.3", "babel-plugin-named-asset-import": "^0.3.8", @@ -4975,6 +4976,17 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, + "node_modules/assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "dependencies": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -7939,6 +7951,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=" + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -10401,6 +10418,20 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10440,6 +10471,21 @@ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -18935,6 +18981,19 @@ "node": ">=4" } }, + "node_modules/util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -23600,6 +23659,17 @@ } } }, + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -25883,6 +25953,11 @@ "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=" + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -27672,6 +27747,14 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -27699,6 +27782,15 @@ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -33877,6 +33969,19 @@ "prepend-http": "^2.0.0" } }, + "util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/web/cashtab/package.json b/web/cashtab/package.json --- a/web/cashtab/package.json +++ b/web/cashtab/package.json @@ -13,6 +13,7 @@ "@testing-library/user-event": "^13.5.0", "@zxing/library": "0.8.0", "antd": "^4.9.3", + "assert": "^2.0.0", "babel-jest": "^27.4.2", "babel-loader": "^8.2.3", "babel-plugin-named-asset-import": "^0.3.8", diff --git a/web/cashtab/src/components/Send/Send.js b/web/cashtab/src/components/Send/Send.js --- a/web/cashtab/src/components/Send/Send.js +++ b/web/cashtab/src/components/Send/Send.js @@ -48,7 +48,6 @@ getWalletState, convertToEcashPrefix, toLegacyCash, - toLegacyCashArray, fromSmallestDenomination, } from 'utils/cashMethods'; import ApiError from 'components/Common/ApiError'; @@ -338,10 +337,6 @@ let addressAndValueArray = address.split('\n'); try { - // construct array of XEC->BCH addresses due to bch-api constraint - let cleanAddressAndValueArray = - toLegacyCashArray(addressAndValueArray); - const link = await sendXec( bchObj, wallet, @@ -349,7 +344,7 @@ currency.defaultFee, opReturnMsg, true, // indicate send mode is one to many - cleanAddressAndValueArray, + addressAndValueArray, null, null, false, // one to many tx msg can't be encrypted @@ -385,7 +380,7 @@ let cleanAddress = address.split('?')[0]; // Ensure address has bitcoincash: prefix and checksum - cleanAddress = toLegacyCash(cleanAddress); + // cleanAddress = toLegacyCash(cleanAddress); // Calculate the amount in BCH let bchValue = value; diff --git a/web/cashtab/src/hooks/useBCH.js b/web/cashtab/src/hooks/useBCH.js --- a/web/cashtab/src/hooks/useBCH.js +++ b/web/cashtab/src/hooks/useBCH.js @@ -13,11 +13,16 @@ convertToEncryptStruct, getPublicKey, parseOpReturn, + convertToEcashPrefix, } from 'utils/cashMethods'; import cashaddr from 'ecashaddrjs'; import ecies from 'ecies-lite'; import wif from 'wif'; +const XECJS = require('../xec-js'); +// @TODO: initialize this to app startup in useWallet +const xecjs = new XECJS({ restURL: 'https://rest.kingbch.com/v4' }); + export default function useBCH() { const SEND_BCH_ERRORS = { INSUFFICIENT_FUNDS: 0, @@ -1473,8 +1478,8 @@ // instance of transaction builder if (process.env.REACT_APP_NETWORK === `mainnet`) - transactionBuilder = new BCH.TransactionBuilder(); - else transactionBuilder = new BCH.TransactionBuilder('testnet'); + transactionBuilder = new xecjs.TransactionBuilder(); + else transactionBuilder = new xecjs.TransactionBuilder('testnet'); const satoshisToSend = toSmallestDenomination(value); @@ -1610,6 +1615,9 @@ REMAINDER_ADDR = wallet.Path1899.cashAddress; } + // ensure change address is always in eCash format after validation + REMAINDER_ADDR = convertToEcashPrefix(REMAINDER_ADDR); + // amount to send back to the remainder address. const remainder = originalAmount.minus(satoshisToSend).minus(txFee); @@ -1630,14 +1638,14 @@ destinationAddressAndValueArray[i].split(',')[1], ); transactionBuilder.addOutput( - BCH.Address.toCashAddress(outputAddress), + outputAddress, parseInt(toSmallestDenomination(outputValue)), ); } } else { // for one to one mode, add output w/ single address and amount to send transactionBuilder.addOutput( - BCH.Address.toCashAddress(destinationAddress), + destinationAddress, parseInt(toSmallestDenomination(value)), ); } diff --git a/web/cashtab/src/xec-js b/web/cashtab/src/xec-js new file mode 160000 --- /dev/null +++ b/web/cashtab/src/xec-js @@ -0,0 +1 @@ +Subproject commit d9097989c0520d84ce9c02a397a5dcea0b5419cb diff --git a/web/cashtab/xec-js b/web/cashtab/xec-js new file mode 160000 --- /dev/null +++ b/web/cashtab/xec-js @@ -0,0 +1 @@ +Subproject commit d9097989c0520d84ce9c02a397a5dcea0b5419cb