├── .babelrc ├── .gitignore ├── .project ├── README.md ├── index.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── api │ ├── sdk.js │ └── serializers.js ├── crypto │ └── eciesCrypto.js ├── index.js ├── model │ ├── ProgramCreateDataEncodePacked.js │ ├── ProgramEncodePacked.js │ ├── block.js │ ├── blockheader.js │ ├── coindata.js │ ├── contractdata.js │ ├── signatures.js │ ├── txs.js │ └── txsignatures.js ├── test │ ├── NAINFTTest │ │ ├── buyToken.js │ │ ├── createToken.js │ │ ├── mint.js │ │ └── sellToken.js │ ├── NAIPumpTest │ │ ├── buyToken.js │ │ ├── createToken.js │ │ └── sellToken.js │ ├── NSWAPTest │ │ ├── Asset_Asset │ │ │ ├── ReverseSwap │ │ │ │ └── swapWAssetForExactWAsset.js │ │ │ ├── addLiquidityWAssetAndWAsset.js │ │ │ ├── removeLiquidityWAssetWAsset.js │ │ │ └── swapExactWAssetForWAsset.js │ │ ├── Asset_Token │ │ │ ├── ReverseSwap │ │ │ │ ├── swapTokensForExactWAsset.js │ │ │ │ └── swapWAssetForExactTokens.js │ │ │ ├── addLiquidityWAsset.js │ │ │ ├── removeLiquidityWAsset.js │ │ │ ├── swapExactTokensForWAsset.js │ │ │ └── swapExactWAssetForTokens.js │ │ ├── Nuls_Asset │ │ │ ├── ReverseSwap │ │ │ │ ├── swapNulsForExactWAsset.js │ │ │ │ └── swapWAssetForExactNuls.js │ │ │ ├── addLiquidityNULSWAsset.js │ │ │ ├── removeLiquidityNulsWAsset.js │ │ │ ├── swapExactNulsForWAsset.js │ │ │ └── swapExactWAssetForNuls.js │ │ ├── Nuls_Token │ │ │ ├── ReverseSwap │ │ │ │ ├── swapNulsForExactTokens.js │ │ │ │ └── swapTokensForExactNuls.js │ │ │ ├── addLiquidityNuls.js │ │ │ ├── removeLiquidityNuls.js │ │ │ ├── swapExactNulsForTokens.js │ │ │ └── swapExactTokensForNuls.js │ │ ├── Token_Token │ │ │ ├── ReverseSwap │ │ │ │ └── swapTokensForExactTokens.js │ │ │ ├── addLiquidity.js │ │ │ ├── removeLiquidity.js │ │ │ └── swapExactTokensForTokens.js │ │ ├── approveTokenToRouter.js │ │ └── calcPairAddress.js │ ├── addressByPub.js │ ├── api │ │ ├── https.js │ │ └── util.js │ ├── coinTrading.js │ ├── coindata.js │ ├── contractCall.js │ ├── contractCallOfAccountTransferTest.js │ ├── contractCallOfMultyAccounts.js │ ├── contractCallOfMultyAssetsTest1.js │ ├── contractCallOfMultyAssetsTest2.js │ ├── contractCallTest.js │ ├── contractCallTest2.js │ ├── contractCreate.js │ ├── contractCreateTest.js │ ├── contractDelete.js │ ├── contractDeleteTest.js │ ├── contractNRC20TransferTest.js │ ├── createTrading.js │ ├── crossChainTransfer.js │ ├── cryptoTest.js │ ├── dataOntoChain.js │ ├── deposit.js │ ├── deserialize │ │ ├── test.js │ │ ├── testCallContractDataHex.js │ │ └── testHex.js │ ├── fee.js │ ├── flash_test.js │ ├── hash.js │ ├── importAddress.js │ ├── newAddress.js │ ├── newAgent.js │ ├── registercrosschain.js │ ├── setAlias.js │ ├── stopAgent.js │ ├── take.js │ ├── testAes.js │ ├── tradingOrder.js │ ├── tradingOrderCancel.js │ ├── transfer.js │ ├── v1Tov2.js │ ├── verifyAddress.js │ ├── verifyProgramEncodePacked.js │ └── verifySig.js └── utils │ ├── bn.js │ ├── buffer.js │ ├── bufferreader.js │ ├── bufferwriter.js │ ├── hash.js │ ├── js.js │ ├── preconditions.js │ └── utils.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ], 5 | "plugins": [] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /node_modules 3 | /lib 4 | .env -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | nuls2-js-sdk 4 | 5 | 6 | 7 | 8 | 9 | com.aptana.ide.core.unifiedBuilder 10 | 11 | 12 | 13 | 14 | 15 | com.aptana.projects.webnature 16 | 17 | 18 | 19 | 1562055552480 20 | 21 | 26 22 | 23 | org.eclipse.ui.ide.multiFilter 24 | 1.0-name-matches-false-false-node_modules 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Install 2 | ```bash 3 | $ npm i nuls-sdk-js 4 | ``` 5 | 6 | # Usage 7 | ```js 8 | const nuls = require('./index'); 9 | 10 | let chainId = 3; //链ID 1:NULS主网 2:NULS测试网 3以上其他链 11 | let passWord = ""; 12 | let prefix = "semo"; //链前缀 13 | 14 | //创建地址 15 | const newAddress = nuls.newAddress(chainId, passWord, prefix); 16 | console.log(newAddress); 17 | 18 | //导入地址 19 | const key =""; 20 | const importAddress = nuls.importByKey(chainId, key, passWord,prefix); 21 | console.log(importAddress); 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/index.js'); 2 | 3 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | process.env.CHROME_BIN = "chromium-browser"; 2 | 3 | module.exports = function(config) { 4 | config.set({ 5 | 6 | // base path that will be used to resolve all patterns (eg. files, exclude) 7 | basePath: "./src/test/", 8 | 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ["mocha", "browserify"], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | "cryptoTest.js" 18 | ], 19 | 20 | 21 | // preprocess matching files before serving them to the browser 22 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 23 | preprocessors: { 24 | "cryptoTest.js": ["browserify"], 25 | }, 26 | 27 | 28 | // list of files to exclude 29 | exclude: [ 30 | ], 31 | 32 | 33 | // test results reporter to use 34 | // possible values: "dots", "progress" 35 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 36 | reporters: ["mocha"], 37 | 38 | 39 | // web server port 40 | port: 9879, 41 | 42 | 43 | // enable / disable colors in the output (reporters and logs) 44 | colors: true, 45 | 46 | 47 | // level of logging 48 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 49 | logLevel: config.LOG_DEBUG, 50 | 51 | 52 | // enable / disable watching file and executing tests whenever any file changes 53 | autoWatch: true, 54 | 55 | 56 | // start these browsers 57 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 58 | browsers: ["Chromium"], 59 | customLaunchers: { 60 | Chromium: { 61 | base: "Chrome", 62 | flags: ["--no-sandbox"], 63 | }, 64 | }, 65 | 66 | 67 | 68 | // Continuous Integration mode 69 | // if true, Karma captures browsers, runs the tests and exits 70 | singleRun: true, 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuls-sdk-js", 3 | "version": "2.5.0", 4 | "description": "nuls nuls-js nuls-sdk nuls-js-sdk", 5 | "main": "index.js", 6 | "files": [ 7 | "lib", 8 | "src" 9 | ], 10 | "scripts": { 11 | "cleanLib": "./node_modules/.bin/rimraf lib", 12 | "bableBuild": "./node_modules/.bin/babel src --out-dir lib", 13 | "prepublish": "npm run cleanLib && npm run bableBuild", 14 | "test": "node ./src/test" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/nuls-io/nuls-v2-js-sdk" 19 | }, 20 | "keywords": [ 21 | "nuls", 22 | "nuls-js", 23 | "nuls-sdk" 24 | ], 25 | "devDependencies": { 26 | "buffer-equal": "^1.0.0", 27 | "chai": "*", 28 | "jshint": "^2.9.6", 29 | "karma": "*", 30 | "karma-browserify": "^5.3.0", 31 | "karma-chrome-launcher": "^2.2.0", 32 | "karma-cli": "^1.0.1", 33 | "karma-firefox-launcher": "^1.1.0", 34 | "karma-mocha": "^1.3.0", 35 | "karma-mocha-reporter": "^2.2.5", 36 | "mocha": "*", 37 | "watchify": "^3.11.0", 38 | "dotenv": "^16.4.1" 39 | }, 40 | "dependencies": { 41 | "acorn": "6.4.1", 42 | "axios": "^0.18.1", 43 | "babel-cli": "^6.26.0", 44 | "babel-plugin-transform-runtime": "^6.23.0", 45 | "babel-preset-es2015": "^6.24.1", 46 | "babel-preset-stage-2": "^6.24.1", 47 | "bignumber.js": "^9.0.0", 48 | "bitcore-lib": "^0.16.0", 49 | "bitcore-mnemonic": "^1.0.1", 50 | "browserify": "16.2.3", 51 | "bs58": "4.0.1", 52 | "buffer": "^5.2.1", 53 | "buffer-from": "^1.1.1", 54 | "crypto-js": "3.1.9-1", 55 | "ecurve": "1.0.6", 56 | "elliptic": "6.5.3", 57 | "es6-promise": "3.0.2", 58 | "jsrsasign": "8.0.19", 59 | "keccak": "^3.0.4", 60 | "nan": "2.11.1", 61 | "randombytes": "2.0.6", 62 | "rimraf": "^2.6.3", 63 | "sha256": "^0.2.0" 64 | }, 65 | "optionalDependencies": { 66 | "secp256k1": "3.7.1" 67 | }, 68 | "author": "NULS team", 69 | "license": "ISC", 70 | "bugs": { 71 | "url": "https://github.com/nuls-io/nuls-v2-js-sdk" 72 | }, 73 | "homepage": "https://github.com/nuls-io/nuls-v2-js-sdk" 74 | } 75 | -------------------------------------------------------------------------------- /src/api/serializers.js: -------------------------------------------------------------------------------- 1 | const BufferWriter = require("../utils/bufferwriter"); 2 | const BN = require("../utils/bn"); 3 | let BigInteger = require("bigi"); 4 | 5 | /** 6 | * 交易序列化 7 | * @param bufWriter 8 | * @constructor 9 | */ 10 | let Serializers = function (bufWriter) { 11 | if (!bufWriter) { 12 | bufWriter = new BufferWriter(); 13 | } 14 | 15 | this.writeString = function (value) { 16 | if (!value || value.length === 0) { 17 | bufWriter.write(Buffer.from([0x00])); 18 | return; 19 | } 20 | let buf = Buffer.from(value, "UTF-8"); 21 | bufWriter.writeVarintNum(buf.length); 22 | bufWriter.write(buf); 23 | }; 24 | 25 | this.writeBytesWithLength = function (value) { 26 | if (!value || value.length === 0) { 27 | bufWriter.write(Buffer.from([0x00])); 28 | return; 29 | } 30 | bufWriter.writeVarintNum(value.length); 31 | bufWriter.write(value); 32 | }; 33 | 34 | this.writeBoolean = function (value) { 35 | if (value) { 36 | bufWriter.writeUInt8(1); 37 | } else { 38 | bufWriter.writeUInt8(0); 39 | } 40 | }; 41 | 42 | this.getBufWriter = function () { 43 | return bufWriter; 44 | }; 45 | 46 | this.writeUInt64LE = function (value) { 47 | bufWriter.writeUInt64LEBN(new BN(value)); 48 | }; 49 | 50 | this.writeBigInt = function (value) { 51 | let bigInt = BigInteger('' + value); 52 | let buf = bigInt.toByteArray(); 53 | if (buf.length > 32) { 54 | throw "data error!"; 55 | } 56 | buf = buf.reverse(); 57 | let arr2 = new Buffer(32); 58 | for (let i = 0; i < buf.length; i++) { 59 | arr2[i] = buf[i]; 60 | } 61 | bufWriter.write(arr2); 62 | }; 63 | this.writeDouble = function (value) { 64 | let buffer = new ArrayBuffer(8); // 初始化6个Byte的二进制数据缓冲区 65 | let dataView = new DataView(buffer); 66 | dataView.setFloat64(0, value, true); 67 | let buf = Buffer.alloc(8); 68 | let view = new Uint8Array(buffer); 69 | for (let i = 0; i < 8; i++) { 70 | buf[i] = view[i]; 71 | } 72 | bufWriter.write(buf); 73 | }; 74 | }; 75 | 76 | module.exports = Serializers; 77 | -------------------------------------------------------------------------------- /src/crypto/eciesCrypto.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var EC = require("elliptic").ec; 4 | 5 | var ec = new EC("secp256k1"); 6 | var browserCrypto = global.crypto || global.msCrypto || {}; 7 | var subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; 8 | 9 | var nodeCrypto = require('crypto'); 10 | 11 | var promise = typeof Promise === "undefined" ? 12 | require("es6-promise").Promise : 13 | Promise; 14 | 15 | var iv = Buffer.from("00000000000000000000000000000000", "hex"); 16 | 17 | const EC_GROUP_ORDER = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex'); 18 | const ZERO32 = Buffer.alloc(32, 0); 19 | 20 | function assert(condition, message) { 21 | if (!condition) { 22 | throw new Error(message || "Assertion failed"); 23 | } 24 | } 25 | 26 | function isScalar(x) { 27 | return Buffer.isBuffer(x) && x.length === 32; 28 | } 29 | 30 | function isValidPrivateKey(privateKey) { 31 | if (!isScalar(privateKey)) { 32 | return false; 33 | } 34 | return privateKey.compare(ZERO32) > 0 && // > 0 35 | privateKey.compare(EC_GROUP_ORDER) < 0; // < G 36 | } 37 | 38 | // Compare two buffers in constant time to prevent timing attacks. 39 | function equalConstTime(b1, b2) { 40 | if (b1.length !== b2.length) { 41 | return false; 42 | } 43 | var res = 0; 44 | for (var i = 0; i < b1.length; i++) { 45 | res |= b1[i] ^ b2[i]; // jshint ignore:line 46 | } 47 | return res === 0; 48 | } 49 | 50 | /* This must check if we're in the browser or 51 | not, since the functions are different and does 52 | not convert using browserify */ 53 | function randomBytes(size) { 54 | var arr = new Uint8Array(size); 55 | if (typeof window === 'undefined') { 56 | return Buffer.from(nodeCrypto.randomBytes(size)); 57 | } else { 58 | browserCrypto.getRandomValues(arr); 59 | } 60 | return Buffer.from(arr); 61 | } 62 | 63 | function sha512(msg) { 64 | return new promise(function (resolve) { 65 | var hash = nodeCrypto.createHash('sha512'); 66 | var result = hash.update(msg).digest(); 67 | resolve(new Uint8Array(result)); 68 | }); 69 | }; 70 | 71 | function getAes(op) { 72 | return function (iv, key, data) { 73 | return new promise(function (resolve) { 74 | if (subtle) { 75 | // console.info("dao aes subtle"); 76 | var importAlgorithm = {name: "AES-CBC"}; 77 | var keyp = subtle.importKey("raw", key, importAlgorithm, false, [op]); 78 | return keyp.then(function (cryptoKey) { 79 | var encAlgorithm = {name: "AES-CBC", iv: iv}; 80 | return subtle[op](encAlgorithm, cryptoKey, data); 81 | }).then(function (result) { 82 | resolve(Buffer.from(new Uint8Array(result))); 83 | }); 84 | } else { 85 | if (op === 'encrypt') { 86 | var cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv); 87 | cipher.update(data); 88 | resolve(cipher.final()); 89 | } else if (op === 'decrypt') { 90 | var decipher = nodeCrypto.createDecipheriv('aes-256-cbc', key, iv); 91 | decipher.update(data); 92 | resolve(decipher.final()); 93 | } 94 | } 95 | }); 96 | }; 97 | } 98 | 99 | var aesCbcEncrypt = getAes("encrypt"); 100 | var aesCbcDecrypt = getAes("decrypt"); 101 | 102 | function hmacSha256Sign(key, msg) { 103 | return new promise(function (resolve) { 104 | var hmac = nodeCrypto.createHmac('sha256', Buffer.from(key)); 105 | hmac.update(msg); 106 | var result = hmac.digest(); 107 | resolve(result); 108 | }); 109 | }; 110 | 111 | function hmacSha256Verify(key, msg, sig) { 112 | return new promise(function (resolve) { 113 | var hmac = nodeCrypto.createHmac('sha256', Buffer.from(key)); 114 | hmac.update(msg); 115 | var expectedSig = hmac.digest(); 116 | resolve(equalConstTime(expectedSig, sig)); 117 | }); 118 | } 119 | 120 | /** 121 | * Generate a new valid private key. Will use the window.crypto or window.msCrypto as source 122 | * depending on your browser. 123 | * @return {Buffer} A 32-byte private key. 124 | * @function 125 | */ 126 | exports.generatePrivate = function () { 127 | var privateKey = randomBytes(32); 128 | while (!isValidPrivateKey(privateKey)) { 129 | privateKey = randomBytes(32); 130 | } 131 | return privateKey; 132 | }; 133 | 134 | var getPublic = exports.getPublic = function (privateKey) { 135 | // This function has sync API so we throw an error immediately. 136 | assert(privateKey.length === 32, "Bad private key"); 137 | assert(isValidPrivateKey(privateKey), "Bad private key"); 138 | // XXX(Kagami): `elliptic.utils.encode` returns array for every 139 | // encoding except `hex`. 140 | return Buffer.from(ec.keyFromPrivate(privateKey).getPublic("arr")); 141 | }; 142 | 143 | /** 144 | * Get compressed version of public key. 145 | */ 146 | var getPublicCompressed = exports.getPublicCompressed = function (privateKey) { // jshint ignore:line 147 | assert(privateKey.length === 32, "Bad private key"); 148 | assert(isValidPrivateKey(privateKey), "Bad private key"); 149 | // See https://github.com/wanderer/secp256k1-node/issues/46 150 | let compressed = true; 151 | return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(compressed, "arr")); 152 | }; 153 | 154 | // NOTE(Kagami): We don't use promise shim in Browser implementation 155 | // because it's supported natively in new browsers (see 156 | // ) and we can use only new browsers 157 | // because of the WebCryptoAPI (see 158 | // ). 159 | exports.sign = function (privateKey, msg) { 160 | return new promise(function (resolve) { 161 | assert(privateKey.length === 32, "Bad private key"); 162 | assert(isValidPrivateKey(privateKey), "Bad private key"); 163 | assert(msg.length > 0, "Message should not be empty"); 164 | assert(msg.length <= 32, "Message is too long"); 165 | resolve(Buffer.from(ec.sign(msg, privateKey, {canonical: true}).toDER())); 166 | }); 167 | }; 168 | 169 | exports.verify = function (publicKey, msg, sig) { 170 | return new promise(function (resolve, reject) { 171 | assert(publicKey.length === 65 || publicKey.length === 33, "Bad public key"); 172 | if (publicKey.length === 65) { 173 | assert(publicKey[0] === 4, "Bad public key"); 174 | } 175 | if (publicKey.length === 33) { 176 | assert(publicKey[0] === 2 || publicKey[0] === 3, "Bad public key"); 177 | } 178 | assert(msg.length > 0, "Message should not be empty"); 179 | assert(msg.length <= 32, "Message is too long"); 180 | if (ec.verify(msg, sig, publicKey)) { 181 | resolve(null); 182 | } else { 183 | reject(new Error("Bad signature")); 184 | } 185 | }); 186 | }; 187 | 188 | var derive = function (privateKeyA, publicKeyB) { 189 | return new promise(function (resolve) { 190 | assert(Buffer.isBuffer(privateKeyA), "Bad private key"); 191 | assert(Buffer.isBuffer(publicKeyB), "Bad public key"); 192 | assert(privateKeyA.length === 32, "Bad private key"); 193 | assert(isValidPrivateKey(privateKeyA), "Bad private key"); 194 | assert(publicKeyB.length === 65 || publicKeyB.length === 33, "Bad public key"); 195 | if (publicKeyB.length === 65) { 196 | assert(publicKeyB[0] === 4, "Bad public key"); 197 | } 198 | if (publicKeyB.length === 33) { 199 | assert(publicKeyB[0] === 2 || publicKeyB[0] === 3, "Bad public key"); 200 | } 201 | var keyA = ec.keyFromPrivate(privateKeyA); 202 | var keyB = ec.keyFromPublic(publicKeyB); 203 | var Px = keyA.derive(keyB.getPublic()); // BN instance 204 | resolve(Buffer.from(Px.toArray())); 205 | }); 206 | }; 207 | 208 | exports.encrypt = async function (publicKeyTo, msg) { 209 | assert(subtle, "WebCryptoAPI is not available"); 210 | let ephemPrivateKey = randomBytes(32); 211 | while (!isValidPrivateKey(ephemPrivateKey)) { 212 | ephemPrivateKey = randomBytes(32); 213 | } 214 | let ephemPublicKey = getPublic(ephemPrivateKey); 215 | let Px = await derive(ephemPrivateKey, publicKeyTo); 216 | let hash = await sha512(Px); 217 | let encryptionKey = hash.slice(0, 32); 218 | let macKey = hash.slice(32); 219 | let ciphertext = await aesCbcEncrypt(iv, encryptionKey, msg); 220 | let dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]); 221 | let mac = await hmacSha256Sign(macKey, dataToMac); 222 | return Buffer.concat([ephemPublicKey, iv, ciphertext, mac]); 223 | }; 224 | 225 | exports.decrypt = async function (privateKey, encrypted) { 226 | assert(subtle, "WebCryptoAPI is not available"); 227 | let metaLength = 1 + 64 + 16 + 32; 228 | assert(encrypted.length > metaLength, "Invalid Ciphertext. Data is too small"); 229 | assert(encrypted[0] >= 2 && encrypted[0] <= 4, "Not valid ciphertext."); 230 | // deserialise 231 | let ephemPublicKey = encrypted.slice(0, 65); 232 | let cipherTextLength = encrypted.length - metaLength; 233 | let iv = encrypted.slice(65, 65 + 16); 234 | let ciphertext = encrypted.slice(65 + 16, 65 + 16 + cipherTextLength); 235 | let msgMac = encrypted.slice(65 + 16 + cipherTextLength); 236 | let Px = await derive(privateKey, ephemPublicKey); 237 | let hash = await sha512(Px); 238 | let encryptionKey = hash.slice(0, 32); 239 | let macKey = hash.slice(32); 240 | let dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]); 241 | let macGood = await hmacSha256Verify(macKey, dataToMac, msgMac); 242 | assert(macGood, "Bad MAC"); 243 | let msg = await aesCbcDecrypt(iv, encryptionKey, ciphertext); 244 | return Buffer.from(new Uint8Array(msg)); 245 | }; 246 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const sdk = require('./api/sdk'); 2 | const txs = require('./model/txs'); 3 | const crypto = require("./crypto/eciesCrypto"); 4 | const CoinData = require("./model/coindata"); 5 | const ContractData = require("./model/contractdata"); 6 | const BufferReader = require("./utils/bufferreader"); 7 | const TxSignatures = require("./model/signatures"); 8 | const Hash = require("./utils/hash"); 9 | 10 | module.exports = { 11 | 12 | /** 13 | * 生成地址 14 | * @param chainId 15 | * @param passWord 16 | * @param prefix 17 | * @returns {{}} 18 | */ 19 | newAddress(chainId, passWord, prefix) { 20 | let addressInfo = {"prefix": prefix}; 21 | if (passWord) { 22 | addressInfo = sdk.newEcKey(passWord); 23 | addressInfo.aesPri = sdk.encrypteByAES(addressInfo.pri, passWord); 24 | addressInfo.pri = null; 25 | } else { 26 | addressInfo = sdk.newEcKey(passWord); 27 | } 28 | addressInfo.address = sdk.getStringAddress(chainId, addressInfo.pri, addressInfo.pub, prefix); 29 | return addressInfo 30 | }, 31 | 32 | /** 33 | * 1.0与2.0的私钥或公钥生成地址是否相同 34 | * @param addressV1 35 | * @param addressV2 36 | * @returns {*} 37 | */ 38 | addressEquals(addressV1, addressV2) { 39 | return sdk.addressEquals(addressV1, addressV2); 40 | }, 41 | 42 | /** 43 | * 根据公钥获取地址 44 | * @param chainId 45 | * @param assetId 46 | * @param pub 47 | * @param prefix 48 | * @returns {*|string} 49 | */ 50 | getAddressByPub(chainId, assetId, pub, prefix) { 51 | return sdk.getStringAddressBase(chainId, assetId, '', pub, prefix); 52 | }, 53 | 54 | /** 55 | * 验证地址 56 | * @param address 57 | * @returns {*} 58 | */ 59 | verifyAddress(address) { 60 | return sdk.verifyAddress(address); 61 | }, 62 | 63 | /** 64 | * 导入地址 65 | * @param chainId 66 | * @param pri 67 | * @param passWord 68 | * @param prefix 69 | * @returns {{}} 70 | */ 71 | importByKey(chainId, pri, passWord, prefix) { 72 | let addressInfo = {}; 73 | const patrn = /^[A-Fa-f0-9]+$/; 74 | if (!patrn.exec(pri)) { //判断私钥是否为16进制 75 | return {success: false, data: 'Bad private key format'} 76 | } 77 | addressInfo.pri = pri; 78 | addressInfo.address = sdk.getStringAddress(chainId, pri, null, prefix); 79 | addressInfo.pub = sdk.getPub(pri); 80 | if (passWord) { 81 | addressInfo.aesPri = sdk.encrypteByAES(addressInfo.pri, passWord); 82 | addressInfo.pri = null; 83 | } 84 | return addressInfo 85 | }, 86 | 87 | /** 88 | * 组装交易 89 | * @param inputs 90 | * @param outputs 91 | * @param remark 92 | * @param type 93 | * @param info 94 | * @returns {Array} 95 | */ 96 | transactionAssemble(inputs, outputs, remark, type, info) { 97 | let tt = []; 98 | if (type === 2) { //转账交易 99 | tt = new txs.TransferTransaction(); 100 | } else if (type === 3) { //设置别名 101 | tt = new txs.AliasTransaction(info.fromAddress, info.alias); 102 | } else if (type === 4) { //创建节点 103 | tt = new txs.CreateAgentTransaction(info); 104 | } else if (type === 5) { //加入共识 105 | tt = new txs.DepositTransaction(info); 106 | } else if (type === 6) { //退出共识 107 | tt = new txs.WithdrawTransaction(info); 108 | } else if (type === 9) { //注销节点 109 | tt = new txs.StopAgentTransaction(info, outputs[0].lockTime - 86400 * 3); 110 | } else if (type === 11) { //注册跨链交易 111 | tt = new txs.RegisterChainAndAssetTransaction(info); 112 | } else if (type === 15) { //创建合约 113 | tt = new txs.CreateContractTransaction(info); 114 | } else if (type === 16) { //调用合约 115 | tt = new txs.CallContractTransaction(info); 116 | } else if (type === 17) { //删除合约 117 | tt = new txs.DeleteContractTransaction(info); 118 | } else if (type === 10) { //跨链转账 119 | tt = new txs.CrossChainTransaction(); 120 | } else if (type === 228) { //创建交易对 121 | tt = new txs.CoinTradingTransaction(info); 122 | } else if (type === 229) { //委托挂单 123 | tt = new txs.TradingOrderTransaction(info); 124 | } else if (type === 230) { //取消委托挂单 125 | tt = new txs.CancelTradingOrderTransaction(info); 126 | } 127 | tt.setCoinData(inputs, outputs); 128 | tt.remark = remark; 129 | return tt 130 | }, 131 | 132 | /** 133 | * 交易签名 134 | * @param pri 135 | * @param pub 136 | * @param tAssemble 137 | * @returns {boolean} 138 | */ 139 | transactionSerialize(pri, pub, tAssemble) { 140 | sdk.signatureTx(tAssemble, pri, pub); 141 | return tAssemble.txSerialize().toString('hex'); 142 | }, 143 | 144 | /** 145 | * 交易签名 146 | * @param pri 147 | * @param pub 148 | * @param txHex 149 | * @returns signed txHex 150 | */ 151 | signTxHex(pri, pub, txHex) { 152 | let tx = new txs.Transaction(); 153 | let bufferReader = new BufferReader(Buffer.from(txHex, "hex"), 0); 154 | tx.parse(bufferReader); 155 | sdk.signatureTx(tx, pri, pub); 156 | return tx.txSerialize().toString('hex'); 157 | }, 158 | 159 | /** 160 | * @disc: App签名,拼接公钥 161 | * @date: 2019-12-03 16:01 162 | * @author: Wave 163 | */ 164 | appSplicingPub: function appSplicingPub(signValue, pubHex) { 165 | return sdk.appSplicingPub(signValue, pubHex); 166 | }, 167 | 168 | /** 169 | * 交易签名 170 | * @param pri 171 | * @param tAssemble 172 | * @returns {boolean} 173 | */ 174 | transactionSignature(pri, tAssemble) { 175 | return sdk.signatureTransaction(tAssemble, pri); 176 | }, 177 | 178 | /** 179 | * 解密私钥 180 | * @param aesPri 181 | * @param password 182 | * @returns {*} 183 | */ 184 | decrypteOfAES(aesPri, password) { 185 | return sdk.decrypteOfAES(aesPri, password) 186 | }, 187 | 188 | /** 189 | * 公钥加密内容 190 | * @param pub 191 | * @param data 192 | * @returns {Promise} 193 | */ 194 | async encryptOfECIES(pub, data) { 195 | let bufferData = Buffer.from(data); 196 | let encrypted = await eccrypto.encrypt(pub, bufferData); 197 | return encrypted.toString("hex"); 198 | }, 199 | 200 | /** 201 | * 私钥解密内容 202 | * @param pri 203 | * @param encrypted 204 | * @returns {Promise} 205 | */ 206 | async decryptOfECIES(pri, encrypted) { 207 | let bufferEncrypted = Buffer.from(encrypted, "hex"); 208 | let decrypted = await eccrypto.decrypt(pri, bufferData); 209 | return decrypted.toString(); 210 | }, 211 | 212 | /** 213 | * @disc: hex 解析 214 | * @params: hex 215 | * @date: 2021-04-13 15:57 216 | * @author: Wave 217 | */ 218 | hexParsing(hex) { 219 | let tx = new txs.Transaction(); 220 | let bufferReader = new BufferReader(Buffer.from(hex, "hex"), 0); 221 | tx.parse(bufferReader); 222 | tx.hash = tx.calcHash(); 223 | const coin = new CoinData(new BufferReader(tx.coinData, 0)); 224 | const signatures = new TxSignatures(new BufferReader(tx.signatures, 0)); 225 | coin.dataReadable(); 226 | signatures.dataReadable(); 227 | tx.hash = tx.hash.toString('hex'); 228 | tx.coinData = coin; 229 | tx.txData = tx.txData.toString('hex'); 230 | tx.remark = tx.remark.toString('utf8'); 231 | tx.signatures = signatures; 232 | return tx; 233 | }, 234 | 235 | contractDataParsing(hex) { 236 | let bufferReader = new BufferReader(Buffer.from(hex, "hex"), 0); 237 | return new ContractData(bufferReader); 238 | }, 239 | 240 | programEncodePacked(args) { 241 | return sdk.newProgramEncodePacked(args); 242 | }, 243 | 244 | parseProgramEncodePacked(data) { 245 | return sdk.parseProgramEncodePacked(data); 246 | }, 247 | 248 | currentTime() { 249 | var times = new Date().valueOf(); 250 | return Number(times.toString().substr(0, times.toString().length - 3)); //交易时间 251 | }, 252 | 253 | programCreateDataEncodePacked(sender, salt, codeHash) { 254 | return sdk.newProgramCreateDataEncodePacked(sender, salt, codeHash); 255 | }, 256 | 257 | hashCode(value) { 258 | let h = 0; 259 | if (value.length > 0) { 260 | for (let i = 0; i < value.length; i++) { 261 | h = 31 * h + value.charCodeAt(i); 262 | h = h | 0; // 保持结果在32位整数范围内 263 | } 264 | } 265 | return h; 266 | }, 267 | 268 | getBytesAddress(addressStr) { 269 | return sdk.getBytesAddress(addressStr); 270 | }, 271 | 272 | getStringAddressByBytes(buf) { 273 | return sdk.getStringAddressByBytes(buf); 274 | }, 275 | 276 | sha256ripemd160(buf) { 277 | return Hash.sha256ripemd160(buf); 278 | } 279 | 280 | }; 281 | -------------------------------------------------------------------------------- /src/model/ProgramCreateDataEncodePacked.js: -------------------------------------------------------------------------------- 1 | const Serializers = require("../api/serializers"); 2 | 3 | let ProgramCreateDataEncodePacked = function () { 4 | this.hard = 255; 5 | this.sender = null; 6 | this.salt = null; 7 | this.codeHash = null; 8 | 9 | this.serialize = function () { 10 | let bw = new Serializers(); 11 | bw.getBufWriter().writeUInt8(this.hard); 12 | bw.getBufWriter().write(this.sender); 13 | bw.writeBytesWithLength(this.salt); 14 | bw.writeBytesWithLength(this.codeHash); 15 | return bw.getBufWriter().toBuffer(); 16 | }; 17 | 18 | this.parse = function (bufferReader) { 19 | this.hard = bufferReader.readUInt8(); 20 | this.sender = bufferReader.slice(23); 21 | this.salt = bufferReader.readBytesByLength(); 22 | this.codeHash = bufferReader.readBytesByLength(); 23 | }; 24 | }; 25 | 26 | module.exports = { 27 | ProgramCreateDataEncodePacked 28 | }; 29 | -------------------------------------------------------------------------------- /src/model/ProgramEncodePacked.js: -------------------------------------------------------------------------------- 1 | const Serializers = require("../api/serializers"); 2 | 3 | let ProgramEncodePacked = function () { 4 | this.argsCount = 0; 5 | this.args = null; 6 | this.serialize = function () { 7 | let bw = new Serializers(); 8 | bw.getBufWriter().writeUInt8(this.argsCount); 9 | if (this.args && this.args.length > 0) { 10 | for (let i = 0; i < this.args.length; i++) { 11 | bw.writeString(this.args[i]); 12 | } 13 | } 14 | return bw.getBufWriter().toBuffer(); 15 | }; 16 | 17 | this.parse = function (bufferReader) { 18 | this.argsCount = bufferReader.readUInt8(); 19 | this.args = []; 20 | for (let k = 0; k < this.argsCount; k++) { 21 | this.args.push(bufferReader.readBytesByLength().toString()); 22 | } 23 | }; 24 | }; 25 | 26 | module.exports = { 27 | ProgramEncodePacked 28 | }; 29 | -------------------------------------------------------------------------------- /src/model/block.js: -------------------------------------------------------------------------------- 1 | const BlockHeader = require("./blockheader") 2 | const txs = require("./txs") 3 | 4 | var Block = function (bufferReader) { 5 | this.header = new BlockHeader(bufferReader); 6 | this.txList = []; 7 | for (var i = 0; i < this.header.txCount; i++) { 8 | let tx = new txs.Transaction(); 9 | tx.parse(bufferReader); 10 | this.txList.push(tx); 11 | } 12 | } 13 | Block.prototype.printInfo = function () { 14 | console.log('header = ['); 15 | this.header.printInfo(); 16 | console.log(']'); 17 | console.log('txList = ['); 18 | for(var i=0;i0){ 20 | console.log(",") 21 | } 22 | this.txList[i].printInfo(); 23 | } 24 | console.log(']'); 25 | } 26 | 27 | module.exports = Block; -------------------------------------------------------------------------------- /src/model/blockheader.js: -------------------------------------------------------------------------------- 1 | const sdk = require("../api/sdk") 2 | 3 | var BlockHeader = function (bufferReader) { 4 | if (!bufferReader) { 5 | return; 6 | } 7 | this.preHash = bufferReader.slice(32); 8 | this.merkleHash = bufferReader.slice(32); 9 | this.createTime = bufferReader.readUInt32LE(); 10 | this.height = bufferReader.readUInt32LE(); 11 | this.txCount = bufferReader.readUInt32LE(); 12 | this.extend = bufferReader.readBytesByLength(); 13 | this.publicKey = bufferReader.readBytesByLength() 14 | this.packer = sdk.getStringAddress(1, null, this.publicKey.toString('hex')) 15 | this.signature = bufferReader.readBytesByLength(); 16 | } 17 | 18 | BlockHeader.prototype.printInfo = function () { 19 | console.log(' preHash :: ' + this.preHash.toString("hex")); 20 | console.log(' merkleHash:: ' + this.merkleHash.toString("hex")); 21 | console.log(' createTime:: ' + this.createTime + "(" + new Date(this.createTime * 1000).toLocaleString() + ")"); 22 | console.log(' height :: ' + this.height); 23 | console.log(' txCount :: ' + this.txCount); 24 | console.log(' extend :: ' + this.extend.toString("hex")); 25 | console.log(' publicKey :: ' + this.publicKey.toString('hex')) 26 | console.log(' packer :: ' + this.packer); 27 | console.log(' signature :: ' + this.signature.toString('hex')); 28 | } 29 | 30 | module.exports = BlockHeader; -------------------------------------------------------------------------------- /src/model/coindata.js: -------------------------------------------------------------------------------- 1 | const sdk = require("../api/sdk") 2 | var CoinData = function (bufferReader) { 3 | this.fromList = []; 4 | this.toList = []; 5 | var fromCount = bufferReader.readVarInt(); 6 | for (var i = 0; i < fromCount; i++) { 7 | this.fromList.push(new CoinFrom(bufferReader)); 8 | } 9 | var toCount = bufferReader.readVarInt(); 10 | for (var i = 0; i < toCount; i++) { 11 | this.toList.push(new CoinTo(bufferReader)); 12 | } 13 | }; 14 | var CoinFrom = function (bufferReader) { 15 | this.address = bufferReader.readBytesByLength(); 16 | this.assetsChainId = bufferReader.readUInt16LE(); 17 | this.assetsId = bufferReader.readUInt16LE(); 18 | this.amount = bufferReader.readBigInteger(); 19 | this.nonce = bufferReader.readBytesByLength(); 20 | this.locked = bufferReader.slice(1); 21 | }; 22 | var CoinTo = function (bufferReader) { 23 | this.address = bufferReader.readBytesByLength(); 24 | this.assetsChainId = bufferReader.readUInt16LE(); 25 | this.assetsId = bufferReader.readUInt16LE(); 26 | this.amount = bufferReader.readBigInteger(); 27 | this.lockTime = bufferReader.readUInt64LE(); 28 | }; 29 | 30 | CoinData.prototype.dataReadable = function() { 31 | for (let i = 0; i < this.fromList.length; i++) { 32 | const coinFrom = this.fromList[i]; 33 | coinFrom.address = sdk.getStringAddressByBytes(coinFrom.address); 34 | coinFrom.nonce = coinFrom.nonce.toString('hex'); 35 | coinFrom.locked = Number(coinFrom.locked.toString('hex')); 36 | } 37 | for (var i = 0; i < this.toList.length; i++) { 38 | const coinTo = this.toList[i]; 39 | coinTo.address = sdk.getStringAddressByBytes(coinTo.address); 40 | } 41 | }; 42 | 43 | CoinData.prototype.getPrintInfo = function () { 44 | var result = "{\n fromList: ["; 45 | for (var i = 0; i < this.fromList.length; i++) { 46 | if (i > 0) { 47 | result += ","; 48 | } 49 | result += this.fromList[i].getPrintInfo(); 50 | 51 | } 52 | result += "]\n"; 53 | result += " toList : ["; 54 | for (var i = 0; i < this.toList.length; i++) { 55 | if (i > 0) { 56 | result += ","; 57 | } 58 | result += this.toList[i].getPrintInfo(); 59 | } 60 | result += "]\n }"; 61 | return result; 62 | }; 63 | 64 | CoinFrom.prototype.getPrintInfo = function () { 65 | var result = "{\n"; 66 | result += " address : " + sdk.getStringAddressByBytes(this.address) + ',\n'; 67 | result += "assetsChainId : " + this.assetsChainId + '\n'; 68 | result += " assetsId : " + this.assetsId + '\n'; 69 | result += " amount : " + this.amount + '\n'; 70 | result += " nonce : " + this.nonce.toString('hex') + '\n'; 71 | result += " locked : " + this.locked + '\n'; 72 | result += " }"; 73 | return result; 74 | }; 75 | CoinTo.prototype.getPrintInfo = function () { 76 | var result = "{\n"; 77 | result += " address : " + sdk.getStringAddressByBytes(this.address) + ',\n'; 78 | result += "assetsChainId : " + this.assetsChainId + '\n'; 79 | result += " assetsId : " + this.assetsId + '\n'; 80 | result += " amount : " + this.amount + '\n'; 81 | result += " loctTime : " + this.lockTime + '\n'; 82 | result += " }"; 83 | return result; 84 | }; 85 | module.exports = CoinData; 86 | -------------------------------------------------------------------------------- /src/model/contractdata.js: -------------------------------------------------------------------------------- 1 | const sdk = require("../api/sdk") 2 | 3 | var ContractData = function (bufferReader) { 4 | this.sender = sdk.getStringAddressByBytes(bufferReader.slice(23)); 5 | this.contractAddress = sdk.getStringAddressByBytes(bufferReader.slice(23)); 6 | this.value = bufferReader.readBigInteger(); 7 | this.gasLimit = bufferReader.readUInt64LE(); 8 | this.price = bufferReader.readUInt64LE(); 9 | this.methodName = bufferReader.readBytesByLength().toString(); 10 | try { 11 | this.methodDesc = bufferReader.readBytesByLength().toString(); 12 | this.argsCount = bufferReader.readUInt8(); 13 | this.args = []; 14 | for (let i = 0; i < this.argsCount; i++) { 15 | let sizePerArg = bufferReader.readUInt8(); 16 | if (sizePerArg == 0) { 17 | this.args.push([]); 18 | } else { 19 | let perArg = []; 20 | for (let k = 0; k < sizePerArg; k++) { 21 | perArg.push(bufferReader.readBytesByLength().toString()); 22 | } 23 | this.args.push(perArg); 24 | } 25 | } 26 | } catch (e) { 27 | // console.log(e); 28 | } 29 | 30 | }; 31 | 32 | 33 | ContractData.prototype.getPrintInfo = function () { 34 | return JSON.stringify(this); 35 | }; 36 | 37 | module.exports = ContractData; 38 | -------------------------------------------------------------------------------- /src/model/signatures.js: -------------------------------------------------------------------------------- 1 | var TxSignatures = function (bufferReader) { 2 | this.list = []; 3 | while (!bufferReader.isFinished()) { 4 | this.list.push(new Item(bufferReader)); 5 | } 6 | }; 7 | var Item = function (bufferReader) { 8 | var length = bufferReader.readUInt8(); 9 | this.publicKey = bufferReader.slice(length); 10 | this.signData = bufferReader.readBytesByLength(); 11 | }; 12 | 13 | TxSignatures.prototype.dataReadable = function () { 14 | for (let i = 0; i < this.list.length; i++) { 15 | const item = this.list[i]; 16 | item.publicKey = item.publicKey.toString('hex'); 17 | item.signData = item.signData.toString('hex'); 18 | } 19 | }; 20 | 21 | TxSignatures.prototype.getPrintInfo = function () { 22 | var result = "["; 23 | for (var i = 0; i < this.list.length; i++) { 24 | if (i > 0) { 25 | result += ","; 26 | } 27 | result += this.list[i].getPrintInfo(); 28 | } 29 | result += "]"; 30 | return result; 31 | }; 32 | Item.prototype.getPrintInfo = function () { 33 | var result = "{\n"; 34 | result += " pubkey : " + this.publicKey.toString('hex') + ',\n'; 35 | result += " signData : " + this.signData.toString('hex') + '\n'; 36 | result += " }"; 37 | return result; 38 | }; 39 | 40 | module.exports = TxSignatures; 41 | -------------------------------------------------------------------------------- /src/model/txsignatures.js: -------------------------------------------------------------------------------- 1 | const Serializers = require("../api/serializers"); 2 | 3 | let P2PHKSignature = function () { 4 | this.pubkey = null; 5 | this.signData = null; 6 | }; 7 | 8 | let TransactionSignatures = function () { 9 | this.signatures = null; 10 | this.serialize = function () { 11 | let bw = new Serializers(); 12 | if (this.signatures && this.signatures.length > 0) { 13 | for (let i = 0; i < this.signatures.length; i++) { 14 | let signature = this.signatures[i]; 15 | bw.getBufWriter().writeUInt8(signature.pubkey.length); 16 | bw.getBufWriter().write(signature.pubkey); 17 | bw.writeBytesWithLength(signature.signData); 18 | } 19 | } 20 | return bw.getBufWriter().toBuffer(); 21 | }; 22 | 23 | this.parse = function (bufferReader) { 24 | this.signatures = []; 25 | while (!bufferReader.isFinished()) { 26 | let length = bufferReader.readUInt8(); 27 | let sign = new P2PHKSignature(); 28 | sign.pubkey = bufferReader.slice(length); 29 | sign.signData = bufferReader.readBytesByLength(); 30 | this.signatures.push(sign); 31 | } 32 | }; 33 | 34 | this.addSign = function (pubkey, signValue) { 35 | if (!this.signatures || this.signatures == null) { 36 | this.signatures = []; 37 | } 38 | let sign = new P2PHKSignature(); 39 | sign.pubkey = pubkey; 40 | sign.signData = signValue; 41 | this.signatures.push(sign); 42 | } 43 | }; 44 | 45 | module.exports = { 46 | TransactionSignatures, P2PHKSignature, 47 | }; 48 | -------------------------------------------------------------------------------- /src/test/NAINFTTest/buyToken.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.lrg; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = 'tNULSeBaN3fGjoJLt5bMVBMjBT9bJHkJwHL2xu'; 19 | 20 | let pid = 0; 21 | let tokenAmount = 20; 22 | let payNULS = 24000;// 支付的NULS数量 23 | // buyToken(int pid, int tokenAmount) 24 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 25 | chainId: assetChainId, 26 | sender: fromAddress, 27 | contractAddress: mainContract, 28 | value: new BigNumber(payNULS).shiftedBy(8).toFixed(), 29 | methodName: "buyToken", 30 | methodDesc: "", 31 | args: [ 32 | pid, tokenAmount 33 | ] 34 | }, 'call contract...', []); 35 | 36 | -------------------------------------------------------------------------------- /src/test/NAINFTTest/createToken.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = 'tNULSeBaN3fGjoJLt5bMVBMjBT9bJHkJwHL2xu'; 19 | 20 | const price = 600;// mint一个nft需要的nuls数量 21 | const maxTotalSupply = 100;// 发行总量 22 | const tigerMode = true;// 是否开启老虎机模式 23 | const mintEndingProgress = 6000;// mint阶段比例,万分位 24 | const swapFeeRate = 1000;// 买卖阶段手续费比例,万分位 25 | // 发布token 26 | // String uri, String extendUri, String name, String symbol, String payAsset, BigInteger price, int maxTotalSupply, 27 | // boolean tigerMode, int mintEndingProgress, int swapFeeRate 28 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 29 | chainId: assetChainId, 30 | sender: fromAddress, 31 | contractAddress: mainContract, 32 | value: new BigNumber(10).shiftedBy(8).toFixed(), // 33 | methodName: "createToken", 34 | methodDesc: "", 35 | args: [ 36 | 'uritest', 'extendUriTest', 'token1n', 'token1s', '2-1', new BigNumber(price).shiftedBy(8).toFixed(), maxTotalSupply, tigerMode, mintEndingProgress, swapFeeRate 37 | ] 38 | }, 'call contract...', []); 39 | -------------------------------------------------------------------------------- /src/test/NAINFTTest/mint.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.l24; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | 15 | // 资产链ID 16 | const assetChainId = 2; 17 | // 资产ID 18 | const assetId = 1; 19 | const mainContract = 'tNULSeBaN3fGjoJLt5bMVBMjBT9bJHkJwHL2xu'; 20 | 21 | let pid = 0; 22 | let mintAmount = 20; 23 | let mintPrice = 600;// mint一个nft需要的nuls数量 24 | // mint token 25 | // int pid, int mintAmount 26 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 27 | chainId: assetChainId, 28 | sender: fromAddress, 29 | contractAddress: mainContract, 30 | value: new BigNumber(mintPrice*mintAmount).shiftedBy(8).toFixed(), // 31 | methodName: "mint", 32 | methodDesc: "", 33 | args: [ 34 | pid, mintAmount 35 | ] 36 | }, 'call contract...', []); 37 | -------------------------------------------------------------------------------- /src/test/NAINFTTest/sellToken.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.l24; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = 'tNULSeBaN3fGjoJLt5bMVBMjBT9bJHkJwHL2xu'; 19 | 20 | let pid = 0; 21 | let tokenIds = []; 22 | for (let i=0;i<10;i++) { 23 | tokenIds.push((i + 0) + ""); 24 | } 25 | 26 | // sellToken(int pid, String[] tokenIds) 27 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 28 | chainId: assetChainId, 29 | sender: fromAddress, 30 | contractAddress: mainContract, 31 | value: '0', 32 | methodName: "sellToken", 33 | methodDesc: "", 34 | args: [ 35 | pid, tokenIds 36 | ] 37 | }, 'call contract...', []); 38 | 39 | -------------------------------------------------------------------------------- /src/test/NAIPumpTest/buyToken.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.l24; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = 'tNULSeBaN26qVMgnxi1AxS1PDfXn2Kpu6YZyud'; 19 | 20 | // 期望得到的token数量 21 | let expectAmount = new BigNumber("0").shiftedBy(8).toFixed(); 22 | // 接受的滑点损失 23 | let slippage = 0; 24 | // 支付的NULS数量 25 | let payNULS = 50; 26 | 27 | // buyToken( BigInteger expectAmount, int slippage, Address receiver) 28 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 29 | chainId: assetChainId, 30 | sender: fromAddress, 31 | contractAddress: mainContract, 32 | value: new BigNumber(payNULS).shiftedBy(8).toFixed(), 33 | methodName: "buyToken", 34 | methodDesc: "", 35 | args: [ 36 | expectAmount, slippage, '' 37 | ] 38 | }, 'call contract...', []); 39 | 40 | -------------------------------------------------------------------------------- /src/test/NAIPumpTest/createToken.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = 'tNULSeBaN11T1Y6o9xJf8empYK8acJdykYr7kR'; 19 | // 发布token时,项目方支付NULS购买token(可填0) 20 | const buyTokenPay = new BigNumber("50").shiftedBy(8).toFixed(); 21 | // 发布token 22 | // String name, String tick, String logoUri, String extendUri 23 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 24 | chainId: assetChainId, 25 | sender: fromAddress, 26 | contractAddress: mainContract, 27 | value: buyTokenPay, 28 | methodName: "createToken", 29 | methodDesc: "", 30 | args: [ 31 | 'T2_A6J2_name', 'T2_A6J2', 'uritest', 'extendUriTest' 32 | ] 33 | }, 'call contract...', []); 34 | -------------------------------------------------------------------------------- /src/test/NAIPumpTest/sellToken.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = 'tNULSeBaN26qVMgnxi1AxS1PDfXn2Kpu6YZyud'; 19 | 20 | // 要卖出的token数量 21 | const amount = new BigNumber("20000000").shiftedBy(8).toFixed(); 22 | // 期望得到的NULS数量 23 | const expectReceive = 0; 24 | // 接受的滑点损失 25 | const slippage = 0; 26 | 27 | // sellToken(BigInteger amount, BigInteger expectReceive, int slippage) 28 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 29 | chainId: assetChainId, 30 | sender: fromAddress, 31 | contractAddress: mainContract, 32 | value: '0', 33 | methodName: "sellToken", 34 | methodDesc: "", 35 | args: [ 36 | amount, expectReceive, slippage 37 | ] 38 | }, 'call contract...', []); 39 | 40 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Asset/ReverseSwap/swapWAssetForExactWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | let multyAssets = [ 21 | { 22 | value: new BigNumber("2").shiftedBy(18).toFixed(), 23 | assetChainId: 5, 24 | assetId: 74 25 | } 26 | ]; 27 | 28 | // Integer chainId, Integer assetId, Integer chainId2, Integer assetId2, BigInteger amountOut, String[] path, Address to, BigInteger deadline, Address ref 29 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 30 | chainId: assetChainId, 31 | sender: fromAddress, 32 | contractAddress: mainContract, 33 | value: 0, // 34 | methodName: "swapWAssetForExactWAsset", 35 | methodDesc: "", 36 | args: [ 37 | 5, 74, 5, 1, new BigNumber("50").shiftedBy(8).toFixed(), [process.env.wusdt, process.env.wnvt], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 38 | ] 39 | }, 'swap usdt for nvt', multyAssets); 40 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Asset/addLiquidityWAssetAndWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.lrg; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入200个USDT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("300").shiftedBy(18).toFixed(), 24 | assetChainId: 5, 25 | assetId: 74 26 | }, 27 | { 28 | value: new BigNumber("20000").shiftedBy(8).toFixed(), 29 | assetChainId: 5, 30 | assetId: 1 31 | } 32 | ]; 33 | 34 | // Integer chainId, Integer assetId, Integer chainId2, Integer assetId2, BigInteger amountTokenMin, BigInteger amountETHMin, Address to, BigInteger deadline 35 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 36 | chainId: assetChainId, 37 | sender: fromAddress, 38 | contractAddress: mainContract, 39 | value: 0, // 40 | methodName: "addLiquidityWAssetAndWAsset", 41 | methodDesc: "", 42 | args: [ 43 | 5, 74, 5, 1, 0, 0, fromAddress, nuls.currentTime() + 300 44 | ] 45 | }, 'add lp usdt(300) and nvt(20000)', multyAssets); 46 | // pair: tNULSeBaMypw3yptBpGRr35B5NETxsiFHdBfWv -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Asset/removeLiquidityWAssetWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.lrg; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // Integer chainId, Integer assetId, Integer chainId2, Integer assetId2, BigInteger liquidity, BigInteger amountTokenMin, BigInteger amountETHMin, Address to, BigInteger deadline 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "removeLiquidityWAssetWAsset", 27 | methodDesc: "", 28 | args: [ 29 | 5, 74, 5, 1, new BigNumber('12247448713915000').shiftedBy(0).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 30 | ] 31 | }, 'remove lp usdt and nvt', []); 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Asset/swapExactWAssetForWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入1个USDT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("1").shiftedBy(18).toFixed(), 24 | assetChainId: 5, 25 | assetId: 74 26 | } 27 | ]; 28 | 29 | // Integer chainId, Integer assetId, Integer chainId2, Integer assetId2, BigInteger amountOutMin, String[] path, Address to, BigInteger deadline, Address ref 30 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 31 | chainId: assetChainId, 32 | sender: fromAddress, 33 | contractAddress: mainContract, 34 | value: 0, // 35 | methodName: "swapExactWAssetForWAsset", 36 | methodDesc: "", 37 | args: [ 38 | 5, 74, 5, 1, 0, [process.env.wusdt, process.env.wnvt], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 39 | ] 40 | }, 'swap usdt for nvt', multyAssets); 41 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Token/ReverseSwap/swapTokensForExactWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // Integer chainId, Integer assetId, BigInteger amountOut, BigInteger amountInMax, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "swapTokensForExactWAsset", 27 | methodDesc: "", 28 | args: [ 29 | 5, 74, new BigNumber("1").shiftedBy(18).toFixed(), new BigNumber("70").shiftedBy(18).toFixed(), [process.env.qqq, process.env.wusdt], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap qqq for wusdt', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Token/ReverseSwap/swapWAssetForExactTokens.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | let multyAssets = [ 21 | { 22 | value: new BigNumber("2").shiftedBy(18).toFixed(), 23 | assetChainId: 5, 24 | assetId: 74 25 | } 26 | ]; 27 | 28 | // Integer chainId, Integer assetId, BigInteger amountOut, String[] path, Address to, BigInteger deadline, Address ref 29 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 30 | chainId: assetChainId, 31 | sender: fromAddress, 32 | contractAddress: mainContract, 33 | value: 0, // 34 | methodName: "swapWAssetForExactTokens", 35 | methodDesc: "", 36 | args: [ 37 | 5, 74, new BigNumber("50").shiftedBy(18).toFixed(), [process.env.wusdt, process.env.qqq], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 38 | ] 39 | }, 'swap usdt for qqq', multyAssets); 40 | // 900.000988390779549621,60000.052887738874063295 41 | // "0.752884336422843860","50.000000000000000000" 42 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Token/addLiquidityWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入200个USDT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("300").shiftedBy(18).toFixed(), 24 | assetChainId: 5, 25 | assetId: 74 26 | } 27 | ]; 28 | 29 | //Integer chainId, Integer assetId, Address token, BigInteger amountTokenDesired, BigInteger amountTokenMin, BigInteger amountETHMin, Address to, BigInteger deadline 30 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 31 | chainId: assetChainId, 32 | sender: fromAddress, 33 | contractAddress: mainContract, 34 | value: 0, // 35 | methodName: "addLiquidityWAsset", 36 | methodDesc: "", 37 | args: [ 38 | 5, 74, process.env.qqq, new BigNumber("20000").shiftedBy(18).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 39 | ] 40 | }, 'add lp usdt(300) and qqq(20000)', multyAssets); 41 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Token/removeLiquidityWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // Integer chainId, Integer assetId, Address token, BigInteger liquidity, BigInteger amountTokenMin, BigInteger amountETHMin, Address to, BigInteger deadline 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "removeLiquidityWAsset", 27 | methodDesc: "", 28 | args: [ 29 | 5, 74, process.env.qqq, new BigNumber('3348469228349534293591').shiftedBy(0).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 30 | ] 31 | }, 'remove lp usdt and qqq', []); 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Token/swapExactTokensForWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // Integer chainId, Integer assetId, BigInteger amountIn, BigInteger amountOutMin, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "swapExactTokensForWAsset", 27 | methodDesc: "", 28 | args: [ 29 | 5, 74, new BigNumber("20").shiftedBy(18).toFixed(), 0, [process.env.qqq, process.env.wusdt], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap qqq for usdt', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Asset_Token/swapExactWAssetForTokens.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入1个USDT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("0.3").shiftedBy(18).toFixed(), 24 | assetChainId: 5, 25 | assetId: 74 26 | } 27 | ]; 28 | 29 | // Integer chainId, Integer assetId, BigInteger amountOutMin, String[] path, Address to, BigInteger deadline, Address ref 30 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 31 | chainId: assetChainId, 32 | sender: fromAddress, 33 | contractAddress: mainContract, 34 | value: 0, // 35 | methodName: "swapExactWAssetForTokens", 36 | methodDesc: "", 37 | args: [ 38 | 5, 74, 0, [process.env.wusdt, process.env.qqq], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 39 | ] 40 | }, 'swap usdt for qqq', multyAssets); 41 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Asset/ReverseSwap/swapNulsForExactWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // Integer chainId, Integer assetId, BigInteger amountOut, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: new BigNumber("5").shiftedBy(8).toFixed(), // 26 | methodName: "swapNulsForExactWAsset", 27 | methodDesc: "", 28 | args: [ 29 | 5, 1, new BigNumber("5").shiftedBy(8).toFixed(), [process.env.wnuls, process.env.wnvt], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap nuls for nvt', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Asset/ReverseSwap/swapWAssetForExactNuls.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入1个NVT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("10").shiftedBy(8).toFixed(), 24 | assetChainId: 5, 25 | assetId: 1 26 | } 27 | ]; 28 | 29 | // Integer chainId, Integer assetId, BigInteger amountOut, String[] path, Address to, BigInteger deadline, Address ref 30 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 31 | chainId: assetChainId, 32 | sender: fromAddress, 33 | contractAddress: mainContract, 34 | value: 0, // 35 | methodName: "swapWAssetForExactNuls", 36 | methodDesc: "", 37 | args: [ 38 | 5, 1, new BigNumber("4").shiftedBy(8).toFixed(), [process.env.wnvt, process.env.wnuls], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 39 | ] 40 | }, 'swap nvt for nuls', multyAssets); 41 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Asset/addLiquidityNULSWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.lrg; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入100个NVT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("100").shiftedBy(8).toFixed(), 24 | assetChainId: 5, 25 | assetId: 1 26 | } 27 | ]; 28 | 29 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 30 | chainId: assetChainId, 31 | sender: fromAddress, 32 | contractAddress: mainContract, 33 | value: new BigNumber("50").shiftedBy(8).toFixed(), // 34 | methodName: "addLiquidityNULSWAsset", 35 | methodDesc: "", 36 | args: [ 37 | 5, 1, 0, 0, fromAddress, nuls.currentTime() + 300 38 | ] 39 | }, 'add lp nuls(50) and nvt(100)', multyAssets); 40 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Asset/removeLiquidityNulsWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.lrg; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 21 | chainId: assetChainId, 22 | sender: fromAddress, 23 | contractAddress: mainContract, 24 | value: 0, // 25 | methodName: "removeLiquidityNulsWAsset", 26 | methodDesc: "", 27 | args: [ 28 | 5, 1, new BigNumber('3071066811').shiftedBy(0).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 29 | ] 30 | }, 'remove lp nuls and nvt', []); 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Asset/swapExactNulsForWAsset.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.lrg; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | //Integer chainId, Integer assetId, BigInteger amountOutMin, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: new BigNumber("1").shiftedBy(8).toFixed(), // 26 | methodName: "swapExactNulsForWAsset", 27 | methodDesc: "", 28 | args: [ 29 | 5, 1, 0, [process.env.wnuls, process.env.wnvt], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap nuls for nvt', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Asset/swapExactWAssetForNuls.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // 转入1个NVT 21 | let multyAssets = [ 22 | { 23 | value: new BigNumber("1").shiftedBy(8).toFixed(), 24 | assetChainId: 5, 25 | assetId: 1 26 | } 27 | ]; 28 | 29 | // Integer chainId, Integer assetId, BigInteger amountOutMin, String[] path, Address to, BigInteger deadline, Address ref 30 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 31 | chainId: assetChainId, 32 | sender: fromAddress, 33 | contractAddress: mainContract, 34 | value: 0, // 35 | methodName: "swapExactWAssetForNuls", 36 | methodDesc: "", 37 | args: [ 38 | 5, 1, 0, [process.env.wnvt, process.env.wnuls], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 39 | ] 40 | }, 'swap nvt for nuls', multyAssets); 41 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Token/ReverseSwap/swapNulsForExactTokens.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // BigInteger amountOut, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: new BigNumber("1").shiftedBy(8).toFixed(), // 26 | methodName: "swapNulsForExactTokens", 27 | methodDesc: "", 28 | args: [ 29 | new BigNumber("5000").shiftedBy(18).toFixed(), [process.env.wnuls, process.env.fark], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap nuls for fark', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Token/ReverseSwap/swapTokensForExactNuls.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // BigInteger amountOut, BigInteger amountInMax, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "swapTokensForExactNuls", 27 | methodDesc: "", 28 | args: [ 29 | new BigNumber("1").shiftedBy(8).toFixed(), new BigNumber("2000").shiftedBy(18).toFixed(), [process.env.fark, process.env.wnuls], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap fark for nuls', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Token/addLiquidityNuls.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 21 | chainId: assetChainId, 22 | sender: fromAddress, 23 | contractAddress: mainContract, 24 | value: new BigNumber(50).shiftedBy(8).toFixed(), // 25 | methodName: "addLiquidityNuls", 26 | methodDesc: "", 27 | args: [ 28 | process.env.fark, new BigNumber(100).shiftedBy(18).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 29 | ] 30 | }, 'add lp nuls(50) and fark(100)', []); 31 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Token/removeLiquidityNuls.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 21 | chainId: assetChainId, 22 | sender: fromAddress, 23 | contractAddress: mainContract, 24 | value: 0, // 25 | methodName: "removeLiquidityNuls", 26 | methodDesc: "", 27 | args: [ 28 | process.env.fark, new BigNumber('353553390592773').shiftedBy(0).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 29 | ] 30 | }, 'remove lp nuls and fark', []); 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Token/swapExactNulsForTokens.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | async function swapNulsForFark() { 21 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: new BigNumber(100).shiftedBy(8).toFixed(), // 26 | methodName: "swapExactNulsForTokens", 27 | methodDesc: "", 28 | args: [ 29 | 0, [process.env.wnuls, process.env.fark], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap nuls(1) for fark', []); 32 | } 33 | 34 | 35 | async function swapNulsForCCC() { 36 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 37 | chainId: assetChainId, 38 | sender: fromAddress, 39 | contractAddress: mainContract, 40 | value: new BigNumber(1).shiftedBy(8).toFixed(), // 41 | methodName: "swapExactNulsForTokens", 42 | methodDesc: "", 43 | args: [ 44 | 0, [process.env.wnuls, process.env.fark, process.env.ccc], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 45 | ] 46 | }, 'swap nuls for ccc: nuls to fark to ccc', []); 47 | } 48 | 49 | swapNulsForFark(); 50 | // swapNulsForCCC(); 51 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Nuls_Token/swapExactTokensForNuls.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | async function swapFarkForNuls() { 21 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "swapExactTokensForNuls", 27 | methodDesc: "", 28 | args: [ 29 | new BigNumber(10000).shiftedBy(18).toFixed(), 0, [process.env.fark, process.env.wnuls], process.env.lrgAddr, nuls.currentTime() + 300, process.env.lrgAddr 30 | ] 31 | }, 'swap fark for nuls', []); 32 | } 33 | 34 | async function swapCCCForNuls() { 35 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 36 | chainId: assetChainId, 37 | sender: fromAddress, 38 | contractAddress: mainContract, 39 | value: 0, // 40 | methodName: "swapExactTokensForNuls", 41 | methodDesc: "", 42 | args: [ 43 | new BigNumber(1).shiftedBy(8).toFixed(), 0, [process.env.ccc, process.env.fark, process.env.wnuls], fromAddress, nuls.currentTime() + 300, process.env.burnAddr 44 | ] 45 | }, 'swap ccc for nuls: ccc to fark to nuls', []); 46 | } 47 | 48 | swapFarkForNuls(); 49 | // swapCCCForNuls(); -------------------------------------------------------------------------------- /src/test/NSWAPTest/Token_Token/ReverseSwap/swapTokensForExactTokens.js: -------------------------------------------------------------------------------- 1 | const call = require('../../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../../index"); 4 | require('dotenv').config({ path: '../../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // BigInteger amountOut, BigInteger amountInMax, String[] path, Address to, BigInteger deadline, Address ref 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "swapTokensForExactTokens", 27 | methodDesc: "", 28 | args: [ 29 | new BigNumber("0.5").shiftedBy(18).toFixed(), new BigNumber("50").shiftedBy(18).toFixed(), [process.env.fark, process.env.qqq], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 30 | ] 31 | }, 'swap fark for qqq', []); 32 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Token_Token/addLiquidity.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.xaf; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | //Address tokenA, Address tokenB, BigInteger amountADesired, BigInteger amountBDesired, BigInteger amountAMin, BigInteger amountBMin, Address to, BigInteger deadline 21 | async function addFarkAndQQQ() { 22 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 23 | chainId: assetChainId, 24 | sender: fromAddress, 25 | contractAddress: mainContract, 26 | value: 0, // 27 | methodName: "addLiquidity", 28 | methodDesc: "", 29 | args: [ 30 | process.env.fark, process.env.qqq, new BigNumber("500").shiftedBy(18).toFixed(), new BigNumber("10000").shiftedBy(18).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 31 | ] 32 | }, 'add lp fark(500) and qqq(10000)', []); 33 | } 34 | 35 | async function addFarkAndCcc() { 36 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 37 | chainId: assetChainId, 38 | sender: fromAddress, 39 | contractAddress: mainContract, 40 | value: 0, // 41 | methodName: "addLiquidity", 42 | methodDesc: "", 43 | args: [ 44 | process.env.fark, process.env.ccc, new BigNumber("50").shiftedBy(18).toFixed(), new BigNumber("100").shiftedBy(8).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 45 | ] 46 | }, 'add lp fark(50) and ccc(100)', []); 47 | } 48 | 49 | // addFarkAndQQQ(); 50 | addFarkAndCcc(); -------------------------------------------------------------------------------- /src/test/NSWAPTest/Token_Token/removeLiquidity.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // Address tokenA, Address tokenB, BigInteger liquidity, BigInteger amountAMin, BigInteger amountBMin, Address to, BigInteger deadline 21 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 22 | chainId: assetChainId, 23 | sender: fromAddress, 24 | contractAddress: mainContract, 25 | value: 0, // 26 | methodName: "removeLiquidity", 27 | methodDesc: "", 28 | args: [ 29 | process.env.fark, process.env.ccc, new BigNumber('353553390592773').shiftedBy(0).toFixed(), 0, 0, fromAddress, nuls.currentTime() + 300 30 | ] 31 | }, 'remove lp fark and ccc', []); 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/test/NSWAPTest/Token_Token/swapExactTokensForTokens.js: -------------------------------------------------------------------------------- 1 | const call = require('../../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../../index"); 4 | require('dotenv').config({ path: '../../../test/.env'}); 5 | 6 | // 用户私钥 7 | const pri = process.env.asd; 8 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 9 | // 用户公钥 10 | const pub = importAddress.pub; 11 | // 用户地址 12 | const fromAddress = importAddress.address; 13 | console.log('fromAddress', fromAddress); 14 | // 资产链ID 15 | const assetChainId = 2; 16 | // 资产ID 17 | const assetId = 1; 18 | const mainContract = process.env.router; 19 | 20 | // BigInteger amountIn, BigInteger amountOutMin, String[] path, Address to, BigInteger deadline, Address ref 21 | async function swapFarkForCCC() { 22 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 23 | chainId: assetChainId, 24 | sender: fromAddress, 25 | contractAddress: mainContract, 26 | value: 0, // 27 | methodName: "swapExactTokensForTokens", 28 | methodDesc: "", 29 | args: [ 30 | new BigNumber("1").shiftedBy(18).toFixed(), 0, [process.env.fark, process.env.ccc], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 31 | ] 32 | }, 'swap fark for ccc', []); 33 | } 34 | 35 | async function swapCCCForFark() { 36 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 37 | chainId: assetChainId, 38 | sender: fromAddress, 39 | contractAddress: mainContract, 40 | value: 0, // 41 | methodName: "swapExactTokensForTokens", 42 | methodDesc: "", 43 | args: [ 44 | new BigNumber("1").shiftedBy(8).toFixed(), 0, [process.env.ccc, process.env.fark], fromAddress, nuls.currentTime() + 300, 'tNULSeBaN5nddf9WkQgRr3RNwARgryndv2Bzs6' 45 | ] 46 | }, 'swap ccc for fark', []); 47 | } 48 | 49 | swapCCCForFark(); -------------------------------------------------------------------------------- /src/test/NSWAPTest/approveTokenToRouter.js: -------------------------------------------------------------------------------- 1 | const call = require('../contractCall.js'); 2 | const BigNumber = require("bignumber.js"); 3 | const nuls = require("../../index"); 4 | require('dotenv').config({ path: '../../test/.env'}); 5 | 6 | async function approve(pri, mainContract, to) { 7 | const importAddress = nuls.importByKey(2, pri, '', "tNULS"); 8 | // 用户公钥 9 | const pub = importAddress.pub; 10 | // 用户地址 11 | const fromAddress = importAddress.address; 12 | console.log('fromAddress', fromAddress); 13 | // 资产链ID 14 | const assetChainId = 2; 15 | // 资产ID 16 | const assetId = 1; 17 | 18 | await call.callContract(pri, pub, fromAddress, assetChainId, assetId, { 19 | chainId: assetChainId, 20 | sender: fromAddress, 21 | contractAddress: mainContract, 22 | value: 0, // 23 | methodName: "approve", 24 | methodDesc: "", 25 | args: [ 26 | to, new BigNumber(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff).toFixed() 27 | ] 28 | }, 'call contract...', []); 29 | } 30 | 31 | async function approveList() { 32 | const router = process.env.router; 33 | await approve(process.env.asd, process.env.fark, router);// FARK 34 | console.log('asd fark done.'); 35 | await approve(process.env.xaf, process.env.fark, router);// FARK 36 | console.log('xaf fark done.'); 37 | await approve(process.env.asd, process.env.ddd, router);// DDD 38 | console.log('asd ddd done.'); 39 | await approve(process.env.xaf, process.env.ddd, router);// DDD 40 | console.log('xaf ddd done.'); 41 | await approve(process.env.asd, process.env.ccc, router);// CCC 42 | console.log('asd ccc done.'); 43 | await approve(process.env.xaf, process.env.ccc, router);// CCC 44 | console.log('xaf ccc done.'); 45 | await approve(process.env.asd, process.env.qqq, router);// QQQ 46 | console.log('asd qqq done.'); 47 | await approve(process.env.xaf, process.env.qqq, router);// QQQ 48 | console.log('xaf qqq done.'); 49 | // await approve(process.env.lrg, 'tNULSeBaMxs25kpN94U9uXArQ7QCGLsmPurRqt', router);// Pair.LPAddress 50 | } 51 | 52 | approveList(); -------------------------------------------------------------------------------- /src/test/NSWAPTest/calcPairAddress.js: -------------------------------------------------------------------------------- 1 | 2 | const nuls = require("../../index"); 3 | const keccak = require('keccak'); 4 | 5 | const factory = 'tNULSeBaMzYWiaCcZPu3kD2nJ52jMzMvbNzgVn'; 6 | const pairCodeHash = '39a7640b54538bafd656a732db46decbed89389cf6207b168dda6f925d60c590'; 7 | const tokenA = 'tNULSeBaMy1Rk3KaHcvXYTGNoNpr8ckAzkKWfS'; 8 | const tokenB = 'tNULSeBaN8Ps39De43Gik5GfQ6h4GYsHGmwNcP'; 9 | 10 | const wAssetFactory = 'tNULSeBaNCULzexmzet8TbRu6uFnzZarwAX4yb'; 11 | const wAssetCodeHash = '8ecce50a65f33c0c8d7ae30d4f7c0b04608ac9825a1db7f1eb6cb7e204e3776f'; 12 | 13 | function calcDeployedAddress(chainId, sender, salt, codeHash) { 14 | const saltBuf = Buffer.from(nuls.programEncodePacked(salt), 'hex'); 15 | const createData = nuls.programCreateDataEncodePacked(nuls.getBytesAddress(sender), saltBuf, Buffer.from(codeHash, 'hex')); 16 | const hash160 = nuls.sha256ripemd160(keccak('keccak256').update(Buffer.from(createData, 'hex')).digest()); 17 | const chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]); 18 | const addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([2]), hash160]); 19 | return nuls.getStringAddressByBytes(addrBuffer); 20 | } 21 | 22 | function calcPairAddress(chainId, _tokenA, _tokenB) { 23 | 24 | // TokenA cannot be equal to TokenB 25 | if (_tokenA == _tokenB) { 26 | throw "IDENTICAL_ADDRESSES"; 27 | } 28 | // Find the correct order of the tokens 29 | let token0; 30 | let token1; 31 | if (nuls.hashCode(tokenA) < nuls.hashCode(tokenB)) { 32 | token0 = _tokenA; 33 | token1 = _tokenB; 34 | } else { 35 | token0 = _tokenB; 36 | token1 = _tokenA; 37 | } 38 | return calcDeployedAddress(chainId, factory, ['pair', token0, token1], pairCodeHash); 39 | } 40 | 41 | function calcWAssetAddress(chainId, assetChainId, assetId) { 42 | return calcDeployedAddress(chainId, wAssetFactory, ['wasset', 'w' + assetChainId, 'w' + assetId], wAssetCodeHash) 43 | } 44 | 45 | console.log(calcPairAddress(2, tokenA, tokenB)); 46 | console.log(calcWAssetAddress(2, 5, 1)); 47 | console.log(calcWAssetAddress(2, 5, 74)); -------------------------------------------------------------------------------- /src/test/addressByPub.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | 3 | /** 4 | * @disc: 根据公钥获取地址 5 | * @date: 2019-10-18 10:27 6 | * @author: Wave 7 | */ 8 | 9 | let addressInfo = { 10 | pub: '02458d425e75a95688571c4cc074289a34d27c74cd284d6be316a775b363a205c3', 11 | address: 'tNULSeBaMiv3V2KMKbkHL8ZRgQRkP6CYUG2hia', 12 | }; 13 | let address = nuls.getAddressByPub(2, 1, addressInfo.pub, 'tNULS'); 14 | console.log(address); 15 | console.log(address === addressInfo.address); 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/test/api/https.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const API_CHAIN_ID = 2; 3 | axios.defaults.timeout = 8000; 4 | // axios.defaults.baseURL = 'http://127.0.0.1:18004/api'; 5 | // axios.defaults.baseURL = 'http://localhost:18003/'; 6 | axios.defaults.baseURL = 'https://beta.public1.nuls.io/'; 7 | // axios.defaults.baseURL = 'https://beta.api.nuls.io/jsonrpc'; 8 | // axios.defaults.baseURL = 'http://127.0.0.1:18004/jsonrpc'; 9 | axios.defaults.headers.post['Content-Type'] = 'application/json'; 10 | 11 | /** 12 | * 封装post请求 13 | * Encapsulation post method 14 | * @param url 15 | * @param methodName 16 | * @param data 17 | * @returns {Promise} 18 | */ 19 | module.exports = { 20 | post(url, methodName, data = []) { 21 | return new Promise((resolve, reject) => { 22 | data.unshift(API_CHAIN_ID); 23 | const params = {"jsonrpc": "2.0", "method": methodName, "params": data, "id": 5898}; 24 | axios.post(url, params) 25 | .then(response => { 26 | resolve(response.data) 27 | }, err => { 28 | reject(err) 29 | }) 30 | }) 31 | }, 32 | 33 | postComplete(url, methodName, data = []) { 34 | return new Promise((resolve, reject) => { 35 | const params = {"jsonrpc": "2.0", "method": methodName, "params": data, "id": 5899}; 36 | axios.post(url, params) 37 | .then(response => { 38 | resolve(response.data) 39 | }, err => { 40 | reject(err) 41 | }) 42 | }) 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /src/test/coinTrading.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const sdk = require('../api/sdk') 3 | const {getBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 4 | 5 | /** 6 | * @disc: 创建交易对 dome 7 | * @params: 8 | * @date: 2019-12-9 10:38 9 | * @author: vivi 10 | */ 11 | 12 | let pri = '4100e2f88c3dba08e5000ed3e8da1ae4f1e0041b856c09d35a26fb399550f530'; 13 | let pub = '020e19418ed26700b0dba720dcc95483cb4adb1b5f8a103818dab17d5b05231854'; 14 | let fromAddress = "tNULSeBaMu38g1vnJsSZUCwTDU9GsE5TVNUtpD"; 15 | //创建交易对收款地址 16 | let toAddress = 'tNULSeBaMqywZjfSrKNQKBfuQtVxAHBQ8rB2Zn'; 17 | //创建交易对需要金额 18 | let amount = 2000000000000; 19 | let remark = 'create coinTrading....'; 20 | let txType = 28; 21 | 22 | let coinTradingInfo = { 23 | quoteAssetChainId: 2, //计价货币chainId 24 | quoteAssetId: 1, //计价货币assetId 25 | quoteMinDecimal: 5, //计价货币交易允许最小小数位 26 | quoteMinSize: 1000000, //计价货币允许最小交易量 27 | baseAssetChainId: 2, //交易货币chainId 28 | baseAssetId: 2, //交易货币assetId 29 | baseMinDecimal: 5, //交易货币交易允许最小小数位 30 | baseMinSize: 1000000, //交易货币允许最小交易量 31 | }; 32 | 33 | let transferInfo = { 34 | fromAddress: fromAddress, 35 | toAddress: toAddress, 36 | assetsChainId: 2, 37 | assetsId: 1, 38 | amount: amount, 39 | remark: remark, 40 | fee: 1000000 41 | }; 42 | 43 | //调用设置别名 44 | coinTrading(transferInfo, coinTradingInfo); 45 | 46 | /** 47 | * 设置别名 48 | * @param pri 49 | * @param pub 50 | * @param fromAddress 51 | * @param toAddress 52 | * @param assetsChainId 53 | * @param assetsId 54 | * @param amount 55 | * @param remark 56 | * @returns {Promise} 57 | */ 58 | async function coinTrading(transferInfo, coinTradingInfo) { 59 | //账户转出资产余额 60 | //console.log(transferInfo); 61 | const balanceInfo = await getBalance(transferInfo.assetsChainId, transferInfo.assetsChainId, transferInfo.assetsId, transferInfo.fromAddress); 62 | 63 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, txType); 64 | 65 | //交易组装 66 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, txType, coinTradingInfo); 67 | console.log(tAssemble); 68 | //获取hash 69 | let hash = await tAssemble.getHash(); 70 | console.log(hash); 71 | //交易签名 72 | let txSignature = await sdk.getSignData(hash.toString('hex'), pri); 73 | console.log(txSignature); 74 | //通过拼接签名、公钥获取HEX 75 | let signData = await sdk.appSplicingPub(txSignature.signValue, pub); 76 | tAssemble.signatures = signData; 77 | let txhex = tAssemble.txSerialize().toString("hex"); 78 | console.log(txhex.toString('hex')); 79 | 80 | /*let getHex = await sdk.appSplicingPub(txSignature); 81 | console.log(getHex); 82 | 83 | let txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 84 | console.log(txhex);*/ 85 | // let result = await validateTx(txhex.toString('hex')); 86 | // console.log(result); 87 | // if (result) { 88 | // console.log(result.data.value); 89 | // let results = await broadcastTx(txhex); 90 | // if (results && result.data.value) { 91 | // console.log("交易完成") 92 | // } else { 93 | // console.log("广播交易失败") 94 | // } 95 | // } else { 96 | // console.log("验证交易失败") 97 | // } 98 | } 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/test/coindata.js: -------------------------------------------------------------------------------- 1 | const tx = require('../model/txs'); 2 | let inputs = []; 3 | inputs.push({ 4 | address: 'LINcjJR16WwP7a7irS3T4p1td7QAd2MSUEqk', 5 | assetsChainId: 8, 6 | assetsId: 1, 7 | amount: 3300000000, 8 | locked: 0, 9 | nonce: '9673f2fdd28de29f' 10 | }); 11 | inputs.push({ 12 | address: 'LINcjJR16WwP7a7irS3T4p1td7QAd2MSUEqk', 13 | assetsChainId: 2, 14 | assetsId: 1, 15 | amount: 1000000, 16 | locked: 0, 17 | nonce: '9673f2fdd28de29f' 18 | }); 19 | let outputs = []; 20 | outputs.push({ 21 | address: 'tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG', 22 | assetsChainId: 8, 23 | assetsId: 1, 24 | amount: 3300000000, 25 | lockTime: 0 26 | }); 27 | let temp = new tx.CrossChainTransaction(); 28 | temp.setCoinData(inputs, outputs); 29 | console.log(temp.coinData.toString('hex')); 30 | -------------------------------------------------------------------------------- /src/test/contractCall.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const utils = require('../utils/utils'); 3 | const sdk = require('../api/sdk'); 4 | const BigNumber = require('bignumber.js'); 5 | const {getBalance, countFee, inputsOrOutputsOfContractCall, getContractMethodArgsTypes, validateContractCall, imputedContractCallGas, validateTx, broadcastTx} = require('./api/util'); 6 | 7 | module.exports = { 8 | /** 9 | * 调用合约 10 | * @param pri 11 | * @param pub 12 | * @param fromAddress 13 | * @param assetsChainId 14 | * @param assetsId 15 | * @param contractCall 16 | * @returns {Promise} 17 | */ 18 | async callContract(pri, pub, fromAddress, assetsChainId, assetsId, contractCall, remark, multyAssets, nulsValueToOthers, payAccount) { 19 | let chainId = contractCall.chainId; 20 | const balanceInfo = await getBalance(chainId, assetsChainId, assetsId, fromAddress); 21 | let contractAddress = contractCall.contractAddress; 22 | let value = Number(contractCall.value); 23 | let newValue = new BigNumber(contractCall.value); 24 | const contractCallTxData = await this.makeCallData(chainId, fromAddress, value, contractAddress, contractCall.methodName, contractCall.methodDesc, contractCall.args, multyAssets); 25 | let gasLimit = new BigNumber(contractCallTxData.gasLimit); 26 | let gasFee = Number(gasLimit.times(contractCallTxData.price)); 27 | let amount = Number(newValue.plus(gasFee)); 28 | let transferInfo = { 29 | fromAddress: fromAddress, 30 | assetsChainId: assetsChainId, 31 | assetsId: assetsId, 32 | amount: amount, 33 | fee: 200000 34 | }; 35 | if (value > 0) { 36 | transferInfo.toAddress = contractAddress; 37 | transferInfo.value = contractCall.value; 38 | } 39 | // let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 16); 40 | if (multyAssets) { 41 | let length = multyAssets.length; 42 | for (var i = 0; i < length; i++) { 43 | let multyAsset = multyAssets[i]; 44 | let _balanceInfo = await getBalance(chainId, multyAsset.assetChainId, multyAsset.assetId, fromAddress); 45 | if (_balanceInfo.balance < Number(multyAsset.value)) { 46 | throw "Your balance of " + multyAsset.assetChainId + "-" + multyAsset.assetId + " is not enough."; 47 | } 48 | multyAssets[i].nonce = _balanceInfo.nonce; 49 | } 50 | } 51 | 52 | let inOrOutputs = await inputsOrOutputsOfContractCall(transferInfo, balanceInfo, contractCall, multyAssets, nulsValueToOthers); 53 | if (!inOrOutputs.success) { 54 | throw inOrOutputs.data; 55 | } 56 | if (payAccount) { 57 | const balanceInfoOfPayAccount = await getBalance(chainId, assetsChainId, assetsId, payAccount); 58 | let inputs = inOrOutputs.data.inputs; 59 | let from = inputs[inputs.length - 1]; 60 | inputs.push({ 61 | address: from.address, 62 | assetsChainId: from.assetsChainId, 63 | assetsId: from.assetsId, 64 | amount: '0', 65 | locked: 0, 66 | nonce: from.nonce 67 | }); 68 | from.address = payAccount; 69 | from.nonce = balanceInfoOfPayAccount.nonce; 70 | } 71 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 16, contractCallTxData); 72 | let txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 73 | 74 | // console.log(txhex); 75 | if (payAccount) { 76 | console.log("请追加账户["+payAccount+"]的签名"); 77 | return; 78 | } 79 | let result = await validateTx(txhex); 80 | console.log('validateTx', result); 81 | if (result.success) { 82 | let results = await broadcastTx(txhex); 83 | if (results && results.value) { 84 | console.log("交易完成") 85 | } else { 86 | console.log("广播交易失败\n", results) 87 | } 88 | } else { 89 | console.log("验证交易失败") 90 | } 91 | }, 92 | 93 | /** 94 | * 预估调用合约的gas 95 | * @param chainId 96 | * @param sender 97 | * @param value 98 | * @param contractAddress 99 | * @param methodName 100 | * @param methodDesc 101 | * @param args 102 | * @returns {Promise<*>} 103 | */ 104 | async imputedCallGas(chainId, sender, value, contractAddress, methodName, methodDesc, args, multyAssets) { 105 | let multyAssetArray; 106 | if (multyAssets) { 107 | let length = multyAssets.length; 108 | multyAssetArray = new Array(length); 109 | for (var i = 0; i < length; i++) { 110 | let multyAsset = multyAssets[i]; 111 | multyAssetArray[i] = [multyAsset.value, multyAsset.assetChainId, multyAsset.assetId]; 112 | } 113 | } 114 | let gasResult = await imputedContractCallGas(sender, value, contractAddress, methodName, methodDesc, args, multyAssetArray); 115 | if (!gasResult.success) { 116 | throw 'imputedCallGas: ' + JSON.stringify(gasResult); 117 | } 118 | return gasResult.data; 119 | }, 120 | 121 | /** 122 | * 组装创建合约交易的txData 123 | * @param chainId 124 | * @param sender 125 | * @param value 126 | * @param contractAddress 127 | * @param methodName 128 | * @param methodDesc 129 | * @param args 130 | * @returns {Promise<{}>} 131 | */ 132 | async makeCallData(chainId, sender, value, contractAddress, methodName, methodDesc, args, multyAssets) { 133 | let contractCall = {}; 134 | contractCall.chainId = chainId; 135 | contractCall.sender = sender; 136 | contractCall.contractAddress = contractAddress; 137 | contractCall.value = value; 138 | 139 | let callGasInfo = await this.imputedCallGas(chainId, sender, value, contractAddress, methodName, methodDesc, args, multyAssets); 140 | contractCall.gasLimit = Number(callGasInfo.gasLimit); 141 | contractCall.price = sdk.CONTRACT_MINIMUM_PRICE; 142 | contractCall.methodName = methodName; 143 | contractCall.methodDesc = methodDesc; 144 | // let argsTypesResult = await getContractMethodArgsTypes(contractAddress, methodName, methodDesc); 145 | // let contractConstructorArgsTypes; 146 | // if (argsTypesResult.success) { 147 | // contractConstructorArgsTypes = argsTypesResult.data; 148 | // } else { 149 | // console.log("获取参数数组失败\n", argsTypesResult.data); 150 | // throw "query data failed"; 151 | // } 152 | contractCall.args = utils.twoDimensionalArray(args, callGasInfo.argsType); 153 | return contractCall; 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/test/contractCallOfAccountTransferTest.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 调用合约的同时, 支持向其他账户转账,示例为token跨链转账 4 | */ 5 | 6 | const call = require('./contractCall.js'); 7 | const BigNumber = require('bignumber.js'); 8 | const TEN = new BigNumber('10'); 9 | // 用户私钥 10 | let pri = '8c6715620151478cdd4ee8c95b688f2c2112a21a266f060973fa776be3f0ebd7'; 11 | // 用户公钥 12 | let pub = '02d0b400dfd6dd9ecdf81a068e8311c3cd4f873162389901d793d41e2043128635'; 13 | // 用户地址 14 | let fromAddress = "tNULSeBaMuU6sq72mptyghDXDWQXKJ5QUaWhGj"; 15 | // 链主资产链ID 16 | let assetChainId = 2; 17 | // 链主资产ID 18 | let assetId = 1; 19 | // 转入地址 20 | let toAddress = "TNVTdTSPVcqUCdfVYWwrbuRtZ1oM6GpSgsgF5"; 21 | // NRC20合约地址 22 | let nrc20ContractAddress = "tNULSeBaMzRzrsGToWnL4BeCMnHyMNBayDNrH3"; 23 | // 转移的token数量 24 | let tokenNumber = new BigNumber('2'); 25 | // token decimals 26 | let decimals = 18; 27 | // 要转入的NULS数量,如果没有请填入0,如转入200个NULS,则填入20000000000,此处填入的值要乘以10的8次幂,如200个NULS,则`value = 200 * (10 ^ 8)` 28 | let nulsAmount = 10000000; 29 | // 交易备注 30 | let remark = 'nrc20 token cross transfer...'; 31 | 32 | let contractCall = { 33 | chainId: assetChainId, 34 | sender: fromAddress, 35 | contractAddress: nrc20ContractAddress, 36 | value: nulsAmount, // 37 | methodName: "transferCrossChain", 38 | methodDesc: "", 39 | args: [toAddress, tokenNumber.shiftedBy(decimals)] 40 | }; 41 | // 向 tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG 转入2个NULS 42 | let nulsValueToOthers = [ 43 | { 44 | value: "200000000", 45 | address: "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG" 46 | } 47 | ]; 48 | //调用合约 49 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark, null, nulsValueToOthers); 50 | -------------------------------------------------------------------------------- /src/test/contractCallOfMultyAccounts.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 调用合约的同时, 支持向其他账户转账,示例为token跨链转账 4 | */ 5 | 6 | const call = require('./contractCall.js'); 7 | const BigNumber = require('bignumber.js'); 8 | const TEN = new BigNumber('10'); 9 | // 手续费支出地址 10 | let payAccount = 'tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG'; 11 | // 用户私钥 12 | let pri = '8c6715620151478cdd4ee8c95b688f2c2112a21a266f060973fa776be3f0ebd7'; 13 | // 用户公钥 14 | let pub = '02d0b400dfd6dd9ecdf81a068e8311c3cd4f873162389901d793d41e2043128635'; 15 | // 用户地址 16 | let fromAddress = "tNULSeBaMuU6sq72mptyghDXDWQXKJ5QUaWhGj"; 17 | // 链主资产链ID 18 | let assetChainId = 2; 19 | // 链主资产ID 20 | let assetId = 1; 21 | // 转入地址 22 | let toAddress = "tNULSeBaMnrs6JKrCy6TQdzYJZkMZJDng7QAsD"; 23 | // NRC20合约地址 24 | let nrc20ContractAddress = "tNULSeBaMzRzrsGToWnL4BeCMnHyMNBayDNrH3"; 25 | // 转移的token数量 26 | let tokenNumber = new BigNumber('2'); 27 | // token decimals 28 | let decimals = 18; 29 | // 要转入的NULS数量,如果没有请填入0,如转入200个NULS,则填入20000000000,此处填入的值要乘以10的8次幂,如200个NULS,则`value = 200 * (10 ^ 8)` 30 | let nulsAmount = 0; 31 | // 交易备注 32 | let remark = 'nrc20 token cross transfer...'; 33 | 34 | let contractCall = { 35 | chainId: assetChainId, 36 | sender: fromAddress, 37 | contractAddress: nrc20ContractAddress, 38 | value: nulsAmount, // 39 | methodName: "transfer", 40 | methodDesc: "", 41 | args: [toAddress, tokenNumber.shiftedBy(decimals)] 42 | }; 43 | //调用合约 44 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark, null, null, payAccount); 45 | -------------------------------------------------------------------------------- /src/test/contractCallOfMultyAssetsTest1.js: -------------------------------------------------------------------------------- 1 | 2 | const call = require('./contractCall.js'); 3 | 4 | /** 5 | * 调用合约转入多资产, 举例资产数据 5-1(NVT) 6 | */ 7 | // 用户私钥 8 | let pri = '477059f40708313626cccd26f276646e4466032cabceccbf571a7c46f954eb75'; 9 | // 用户公钥 10 | let pub = '0318f683066b45e7a5225779061512e270044cc40a45c924afcf78bb7587758ca0'; 11 | // 用户地址 12 | let fromAddress = "tNULSeBaMnrs6JKrCy6TQdzYJZkMZJDng7QAsD"; 13 | // 业务合约地址 14 | let busContractAddress = "tNULSeBaN7pquou8YXJZmPbkna37j7rJRUe5fV"; 15 | // 要转入的NULS数量,如果没有请填入0,如转入200个NULS,则填入20000000000,此处填入的值要乘以10的8次幂,如200个NULS,则`value = 200 * (10 ^ 8)` 16 | let nulsAmount = 0; 17 | // 资产链ID 18 | let assetChainId = 2; 19 | // 资产ID 20 | let assetId = 1; 21 | // 交易备注 22 | let remark = 'call contract...'; 23 | 24 | let contractCall = { 25 | chainId: assetChainId, 26 | sender: fromAddress, 27 | contractAddress: busContractAddress, 28 | value: nulsAmount, // 29 | methodName: "_payableMultyAsset", 30 | methodDesc: "", 31 | args: [] 32 | }; 33 | // 转入0.2个NVT 34 | let multyAssets = [ 35 | { 36 | value: "200000000000000000", 37 | assetChainId: 5, 38 | assetId: 74 39 | } 40 | ]; 41 | //调用合约 42 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark, multyAssets); 43 | -------------------------------------------------------------------------------- /src/test/contractCallOfMultyAssetsTest2.js: -------------------------------------------------------------------------------- 1 | 2 | const call = require('./contractCall.js'); 3 | 4 | /** 5 | * 调用合约同时转入NULS和NVT, 举例数据: NULS 其他资产 5-1(NVT) 6 | * 转入6.6NULS和0.02NVT 7 | */ 8 | // 用户私钥 9 | let pri = '9ce21dad67e0f0af2599b41b515a7f7018059418bab892a7b68f283d489abc4b'; 10 | // 用户公钥 11 | let pub = '03958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3'; 12 | // 用户地址 13 | let fromAddress = "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG"; 14 | // 业务合约地址 15 | let busContractAddress = "tNULSeBaMw6y39H3akxv2QofFf5KNR3pUr1Ltf"; 16 | // 要转入的NULS数量,如果没有请填入0,如转入200个NULS,则填入20000000000,此处填入的值要乘以10的8次幂,如200个NULS,则`value = 200 * (10 ^ 8)` 17 | let nulsAmount = 660000000; 18 | // 资产链ID 19 | let assetChainId = 2; 20 | // 资产ID 21 | let assetId = 1; 22 | // 交易备注 23 | let remark = 'call contract...'; 24 | 25 | let contractCall = { 26 | chainId: assetChainId, 27 | sender: fromAddress, 28 | contractAddress: busContractAddress, 29 | value: nulsAmount, // 30 | methodName: "receiveAllAssets", 31 | methodDesc: "", 32 | args: [] 33 | }; 34 | // 转入0.02个NVT 35 | let multyAssets = [ 36 | { 37 | value: "2000000", 38 | assetChainId: 5, 39 | assetId: 1 40 | } 41 | ]; 42 | //调用合约 43 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark, multyAssets); 44 | -------------------------------------------------------------------------------- /src/test/contractCallTest.js: -------------------------------------------------------------------------------- 1 | 2 | const call = require('./contractCall.js'); 3 | 4 | /** 5 | * @disc: 调用合约dome - token授权 6 | * @date: 2019-10-18 10:28 7 | * @author: Wave 8 | */ 9 | // 用户私钥 10 | let pri = ''; 11 | // 用户公钥 12 | let pub = '02cb7d76b7e91d60fa3c10298b414e5fe711aed8011b583e366b918d27fc262d73'; 13 | // 用户地址 14 | let fromAddress = "tNULSeBaMshNPEnuqiDhMdSA4iNs6LMgjY6tcL"; 15 | // 业务合约地址 16 | let busContractAddress = "tNULSeBaMyCzpjWfk4Y4EfGaQq9z72C12GLRpy"; 17 | // 要转入的NULS数量,如果没有请填入0,如转入200个NULS,则填入20000000000,此处填入的值要乘以10的8次幂,如200个NULS,则`value = 200 * (10 ^ 8)` 18 | let nulsAmount = 10000; 19 | // 资产链ID 20 | let assetChainId = 2; 21 | // 资产ID 22 | let assetId = 1; 23 | // 交易备注 24 | let remark = 'call contract...'; 25 | 26 | let contractCall = { 27 | chainId: assetChainId, 28 | sender: fromAddress, 29 | contractAddress: busContractAddress, 30 | value: nulsAmount, // 31 | methodName: "_payable", 32 | methodDesc: "", 33 | args: [] 34 | }; 35 | //调用合约 36 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark); 37 | -------------------------------------------------------------------------------- /src/test/contractCallTest2.js: -------------------------------------------------------------------------------- 1 | 2 | const call = require('./contractCall.js'); 3 | 4 | /** 5 | * @disc: 调用合约dome - 向合约转入8.88个nuls 6 | * @date: 2019-10-18 10:28 7 | * @author: Wave 8 | */ 9 | // 用户私钥 10 | let pri = 'ddddb7cb859a467fbe05d5034735de9e62ad06db6557b64d7c139b6db856b200'; 11 | // 用户公钥 12 | let pub = '02cb7d76b7e91d60fa3c10298b414e5fe711aed8011b583e366b918d27fc262d73'; 13 | // 用户地址 14 | let fromAddress = "tNULSeBaMshNPEnuqiDhMdSA4iNs6LMgjY6tcL"; 15 | // 业务合约地址 16 | let busContractAddress = "tNULSeBaMxjeNfiicypEUtttpBC1NdFsmDcCGS"; 17 | // 要转入的NULS数量,如果没有请填入0,如转入200个NULS,则填入20000000000,此处填入的值要乘以10的8次幂,如200个NULS,则`value = 200 * (10 ^ 8)` 18 | let nulsAmount = 888000000; 19 | // 资产链ID 20 | let assetChainId = 2; 21 | // 资产ID 22 | let assetId = 1; 23 | // 交易备注 24 | let remark = 'call contract...'; 25 | 26 | let contractCall = { 27 | chainId: assetChainId, 28 | sender: fromAddress, 29 | contractAddress: busContractAddress, 30 | value: nulsAmount, // 31 | methodName: "_payable", 32 | methodDesc: "", 33 | args: [] 34 | }; 35 | //调用合约 36 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark); 37 | -------------------------------------------------------------------------------- /src/test/contractCreate.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const utils = require('../utils/utils'); 3 | const sdk = require('../api/sdk'); 4 | const {getBalance, countFee, inputsOrOutputs, getContractConstructor, validateContractCreate, imputedContractCreateGas, validateTx, broadcastTx} = require('./api/util'); 5 | 6 | module.exports = { 7 | 8 | /** 9 | * 创建合约 10 | * @param pri 11 | * @param pub 12 | * @param createAddress 13 | * @param assetsChainId 14 | * @param assetsId 15 | * @returns {Promise} 16 | */ 17 | async createContract(pri, pub, createAddress, assetsChainId, assetsId, contractCreate, remark) { 18 | //1、通过接口获取合约的参数 args 19 | let hex = contractCreate.contractCode; 20 | const constructor = await getContractConstructor(hex); 21 | console.log(constructor.data.constructor.args); 22 | //2、给每个参数复制 获取contractCreateTxData 23 | let newArgs = contractCreate.args; 24 | const contractCreateTxData = await this.makeCreateData(contractCreate.chainId, createAddress, contractCreate.alias, hex, newArgs); 25 | //3、序列化 26 | 27 | let chainId = contractCreate.chainId; 28 | const balanceInfo = await getBalance(chainId, assetsChainId, assetsId, createAddress); 29 | let amount = contractCreateTxData.gasLimit * contractCreateTxData.price; 30 | let transferInfo = { 31 | fromAddress: createAddress, 32 | assetsChainId: assetsChainId, 33 | assetsId: assetsId, 34 | amount: amount, 35 | fee: 100000 36 | }; 37 | 38 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 15); 39 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 15, contractCreateTxData); 40 | let txhex; 41 | //获取手续费 42 | let newFee = countFee(tAssemble, 1); 43 | //手续费大于0.001的时候重新组装交易及签名 44 | if (transferInfo.fee !== newFee) { 45 | transferInfo.fee = newFee; 46 | inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 15); 47 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 15, contractCreateTxData); 48 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 49 | } else { 50 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 51 | } 52 | console.log(txhex); 53 | //4、验证交易 54 | let result = await validateTx(txhex); 55 | if (result) { 56 | //5、广播交易 57 | let results = await broadcastTx(txhex); 58 | console.log(results); 59 | if (results && results.value) { 60 | console.log("交易完成, 合约地址: " + contractCreateTxData.contractAddress) 61 | } else { 62 | console.log("广播交易失败") 63 | } 64 | } else { 65 | console.log("验证交易失败") 66 | } 67 | }, 68 | 69 | /** 70 | * 组装构造函数的参数类型 71 | * @param constructor 72 | * @returns {Promise} 73 | */ 74 | async makeContractConstructorArgsTypes(constructor) { 75 | let args = constructor.data.constructor.args; 76 | let length = args.length; 77 | let contractConstructorArgsTypes = new Array(length); 78 | let arg; 79 | for (let i = 0; i < length; i++) { 80 | arg = args[i]; 81 | contractConstructorArgsTypes[i] = arg.type; 82 | } 83 | return contractConstructorArgsTypes; 84 | }, 85 | 86 | /** 87 | * 预估创建合约的gas 88 | * @param sender 89 | * @param contractCode 90 | * @param args 91 | * @returns {Promise<*>} 92 | */ 93 | async imputedCreateGas(sender, contractCode, args) { 94 | let result = await validateContractCreate(sender, sdk.CONTRACT_MAX_GASLIMIT, sdk.CONTRACT_MINIMUM_PRICE, contractCode, args); 95 | if (result.success) { 96 | return await imputedContractCreateGas(sender, contractCode, args); 97 | } else { 98 | console.log("创建合约验证失败") 99 | } 100 | }, 101 | 102 | /** 103 | * 组装创建合约交易的txData 104 | * @param chainId 105 | * @param sender 106 | * @param contractCode 107 | * @param args 108 | * @param alias 109 | * @returns {Promise<{}>} 110 | */ 111 | async makeCreateData(chainId, sender, alias, contractCode, args) { 112 | let contractCreate = {}; 113 | contractCreate.chainId = chainId; 114 | contractCreate.sender = sender; 115 | contractCreate.alias = alias; 116 | contractCreate.gasLimit = await this.imputedCreateGas(sender, contractCode, args); 117 | contractCreate.price = sdk.CONTRACT_MINIMUM_PRICE; 118 | contractCreate.contractCode = contractCode; 119 | 120 | let constructor = await getContractConstructor(contractCode); 121 | let contractConstructorArgsTypes = await this.makeContractConstructorArgsTypes(constructor); 122 | contractCreate.args = await utils.twoDimensionalArray(args, contractConstructorArgsTypes); 123 | contractCreate.contractAddress = sdk.getStringContractAddress(chainId); 124 | return contractCreate; 125 | } 126 | 127 | } -------------------------------------------------------------------------------- /src/test/contractCreateTest.js: -------------------------------------------------------------------------------- 1 | 2 | const create = require('./contractCreate.js'); 3 | 4 | /** 5 | * @disc: 创建合约 dome 6 | * @date: 2019-10-18 10:29 7 | * @author: Wave 8 | */ 9 | let pri = '76b7beaa98db863fb680def099af872978209ed9422b7acab8ab57ad95ab218b'; 10 | let pub = '02ec9e957823cd30d809f44830442562ca5bf42530251247b35d9209690f39be67'; 11 | let fromAddress = "tNULSeBaMqywZjfSrKNQKBfuQtVxAHBQ8rB2Zn"; 12 | let alias = "test_alias"; 13 | // 资产链ID 14 | let assetChainId = 2; 15 | // 资产ID 16 | let assetId = 1; 17 | let remark = 'new contract...'; 18 | 19 | let contractCreate = { 20 | chainId: assetChainId, 21 | sender: fromAddress, 22 | alias: alias, 23 | contractCode: '504b03040a0000080000aa7b564e00000000000000000000000003000400696f2ffeca0000504b03040a0000080000aa7b564e00000000000000000000000008000000696f2f6e756c732f504b03040a0000080000aa7b564e00000000000000000000000011000000696f2f6e756c732f636f6e74726163742f504b03040a0000080000aa7b564e00000000000000000000000017000000696f2f6e756c732f636f6e74726163742f746f6b656e2f504b0304140008080800aa7b564e00000000000000000000000028000000696f2f6e756c732f636f6e74726163742f746f6b656e2f53696d706c65546f6b656e2e636c617373b558f97754e5197eeecc90990c972d9090059209a498cc9291a58a8152020d35ca5602b1605bbd99b9492ecc12670922b46ead4babd56aeb5ad1565bd4aa2c020169d59ed353cfe93fd17f84d3d3e7fdee9d3b37612639d5d31ff2ddf77ecbfb3eeff67c77f2afff7cf639804df87b23a23825c323329c96e14c1831fcb411cdf859108f86119497281e93e171997e22cce149197e1ec62ff0d462acc2d3413c13c672fc2a8ce7f0bcccfc3a8817827831cc53bf91e125195e96e5df8af4bb205e09a3430e44f19a0cafcbf086a87d5386df87f096cc9c9597b7457a27843fc8f38f21bc2b7ade0be24f41fc39887341bcaf219033b2a686a6bdc78d692399317213c99152c1ca4d6cd3d0503c951dcb673484d266caca1a99a2066d58c3e252be646446ca535399531a5aeca359a33499dc654d0ce74ae68459e0f1d098417d2993a796d97bca252b93dc674c71b171c49ac819a57281c68766af6edf6be593b972a6984ce573a582912a258be913c9c174ba60168bdb6a9bdb419d412393c99f34d31a4a5f43e337342f0056f5f6d58a6360773e6d4a10ac9cb9bf9c1d330b878db18c8a7a3e6564468d8225efce64a0346931643db7c228e54f98b9e488959de26691a9bbed503957b2b2e6a855b4787c3097636e4a563e47151b6a7b62b87b92a39679924afcbd7d4c6b6b05fdada96cd86ee5acd20e0d3b7a6f75b0decc5c35c37da31a968822cbc80c66f304ae61dd6cfc078d02ebb164166639125dd09143e64365ab60a6a5b2541548e16938dcbb4032e75dad1b8e45f99339b3a0a173fef3acc8e294994bcb565d1d19ac14e8a269235336a5796655c0a9a94a152c192919a9132c47f56eb302b5d048ae386e16f614f2590d47be917bb5bdeb3bc6121c57ea7da53cc3e974f181710d772c60af6ec0828e129242c5030d772e84be2ebea0313555c84f53dd722b972a9846d11c543306c92a6ca4d3667ad48eef7232d79cf565c5f29832e66e0ae53315510ebb49fabf84973d1032ec2d1babe2260f2ed77eb868565f96550e559739b3ab12d7af19cc5109a6bdc583c0d5ba283569a64e90657aeb9f4fd659ab7fa24115ffc68a40df63f3eaf0528b9cf7678b131a06ff27bbb5358547f2e542cadc6349cb2df7306bbf6cd7d18fa48edb65d8884d3a36638b8e217ca0e3436cd1b0a27a6fdc6d1427d9ac3abe8d3b74dc25c35f64f347f858c727381fc4051d177149c7a7b84c42abc3edca76cf61a74586a64da1c82573def5e11ca96477c62816cda2e0213d5cd17115333aaee13a0fccbacf782dd58a888e49983a72c8e83821c367b8a1c382b910ba4a2755d0cd7ad79116adf7e05e1d79301e7fc5df747c8ef31a3a8673c5f2f8b895b2b82fe274703aa254cbe6691d5fe0bc8ea36087270e4f9a11551d916cb9588a8c999109f6312f864869d2c845f2850819dfc8f078e4f67e394e289db32c389413c98fdb36fac5c52f79e32c7cafb216aae57260ecb899a2f6b535fb6bb7f3a261cd7c5153772c0b2e706ce8d001be1c1edacf712a7f527a6bb82e6f86b2e54cc9529f59fdf55ab0ded9d69a78f749eb34149d5b29c22b7f812bcc3f55a6735bbdf7be1d916db7cef4dd3aa5a1bda68123ac4e524ec0cc5a54df5587bd544dd93d3f6172df861a306a1a0d16ec0f025ae83d26e71b53f9ec9451607ee761337e04f9c9868c7b85097943f71eabc51de8e637750c3ec49140039a842af8e3a049d8423d49187cfa8433d493c400d2b492b7f2ef2ecffb003fd699616ca3bc9d3349be697c2e8a5e8676416df90ec70635b9163b38eaf6067c173bf91c745677f1a911422d45beb98ad62fa8682376d750e4ff688ea2be05156dc6f76a280acc45945c50d110f6388afecd1d8bf834a3335476090d571088de40f0e80c4257d05815c3d1d81568d1f815f8a2cd812bf0471397b0b8397015fa552c915397d1780d4b05d0752cf3e3be1b587e54736666b0e21a9a2eba40fbb158fd060c30658bb11a2d6865296cc606a639c6246f645a0799d6434c729a491687b6d8401d8744ea57711049cac5a7a4ef739f5f491b95febb29b705b86d58797eeb4892e50189c51754212692441c8e5dc74a1fbec4aafd89af1064602e24e2ce54f340a02df015429c1449c21f505e75f2f72a887529313611650bc3bd8ec9bf8d798b33e4552f92ae1749ecc53e276dfb29f978ba1b07e8bf9f6797e0204f04f00327a1f6da56ae1de2cc52f86ea22588919b680ee2f0ac248bdf4b7c737c3d825127ef670823c0674f34c6142566d0128d715c1d8d736c95d4c54492ac05aa85daa2c0df8b46825e46b0cd84bc8e80c4b1a8adcf75ac07f7398ef5e087ca31910eaaf408b895fe9ae9e0bde5a4e3491e914cf6c4fe8960e01c02fe6b68932aaba4a6795fdc4ecdbeb8e4c0ef817884d11a453b2174d2f83aea1488115b9f07a21dfb7684713f81f9545417c31fdaa9dd446bad90063517e98ff0632798166d8ae6ae2863199728c6e24e143921f29c3836a9583d80101e64120d92d1980760970bb04b454e53d24105b0665a7fe22279d041d21e750cb7df404705c49ad92096aa9d134ce624bbcff200687701b4ab9ad494340f80075c00136c0151d15d01b0b602404d5c45671d1c59e2c8d1cdbc0747b78ba3dbc5d14d1febe2305c1c978943623c142586ae8aedfdf1c45544ce62859a60e53040e7a057b0b6cc83d5efe9f022a35c22ee32ab6d9a55f4302faf47d8e7a73d8d30e4621f72b10f31cd5b5487df89946a04a9b746e9e21e165ba896533ef914a42c4e3de1907584f545740381685b40bc4bc8108bb705e85d375daaf2acdd0d8fb2d01ea3d5c7b1923abad85955268ab83823187770469846bb61234ec3865821f72826f2c907af83e78c83a7d38327d1b46e06eb2b687a66a1b1cbfe296a7b1a2bf00ccbfe590f924e1749a78ba4d345d2e922697191582e927f7045740cd8b1f0f2b74dd66dce453610508b6dce1dd51688276c49507a59fc39ea7b5efe958836bc40067991fcfc126fa2973d88075cc4032ee20117f1808378156fb5e3e4f32a8bdb335b3923f90f816493248bf3147f42381e9de6aa448ba1bc8a6fed8fc69b36cce0b68a7b8db10423de5d85ee4df72b64ac577975bcc680bf4ee86f78ca72bd0b793d5b6e9ff30563b776031372bf82ec931f340e90a203a4cb01928837f54a862b207ae682b0b3fc16d59d65cdbdcd78bee301e025b7ec1c726b60ac2b00f8b3c701708c6f12cfd5bc075648d3b285dfacde0817dde60cab6def320aef29832df631d7e06a654653415f045fd34e4dd979c8b133e5dc371dd19804597843cabab62ddbc973d4f33eed7e407afcd0435c1daecd0e14944d918aee1543eb2d8ef59263dd74acb7d6f0327e0d7d73ddfc98ee7ce231d9ea9a6c75dc14a9acbe8be6383ced96984f79b1a68ec38959666d8f2f52d12542f894fe5cf6a4758d6b7e8debf11ac7639104887fb6ef2755c53c8c5f2ae53e2c278b3e4b36ece0f35534fe17504b0708ec308779cb09000028180000504b0304140008080800aa7b564e00000000000000000000000022000000696f2f6e756c732f636f6e74726163742f746f6b656e2f546f6b656e2e636c617373a552d14e1341143d03b5cb16aa28a8a0284a08697970131ff481a76a24694282a19507dfa6bb431d989da933b325fc9a0f7e801f65bc534ba5b6a5896eb23b3be79e7bcebd33f7c7cf6fdf01bcc64e84e711b623bc60a8367a3d6bfa5c7de80bed19569a5a0bfb5e71e7848bf092186dcbb53b1376c828699e0b86f55afde89cf779a2b8ee262d6fa5ee1e306c9e14dacb5c9c4a273b4a34b4369e7b69b463d83b9226d18572496ab4b73cf589cb2e123ee224a7525c9248d95de51da318963291ca9c2b4a5eacd59b0ccb9ea8aa55f47aea8a61e3ba869cfb2fc93bd96d6a2fbac29244dce154582a8ecf18ded4a61b37b2cc0ae70e668aec8c37f3915b6add0b3bd6d5fedcae4ec4d7425a9191e2921f1e26c3db39554d2faafe99eee85ae4d09a9ce1d33ca17fb489f86034e8ae63ae94b90cc7c9d0fe2fb799475d6999c2a6e2502af2a8b4cd85d0af0295616b42d0876832e030acfe19c2e3ceb9486942f76fcbd8fd6be06f278fcd7e99816101e1894b749788695fa15d99d66580b0952958157727b07b589dc0eee301a9dfc0b0466f144cd70784877844ff01ac2efc0647a1c7d81886d6166f864684cdd9b94ff0748aef388d085b83ef33dca135141a7c4ad46e488a10ff02504b070868fe421cca0100005e040000504b0304140008080800aa7b564e00000000000000000000000030000000696f2f6e756c732f636f6e74726163742f746f6b656e2f546f6b656e24417070726f76616c4576656e742e636c6173738d565b6f1b4514fec6bbde75b69bbb49d224b46929e05b6a2ee19a4b73218140d2943835b4406163af926d9cdd74771d90a0129540ea033c801020242e2f252f790089b80824c45390f82ffc03049c995dbb89e3243cf8ccd93367e67cdf7c6746fef39f5f7e03f018ae6988e34213148c7333c1cd248f4da998d63083e735bcc0cd0c66b937abe2450d2770218697f838c7cd7c0c176358e0ee256e5e56b1a822c71075deb64d97e1d49ce564ed72c9cb161cdb778d829ff58a6bd98962d1353d6f9841f5364cbbc853a39b46a96c3274cd5d37368decbae1af6627ad9559db37574c97529511cbb6fc3186cb89a3773d66b6e1f6c93c833ce5140940eb9c659b17cbebcba6bb642c9728d231e7148c52de702dfe1d06657fd5f2189a2736365c87b04f6f9ab6cfa0cfdac47caa64789e49d39983607c67cdb4b34bdc9edbb798389e5d2cdbbeb56ee62dcfa22a970cd758377dd39db06dc7377ccbb169cf546382462d27bb68de285bae59a41d632ba6bf10883190481e2747ccab659f39e694f98969b479ae2aa0e6edf9e065f381a03d54f6104979b930eb64e2706114a2639488f97d6152c9b057b20bcbd7cd823f9cbccac01c2ed28129219241a234e77ca3b0366f6c08eda8c1a9f4aae1ad06824b89e42c152156e5122533fa88f94ece772d7b85215e852f760ea2b4b39673ca6ec19cb1782f6842cdf33c4d471f967474a15b470f3727d1abe332f22a5e21e9fe7f37a87855c7237854c5151d4fe16986ee7a189365ab244e3bbe6fe5bbe2f28deab88ad7b8799d006606c28b364ae43203e2ae898c37740c6384a1adfef4187a1bea1ff6391d5a3e9059f43a43e7be7312413aa6fea308379aded362c4ab514b9054c60627c330983828cd41b5c2631aaecbaff6cf11f9fd89a9c3a771869ecc38a82b2121c215a78735c2451723e94ea346f37de8a7effbe9ab44a34c633c75172c95de412495d981941adc81fca358758a6c17a2646f50a68b267868818f4e94719aa2a9603d06f000203c5e97098f578e088fd796708efc4e89261f2467bf7d080f93e590b234f2e5d1d44f88fc50c3a088e03ba2a61e248435191248868bc7289b575404977b0c34117d8fd6dc143b74055935d44a889a2e444320523d90f71b0249370622d503f980d67c7808909e104806830d80c8f5406e3704725e2c3a0044ae07f211adf9f810205c335e98ae7cb8d75f9423d1782b95fe1e51793bbd8b965405d134fdee202a6da77f8732cf75dba58ea22143bf0ad4afd0ba45375ec4298b9f679020514cda9b205513e45db4f381627205b12db472ef0fa8f21664699b404882462f01053e818a4fe9e43e23989f13e52ff026be14b40602c0355ab7e89fc6e3824e1143148be009d1a0badac2fe46bf8a2715d6adb0b836cea9d32b1752ff393cc6e9805d734a306be26046da4ef7ad069c78580ac36f55e37210271a5a10efbb07bf43dc9eafe9367d43cdf32da6f0dd1e35a643d89d04fa193c4b5038d84128ede3ec5fbae511824b30c947e84718cbefffa445f49c862caed1b6bc51867ec5892b77a1773457484141a5b5a32df025eeb7073e616e6dbb594147059df58d77674fe30d8540231815760c67c3a746c173f42c35fd07504b0708ea7bbc798f040000e6090000504b0304140008080800aa7b564e00000000000000000000000030000000696f2f6e756c732f636f6e74726163742f746f6b656e2f546f6b656e245472616e736665724576656e742e636c6173738d56df531b5514fe6e76b31bb60be19740015b5aab8624b06ad156c36f84160da5051a0bd5da25d9c296b08bbb1b5e1c1ffa6ff8aebcf0a033923a3ae3f88433fe2ffe078e7aeedd854212c0879c7bf6dc73eef9cef9cebd933ffff9e53700efe189864e4c3441c12417535c4c73db8c8a590d73b8a3e12e177398e7dabc8a4f345cc244029ff235cfc54202f71258e4ea7d2e1ea85852b1cc203ff3dc6d862b79db359c4ad9378aae1378663130fcd29631552a7996efe7186281cb10df35cb158ba12bffdcdc358d6d33d834a6ed8d7927b0362c8fbc9451dbb183718687a9f30fbc60b7e1f18305823be3960840326f3bd6bdcaf6bae5ad98eb65b2b4e7dda2592e989ecdbf23a31c6cda3e43f38a673afe33cb9bddb59c80419f771ccb9b299bbe6fd176b61e4ce06e598eb1c2e58d53c154e3f5a58a13d8db56c1f66dca72dff4cc6d2bb0bc29c7710333b05d87ce4c372ed03cf63196acaf2ab66795e84475c30ae6040d03a9c18b8850fd23e76b17f498f72b4e47af70e6fc704dd0772124b187729d4163c23ff6ba9c3a9b0c854a30cb54ed6b9153d974368cc5f5e75631c80dae3130971353b72588318988e6e5c02c6e2d983b822f1a674abd69fa9b21c9526a709e92502d95323933fa4804ee72e0d9ce0643e7117c717268a593b565b7e215ad399bf3af090687b99b8e3eace8e842b78e1e2e2ea357c74314547c4674fdff0950f148c73b7857c5aa8e5bb8cdd05d0b63ba62974b96c7d0712af26b7ed5c674ace131179f132bd981c01da3b2b203e26689cd2f74e430cad05adb3786de867c47534ded2a84048bc9a6eca73a248cd4a0fef34a6db47d62a4a8eb8d8681483277762ca7c43094aa27a59ea7a841b91affa3c939c7bf3f3573f636aed1d3d8099a47488871aee9018d71bac54a8cd3aad17e1ffae9fb75fa2ad32ad3da997e0996ce1c2096ce1e404a0f1d40fe51445d21d98538c92c790ea109c36881810e1a82ab644d87f118c01b80d0785e26349e3926349e5bc20dd293120986374fc8b7f036490ec7a09587c6d33f21f6c3717e45186f8a7c7ae810e5634861300a1e276f9e4d1175bc42af09eb2d8ab92d4ee80abd8e112b1162ba060d8148b540720d81641a03916a814c50cce419407a2220596a743d10b916c84c4320c322a80e885c0be40ec5dc3d0308e78b27a68b1e9df517f970ea5ea433df232eef670ed192ae229ea1df77884bfb99dfa12c70de0e699a68c9d2af0af55b24f7a065859dbc783f4307896cd24907e9c8413e441b5fc8265791d843926b7f4095f7204bfb04421265f41250200f150bd4b94582f9804a5ec2975816650d84808fcb7a41ff266e8a724a18215b0cef8be1d4d516f637fa557ca0b06e85756a93bc747adba2d27f8eda381b56d79c1695357130a3ad57fb36c39ab8598acc4f8fec7268a732b4d0def70a7ebbb8398fe826add2f0ac119b8f4fb0311bc1ee20d01fe22382c2c10e41699b64ffd20d8f115c82493a223dc658e1f42705d1531a55f1848ee58332f22b2eadbe84dede5c25064529c9f6d65097b8de16ea8439d9fa4d15ed5574d40eded313833712018d614cc8715c8f9e19051fd393d4f41f504b0708826261e37e040000ca090000504b01020a000a0000080000aa7b564e000000000000000000000000030004000000000000000000000000000000696f2ffeca0000504b01020a000a0000080000aa7b564e000000000000000000000000080000000000000000000000000025000000696f2f6e756c732f504b01020a000a0000080000aa7b564e00000000000000000000000011000000000000000000000000004b000000696f2f6e756c732f636f6e74726163742f504b01020a000a0000080000aa7b564e00000000000000000000000017000000000000000000000000007a000000696f2f6e756c732f636f6e74726163742f746f6b656e2f504b01021400140008080800aa7b564eec308779cb090000281800002800000000000000000000000000af000000696f2f6e756c732f636f6e74726163742f746f6b656e2f53696d706c65546f6b656e2e636c617373504b01021400140008080800aa7b564e68fe421cca0100005e0400002200000000000000000000000000d00a0000696f2f6e756c732f636f6e74726163742f746f6b656e2f546f6b656e2e636c617373504b01021400140008080800aa7b564eea7bbc798f040000e60900003000000000000000000000000000ea0c0000696f2f6e756c732f636f6e74726163742f746f6b656e2f546f6b656e24417070726f76616c4576656e742e636c617373504b01021400140008080800aa7b564e826261e37e040000ca0900003000000000000000000000000000d7110000696f2f6e756c732f636f6e74726163742f746f6b656e2f546f6b656e245472616e736665724576656e742e636c617373504b0506000000000800080051020000b31600000000', 24 | args: ['waves', 'waves', 100000000, 8] 25 | }; 26 | 27 | create.createContract(pri, pub, fromAddress, assetChainId, assetId, contractCreate, remark); -------------------------------------------------------------------------------- /src/test/contractDelete.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const {getBalance, inputsOrOutputs, validateContractDelete, validateTx, broadcastTx} = require('./api/util'); 3 | 4 | module.exports = { 5 | /** 6 | * 调用删除合约 7 | * @param pri 8 | * @param pub 9 | * @param fromAddress 10 | * @param assetsChainId 11 | * @param assetsId 12 | * @param contractDelete 13 | * @returns {Promise} 14 | */ 15 | async deleteContract(pri, pub, fromAddress, assetsChainId, assetsId, contractDelete, remark) { 16 | let chainId = contractDelete.chainId; 17 | const balanceInfo = await getBalance(chainId, assetsChainId, assetsId, fromAddress); 18 | let amount = 0; 19 | let transferInfo = { 20 | fromAddress: fromAddress, 21 | assetsChainId: assetsChainId, 22 | assetsId: assetsId, 23 | amount: amount, 24 | fee: 100000 25 | }; 26 | 27 | const contractDeleteTxData = await this.makeDeleteData(contractDelete.chainId, contractDelete.sender, contractDelete.contractAddress); 28 | 29 | let deleteValidateResult = await validateContractDelete(assetsChainId, contractDeleteTxData.sender, contractDeleteTxData.contractAddress); 30 | if (!deleteValidateResult) { 31 | console.log("验证删除合约失败"); 32 | return; 33 | } 34 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 17); 35 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 17, contractDeleteTxData); 36 | let txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 37 | let result = await validateTx(txhex); 38 | console.log(result); 39 | if (result) { 40 | let results = await broadcastTx(txhex); 41 | if (results && results.value) { 42 | console.log("交易完成") 43 | } else { 44 | console.log("广播交易失败") 45 | } 46 | } else { 47 | console.log("验证交易失败") 48 | } 49 | }, 50 | 51 | /** 52 | * 组装创建合约交易的txData 53 | * @param chainId 54 | * @param sender 55 | * @param contractAddress 56 | * @returns {Promise<{}>} 57 | */ 58 | async makeDeleteData(chainId, sender, contractAddress) { 59 | let contractDelete = {}; 60 | contractDelete.chainId = chainId; 61 | contractDelete.sender = sender; 62 | contractDelete.contractAddress = contractAddress; 63 | return contractDelete; 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/test/contractDeleteTest.js: -------------------------------------------------------------------------------- 1 | 2 | const deleted = require('./contractDelete.js'); 3 | 4 | /** 5 | * @disc: 删除合约 dome 6 | * @date: 2019-10-18 10:31 7 | * @author: Wave 8 | */ 9 | let pri = '76b7beaa98db863fb680def099af872978209ed9422b7acab8ab57ad95ab218b'; 10 | let pub = '02ec9e957823cd30d809f44830442562ca5bf42530251247b35d9209690f39be67'; 11 | let fromAddress = "tNULSeBaMqywZjfSrKNQKBfuQtVxAHBQ8rB2Zn"; 12 | // 业务合约地址 13 | let busContractAddress = "tNULSeBaNA3RADUR6CJCzxdPSevKJKDM4ULAqz"; 14 | // 资产链ID 15 | let assetChainId = 2; 16 | // 资产ID 17 | let assetId = 1; 18 | let remark = 'delete contract...'; 19 | 20 | let contractDelete = { 21 | chainId: assetChainId, 22 | sender: fromAddress, 23 | contractAddress: busContractAddress 24 | }; 25 | 26 | //合约删除 27 | deleted.deleteContract(pri, pub, fromAddress, assetChainId, assetId, contractDelete, remark); 28 | 29 | -------------------------------------------------------------------------------- /src/test/contractNRC20TransferTest.js: -------------------------------------------------------------------------------- 1 | 2 | const call = require('./contractCall.js'); 3 | const BigNumber = require('bignumber.js'); 4 | const TEN = new BigNumber('10'); 5 | /** 6 | * @disc: NRC20 token transfer dome 7 | * @date: 2019-10-18 10:28 8 | * @author: Wave 9 | */ 10 | // 用户私钥 11 | let pri = 'ddddb7cb859a467fbe05d5034735de9e62ad06db6557b64d7c139b6db856b200'; 12 | // 用户公钥 13 | let pub = '02cb7d76b7e91d60fa3c10298b414e5fe711aed8011b583e366b918d27fc262d73'; 14 | // 用户地址 15 | let fromAddress = "tNULSeBaMshNPEnuqiDhMdSA4iNs6LMgjY6tcL"; 16 | // 链主资产链ID 17 | let assetChainId = 2; 18 | // 链主资产ID 19 | let assetId = 1; 20 | // 转入地址 21 | let toAddress = "tNULSeBaMnrs6JKrCy6TQdzYJZkMZJDng7QAsD"; 22 | // NRC20合约地址 23 | let nrc20ContractAddress = "tNULSeBaN2vEicPEn15febEuvqM29X4wRZ5eGG"; 24 | // 转移的token数量 25 | let tokenNumber = new BigNumber('100'); 26 | // token decimals 27 | let decimals = 2; 28 | // 交易备注 29 | let remark = 'nrc20 token transfer...'; 30 | 31 | let contractCall = { 32 | chainId: assetChainId, 33 | sender: fromAddress, 34 | contractAddress: nrc20ContractAddress, 35 | value: 0, // 36 | methodName: "transfer", 37 | methodDesc: "", 38 | args: [toAddress, tokenNumber.multipliedBy(TEN.pow(decimals))] 39 | }; 40 | //调用合约 41 | call.callContract(pri, pub, fromAddress, assetChainId, assetId, contractCall, remark); 42 | -------------------------------------------------------------------------------- /src/test/createTrading.js: -------------------------------------------------------------------------------- 1 | const txs = require('../model/txs'); 2 | const sdk = require('../api/sdk'); 3 | 4 | // 以NVT/NULS举例 5 | 6 | 7 | var addressHex = "TNVTdTSPVcqUCdfVYWwrbuRtZ1oM6GpSgsgF5"; 8 | 9 | let coinTrading = {} 10 | 11 | coinTrading.address = sdk.getBytesAddress(addressHex) 12 | coinTrading.quoteAssetChainId = 5; 13 | coinTrading.quoteAssetId = 1; 14 | coinTrading.scaleQuoteDecimal = 6; 15 | coinTrading.baseAssetChainId = 2; 16 | coinTrading.baseAssetId = 1; 17 | coinTrading.scaleBaseDecimal = 6; 18 | coinTrading.minBaseAmount = 10000000; 19 | coinTrading.minQuoteAmount = 10000000; 20 | 21 | let tx = new txs.CoinTradingTransaction(coinTrading); 22 | console.log(tx.txData.toString("hex")) -------------------------------------------------------------------------------- /src/test/crossChainTransfer.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); const txs = require('../model/txs'); const Serializers = require("../api/serializers"); const {isMainNet, countCtxFee, getBalance, broadcastTx, sendCrossTx} = require('./api/util'); /** * @disc: 跨链交易 dome * @date: 2019-10-18 10:32 * @author: Wave */ /*let pri = '9ce21dad67e0f0af2599b41b515a7f7018059418bab892a7b68f283d489abc4b';//tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG let pub = '03958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3'; let fromAddress = "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG"; let toAddress = '8CPcA7kaXSHbWb3GHP7bd5hRLFu8RZv57rY9w';*/ let pri = "94bb1af12b9099d9c28c436e5613661253a7b3f45a4c2534a0f08a996518bb37";//8CPcA7kaXSHbWb3GHP7bd5hRLFu8RZv57rY9w let pub = '0398d4c2f8fa788a5f314bd40da588fa0991f2b4fdf7dbf25abce5ecc8cf129d00'; let fromAddress = "LINcjJR3SA4Ui6z5kcGmYm459z7JGQPxuxRC"; let toAddress = 'tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG'; let amount = 8800000000; let remark = '跨链交易测试....'; let transferInfo = { fromAddress: fromAddress, toAddress: toAddress, assetsChainId: 8, assetsId: 1, amount: amount, remark: remark, fee: 1000000 }; //调用 transferTransaction(pri, pub, 2, transferInfo); /** * 转账交易 * @param pri * @param pub * @param chainId * @param transferInfo * @returns {Promise} */ async function transferTransaction(pri, pub, chainId, transferInfo) { //账户转出资产余额 //console.log(transferInfo); const balanceInfo = await getBalance(8, transferInfo.assetsChainId, transferInfo.assetsId, transferInfo.fromAddress); let inputs = []; let outputs = [{ address: transferInfo.toAddress ? transferInfo.toAddress : transferInfo.fromAddress, assetsChainId: transferInfo.assetsChainId, assetsId: transferInfo.assetsId, amount: transferInfo.amount, lockTime: 0 }]; let mainNetBalanceInfo = await getBalance(8, 2, 1, transferInfo.fromAddress); let localBalanceInfo; //如果不是主网需要收取NULS手续费 if (!isMainNet(chainId)) { if (mainNetBalanceInfo.balance < transferInfo.fee) { console.log("余额不足"); return; } } //如果转出资产为本链主资产,则直接将手续费加到转出金额上 if (chainId === transferInfo.assetsChainId && transferInfo.assetsId === 1) { let newAmount = transferInfo.amount + transferInfo.fee; if (balanceInfo.balance < transferInfo.amount + transferInfo.fee) { console.log("余额不足"); return; } //转出的本链资产 = 转出资产amount + 本链手续费 inputs.push({ address: transferInfo.fromAddress, assetsChainId: transferInfo.assetsChainId, assetsId: transferInfo.assetsId, amount: newAmount, locked: 0, nonce: balanceInfo.nonce }); //如果不是主网需收取主网NULS手续费 if (!isMainNet(chainId)) { inputs.push({ address: transferInfo.fromAddress, assetsChainId: 2, assetsId: 1, amount: transferInfo.fee, locked: 0, nonce: mainNetBalanceInfo.nonce }); } } else { localBalanceInfo = await getBalance(8, chainId, 1, transferInfo.fromAddress); if (localBalanceInfo.balance < transferInfo.fee) { console.log("该账户本链主资产不足够支付手续费!"); return; } //如果转出的是NULS,则需要把NULS手续费添加到转出金额上 if (transferInfo.assetsChainId === 2 && transferInfo.assetsId === 1) { let newAmount = transferInfo.amount + transferInfo.fee; if (mainNetBalanceInfo.balance < newAmount) { console.log("余额不足"); return; } inputs.push({ address: transferInfo.fromAddress, assetsChainId: transferInfo.assetsChainId, assetsId: transferInfo.assetsId, amount: newAmount, locked: 0, nonce: mainNetBalanceInfo.nonce }); } else { inputs.push({ address: transferInfo.fromAddress, assetsChainId: transferInfo.assetsChainId, assetsId: transferInfo.assetsId, amount: transferInfo.amount, locked: 0, nonce: balanceInfo.nonce }); inputs.push({ address: transferInfo.fromAddress, assetsChainId: 2, assetsId: 1, amount: transferInfo.fee, locked: 0, nonce: mainNetBalanceInfo.nonce }); } //本链主资产手续费 if (!isMainNet(chainId)) { inputs.push({ address: transferInfo.fromAddress, assetsChainId: chainId, assetsId: 1, amount: transferInfo.fee, locked: 0, nonce: localBalanceInfo.nonce }); } } let tAssemble = await nuls.transactionAssemble(inputs, outputs, transferInfo.remark, 10);//交易组装 let ctxSign = "";//本链协议交易签名 let mainCtxSign = "";//主网协议交易签名 let bw = new Serializers(); let mainCtx = new txs.CrossChainTransaction(); let pubHex = Buffer.from(pub, 'hex'); let newFee = 0; if (isMainNet(chainId)) { newFee = countCtxFee(tAssemble, 1) } else { newFee = countCtxFee(tAssemble, 2); mainCtx.time = tAssemble.time; mainCtx.remark = tAssemble.remark; let mainNetInputs = []; if (transferInfo.assetsChainId === 2 && transferInfo.assetsId === 1) { mainNetInputs.push({ address: transferInfo.fromAddress, assetsChainId: transferInfo.assetsChainId, assetsId: transferInfo.assetsId, amount: transferInfo.amount + newFee, locked: 0, nonce: mainNetBalanceInfo.nonce }); } else { mainNetInputs = [{ address: transferInfo.fromAddress, assetsChainId: transferInfo.assetsChainId, assetsId: transferInfo.assetsId, amount: transferInfo.amount, locked: 0, nonce: balanceInfo.nonce }, { address: transferInfo.fromAddress, assetsChainId: 2, assetsId: 1, amount: newFee, locked: 0, nonce: mainNetBalanceInfo.nonce }]; } mainCtx.setCoinData(mainNetInputs, outputs); } //如果手续费发生改变,重新组装CoinData if (transferInfo.fee !== newFee) { if (chainId === transferInfo.assetsChainId && transferInfo.assetsId === 1) { if (balanceInfo.balance < transferInfo.amount + newFee) { console.log("余额不足"); return; } inputs[0].amount = transferInfo.amount + newFee; if (!isMainNet(chainId)) { inputs[1].amount = newFee; } } else { if (localBalanceInfo.balance < transferInfo.fee) { console.log("该账户本链主资产不足够支付手续费!"); return; } if (transferInfo.assetsChainId === 2 && transferInfo.assetsId === 1) { if (mainNetBalanceInfo.balance < transferInfo.amount + newFee) { console.log("余额不足"); return; } inputs[0].amount = transferInfo.amount + newFee; inputs[1].amount = newFee; } else { inputs[1].amount = newFee; inputs[2].amount = newFee; } } tAssemble = await nuls.transactionAssemble(inputs, outputs, transferInfo.remark, 10); ctxSign = nuls.transactionSignature(pri, tAssemble); } else { ctxSign = nuls.transactionSignature(pri, tAssemble); } bw.writeBytesWithLength(pubHex); bw.writeBytesWithLength(ctxSign); if (!isMainNet(chainId)) { mainCtx.txData = tAssemble.getHash(); mainCtxSign = nuls.transactionSignature(pri, mainCtx); bw.writeBytesWithLength(pubHex); bw.writeBytesWithLength(mainCtxSign); } tAssemble.signatures = bw.getBufWriter().toBuffer(); let txHex = tAssemble.txSerialize().toString('hex'); let result = await sendCrossTx(txHex); console.log(result); if (result.success) { console.log(result.data.value); let results = await broadcastTx(txHex); if (results && results.value) { console.log("交易完成") } else { console.log("广播交易失败") } } else { console.log("验证交易失败:" + result.error) } } -------------------------------------------------------------------------------- /src/test/cryptoTest.js: -------------------------------------------------------------------------------- 1 | let expect = require('chai').expect; 2 | let eccrypto = require("../crypto/eciesCrypto"); 3 | 4 | let userPrivateKey = Buffer.from("1523eb8a85e8bb6641f8ae53c429811ede7ea588c4b8933fed796c667c203c06", "hex"); 5 | let userPublicKey = eccrypto.getPublic(userPrivateKey); 6 | 7 | describe("crypto", function () { 8 | 9 | it("whole encrypt success", async function () { 10 | let data = "Information:Modules \"nuls-base\", \"nuls-core-rockdb\", \"nuls-core-rpc\", \"nuls-base-api-provider\", \"nuls-base-protocol-update\" and 我们认为NFT的使用案例由个人拥有和交易,以及托运给第三方经纪人/钱包/拍卖商(“运营商”)。NFT可以代表对数字或实物资rebuilt due to project configuration/dependencies changes"; 11 | let bufferData = Buffer.from(data); 12 | let encrypted = await eccrypto.encrypt(userPublicKey, bufferData); 13 | console.info("encryptd data: ", encrypted.toString("hex")); 14 | }); 15 | 16 | it("whole decrypt success", async function () { 17 | let encrypted = Buffer.from("0451aa0e455d20a2ddeb9c4671b55738e980a615001b5c4b5bb83db94442375745a2e5eb26a6bb8f45aec6e19c617b3135f14384979ae4cf315ff352ead873534e000000000000000000000000000000008f1333c6b62b88af2f5f5bcad6712e3aa36eab3d2f01bcc9cceabd2fb1a1c353be94ae3fe5c7dd5b5c091c8228d61f39d8f252b67de04c55167e6369267b707bd805348b1d77307e523917cf94d1500bff50926169461dbfdce0a5740b7e92d187c0e2aefc45947220a69dbfb585eed565b51c477c0ae1e5a58e38902fc1fc058a481061a6c7916ebceee078f2328b1b37e4d96da8f6cae6d64ce3eb1ab58b261dcd81af4a8d488ec7267e502b97dd6de408fc12cc7bd9b70de9f20146b9122e0b817b934bfc90aa08d660705954e7e7d80f40a8fd2a8b4cdec4e6e229376b5f51f2c5f5f6c81d7b22ee5aebc0c350571ef179e46356dc9ceaaa34b65a762d934241d258a63ed9f9d98e01cd8c9a879dba2a0d2d5f147fabb5f398b975f56515ad1587655fcc592ad806e8b3abb5d00839b4ff76ff3cf5264a2beb9d4cb13382b22a3fe99700ca86ec97ab07c7e4682931bdd53669361fa62e0400e39ebc57ecafd44334de8e509cee5a2dca60ff8399f9a5511a4496ad0100f6acc2e0b85fc44c30065b7be1fd4cca58fad17caf3b4d1168fa4347ff6adf1c18169c83a8fdddfd07db26b792bca0ad990b02b42d644a3deb192afc586d87a3ead311077a5de95dc249f81133b749a548d3aeca51f06166c14d6a860061f214b18e55fa9d51e6ed00c9b2fa3272b280c1d892927bc6b1", "hex"); 18 | let decryptd = await eccrypto.decrypt(userPrivateKey, encrypted); 19 | console.info("decryptd data :", decryptd.toString()); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /src/test/dataOntoChain.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const {getNulsBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 3 | const sdk = require('../api/sdk'); 4 | 5 | let address = 'tNULSeBaMuG5b4KuWuSg8rvNPttqWThhFsH3ns'; 6 | let pri = "642d33a2fe29e40c6e5ee8aafd16da9699e1b9fbba45de7bb879831bed2cbd59"; 7 | //上链数据:NULS主网创世块hash 8 | let data = '8221e980cc9707b4fcf05ac79e70b8ac75f00550bb7da9292e6d6432a716ea88'; 9 | 10 | //调用 11 | transferTransaction(pri, address, data); 12 | 13 | /** 14 | * 基于转账交易的数据上链交易示例 15 | * @param pri 16 | * @param address 17 | * @param data 18 | * @returns {Promise} 19 | */ 20 | async function transferTransaction(pri, address, data) { 21 | let remark = '测试数据上链'; 22 | //获取余额和nonce 23 | const balanceInfo = await getNulsBalance(address); 24 | 25 | let pub = sdk.getPub(pri); 26 | 27 | let transferInfo = { 28 | fromAddress: address, 29 | assetsChainId: 2, 30 | assetsId: 1, 31 | amount: 0, 32 | fee: 100000 33 | }; 34 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 2); 35 | let tAssemble = [];//交易组装 36 | let txhex = "";//交易签名 37 | if (inOrOutputs.success) { 38 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 2); 39 | //获取手续费 40 | let newFee = countFee(tAssemble, 1); 41 | //手续费大于0.001的时候重新组装交易及签名 42 | if (transferInfo.fee !== newFee) { 43 | transferInfo.fee = newFee; 44 | inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 2); 45 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 2); 46 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 47 | } else { 48 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 49 | } 50 | } else { 51 | console.log(inOrOutputs.data) 52 | } 53 | console.log(txhex); 54 | let result = await validateTx(txhex); 55 | if (result.success) { 56 | console.log(result.data.value); 57 | let results = await broadcastTx(txhex); 58 | if (results && results.value) { 59 | console.log("交易完成") 60 | } else { 61 | console.log("广播交易失败") 62 | } 63 | } else { 64 | console.log("验证交易失败:" + result.error.message) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/deposit.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const {getNulsBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 3 | 4 | /** 5 | * @disc: 加入共识dome 6 | * @date: 2019-10-18 10:34 7 | * @author: Wave 8 | */ 9 | 10 | let pri = '411fa90f7161a20f4624a4f00167fac6d5afd97a7e6815f60e66106c559564a1'; 11 | let pub = '031c810153d633a5167ec629af771296bad4f26eacfe4034c978afee12b6c4fd44'; 12 | let fromAddress = "tNULSeBaMuBCG7NkSyufjE76CVbPQMrZ5Q1v3s"; 13 | let amount = 210000000000; 14 | let remark = 'deposit ....'; 15 | 16 | let deposit = { 17 | address: fromAddress, 18 | agentHash: 'd8b31649b8d2ccac2fd258787583017f98fc1e1be579298aae650cb9698845c9', 19 | deposit: 2010000000000 20 | }; 21 | //调用加入共识 22 | doit(pri, pub, fromAddress, 2, 1, amount, deposit); 23 | 24 | async function doit(pri, pub, fromAddress, assetsChainId, assetsId, amount, deposit) { 25 | const balanceInfo = await getNulsBalance(fromAddress); 26 | let transferInfo = { 27 | fromAddress: fromAddress, 28 | assetsChainId: assetsChainId, 29 | assetsId: assetsId, 30 | amount: amount, 31 | fee: 100000 32 | }; 33 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 5); 34 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 5, deposit); 35 | let txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 36 | //console.log(txhex); 37 | let result = await validateTx(txhex); 38 | if (result) { 39 | console.log(result.data.value); 40 | let results = await broadcastTx(txhex); 41 | if (results && result.data.value) { 42 | console.log("交易完成") 43 | } else { 44 | console.log("广播交易失败") 45 | } 46 | } else { 47 | console.log("验证交易失败") 48 | } 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/test/deserialize/test.js: -------------------------------------------------------------------------------- 1 | const Serializers = require("../../api/serializers"); 2 | const Block = require("../../model/block") 3 | const BufferReader = require("../../utils/bufferreader") 4 | 5 | //共识奖励+转账,1453110 6 | const blockhex = "4ab91a7d320b0b07b29536ec58c076ea7d3169d2c8592662f179f358c70036144ba5e7c1af3c19aa1b3c09ec8190b8b28d8baf789382a378f1f3109642e103622a0b585e362c1600020000005c5c3f00006f00580a585e150004000400500a00208632672517e468d1acdc6e59dd3e757138b8dbc908afb7f7c3daba90759d40c06c608a936d45b943dd821c393be73a53ce88585ccf18f93e8e1924dbd6f1ec9e30b0acafec2d78d32102f28feeaa3cd5b3d0ccde3389debbbc1268db317703750f756eaead92b3c23af546304402201339330f5adaab7163fa284456f07361cf2c29e8de2b5ee4bd9b360f1c6c577a02204aba70760fc5e4de2460bb6bdb1017f5a5e1116571c6cfbae17889760f51c90a01002a0b585e00008a000217010001474a63f8b2f0a999741c4fd162d430e17733f33b01000100a9e8810b00000000000000000000000000000000000000000000000000000000000000000000000017010001940c5646e9b680142d4452ec91ea7a0eeebe05d7010001007f580a00000000000000000000000000000000000000000000000000000000000000000000000000000200230b585e1262696e616e6365207769746864726177616c008c01170100013ba3e3c56062266262514c74fafb01852af99fec01000100e0b562910200000000000000000000000000000000000000000000000000000008dc1890d6baa257ad000117010001a9fa55a587f415bde2cc50469af2ee873322d5fa01000100402f61910200000000000000000000000000000000000000000000000000000000000000000000006921037af860c03801a7453c55fd2a7fe90c5081ac66db79b7a92139f320d4d60fc0bb463044022020731fb06b6452ae6ce67efe5334159f9008fcaa037e717f040774f7e8b4b75502205432dda224c6104aebde56875eec5ba1646eaaeae63f7482dce579c3ec13d79b"; 7 | 8 | 9 | let reader = new BufferReader(Buffer.from(blockhex, "hex"), 0); 10 | 11 | let block = new Block(reader); 12 | 13 | block.printInfo(); 14 | 15 | 16 | console.log('---------------------------------------------------------------------') 17 | console.log('Cursor::::' + reader.getCursor()) 18 | console.log('Total::::' + reader.getBuffer().length) 19 | 20 | 21 | let bw = new Serializers(); 22 | bw.getBufWriter().writeVarintNum(65536) 23 | var val = bw.getBufWriter().toBuffer().toString("hex") 24 | console.log(val) 25 | console.log(bw.getBufWriter().toBuffer()) -------------------------------------------------------------------------------- /src/test/deserialize/testCallContractDataHex.js: -------------------------------------------------------------------------------- 1 | const nuls = require("./../../index"); 2 | 3 | const hex = "010001707cb4da76399b3406babc98060e524295ddf7e3010002b9387225c04b17daedc4abec193965559fad75d10000000000000000000000000000000000000000000000000000000000000000ab510000000000001900000000000000087472616e73666572000201254e554c53643648676a534c4759456339455a566673566f72654e7862375a7037484d616e7801083434303030303030"; 4 | let hexInfo = nuls.contractDataParsing(hex); 5 | console.log(hexInfo.sender); 6 | console.log(JSON.stringify(hexInfo)); 7 | -------------------------------------------------------------------------------- /src/test/deserialize/testHex.js: -------------------------------------------------------------------------------- 1 | const nuls = require("./../../index"); 2 | 3 | // const txHex = "02004e1175600433333433008c0117020001f88d93a52edc7437da5e2977d27681f0fb1e6bab02000100a029e31100000000000000000000000000000000000000000000000000000000089159a7cf6f535de8000117020001ad3482b405ca6ba6aee19b3c7db9f4a016b457770200010000a3e11100000000000000000000000000000000000000000000000000000000000000000000000000"; 4 | const txHex = "0200211a7d6609636f696e2074657374008c0117020001f7ec6473df12e751d64cf20a8baa7edd50810f8102000100201d9a00000000000000000000000000000000000000000000000000000000000810c7c56b356608c7000117020001d24ac8859ded42e24659f3a953f009c908f1093e02000100809698000000000000000000000000000000000000000000000000000000000000000000000000006a2103958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3473045022008864c9df4d34fb95493348d06cecb86656055efd497f371b1cdbd146593fc21022100d941780b1bad9a54172e5a6926873ec819069efc3ed086fa45091f2293b50631"; 5 | let tx = nuls.hexParsing(txHex); 6 | console.log(tx) 7 | console.log(JSON.stringify(tx)) 8 | 9 | -------------------------------------------------------------------------------- /src/test/fee.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @disc: 使用方式:先组装交易,然后获取手续费,再把手续费增加到from中,然后对交易进行签名,请确认交易地址有足够的余额。 3 | * signatrueCount 签名数量、默认为1 4 | * @date: 2019-10-18 10:35 5 | * @author: Wave 6 | **/ 7 | export function countFee(tx, signatrueCount) { 8 | let txSize = tx.txSerialize().length;//后面花些时间把tx.size()方法实现后,可以用size() 9 | txSize += signatrueCount * 110; 10 | return 100000 * (txSize / 1024); 11 | } 12 | 13 | let a = { 14 | "chainId": 1, 15 | "assetId": 1, 16 | "mainChainId": 1, 17 | "mainAssetId": 1, 18 | "language": "zh-CHS", 19 | "encoding": "UTF-8", 20 | "keystoreFolder": "/keystore/backup", 21 | "dataPath":"/data", 22 | "blackHolePublicKey":"000000000000000000000000000000000000000000000000000000000000000000", 23 | "addressPrefix":"NULS" 24 | }; 25 | -------------------------------------------------------------------------------- /src/test/flash_test.js: -------------------------------------------------------------------------------- 1 | const BufferReader = require("../utils/bufferreader"); 2 | const txs = require("../model/txs"); 3 | const txsignatures = require("../model/txsignatures"); 4 | const nuls = require('../index'); 5 | const sdk = require("../api/sdk"); 6 | 7 | //todo 入参 8 | let txHex = ""; 9 | //todo 入参 10 | let prikeyHex = ""; 11 | // 解析交易 12 | let bufferReader = new BufferReader(Buffer.from(txHex, "hex"), 0); 13 | // 反序列回交易对象 14 | let tx = new txs.Transaction(); 15 | tx.parse(bufferReader); 16 | // 初始化签名对象 17 | let txSignData = new txsignatures.TransactionSignatures(); 18 | // 反序列化签名对象 19 | let reader = new BufferReader(tx.signatures, 0); 20 | txSignData.parse(reader); 21 | // 打印已签名地址 22 | let address = nuls.getAddressByPub(5, 1, txSignData.signatures[0].pubkey, 'TNVT'); 23 | console.log(address); 24 | //获取本账户公钥 25 | let pub = sdk.getPub(prikeyHex); 26 | // 签名 27 | let sigHex = sdk.signature(tx.getHash().toString("hex"), prikeyHex); 28 | let signValue = Buffer.from(sigHex, 'hex'); 29 | // 追加签名到对象中 30 | txSignData.addSign(Buffer.from(pub, "hex"), signValue); 31 | // 追加签名到交易中 32 | tx.signatures = txSignData.serialize(); 33 | //计算交易hash 34 | tx.calcHash(); 35 | console.log(tx.getHash().toString("hex")); 36 | // console.log(pub) 37 | // console.log(signValue) 38 | // 结果 39 | console.log(tx.txSerialize().toString("hex")); 40 | -------------------------------------------------------------------------------- /src/test/hash.js: -------------------------------------------------------------------------------- 1 | const sdk = require('../api/sdk'); 2 | 3 | let data = "0200b67f2d5d0672656d61726b008c01170200012a9af4ee49f4cb1ee84eafd42aec41bc04b28f7b02000100402a8648170000000000000000000000000000000000000000000000000000000800000000000000000001170200012a9af4ee49f4cb1ee84eafd42aec41bc04b28f7b0200010000e87648170000000000000000000000000000000000000000000000000000000000000000000000"; 4 | 5 | 6 | let result = sdk.getSha256Hex(data); 7 | 8 | console.log(sdk.getSha256Hex(result)); 9 | 10 | 11 | //验证签名是否正确 12 | 13 | 14 | let hashHex = "89f44d63bd3323f7830993418fa62442f7d1c445a775dc6b4e317ef889b7ddd1"; 15 | let signVal = "304502202670fd33a3df9200760fbec71bbdfa46f3e0dab21de1eb6c6a67958c18da9d29022100ab75ea2f44cea563370d8ce0a00e3f68d3c033db06edca755a2e9dc35653c653"; 16 | let pub = "033fb58fdd16e7c23b31a3f7fb3bdd41942e2db53092e7dd183c8fef8dafff1082"; 17 | 18 | let result1 = sdk.verifySign(hashHex, signVal, pub); 19 | console.log(result1) 20 | 21 | 22 | hashHex = "5ea8974bc3ad29a9af9035be47d3e6a4a5b505935658ff4234c60d795313b524"; 23 | signVal = "304502206eacf2bcea9baafed12a50b9017f4be1a6bdbfd6842ed7c86d57d5ac7a47ea29022100f4d31b3d4c78af110f0f481bedea44614642cf33d87325c8bc6342f4642127eb"; 24 | pub = "026f74d026c89f6f87ed88c7eeba6380bde58b8711f5481e6d99c63b110091663f"; 25 | 26 | result1 = sdk.verifySign(hashHex, signVal, pub); 27 | console.log(result1) -------------------------------------------------------------------------------- /src/test/importAddress.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | 3 | /** 4 | * @disc: 导入地址 dome 5 | * @date: 2019-10-18 10:36 6 | * @author: Wave 7 | */ 8 | 9 | let passWord = ''; 10 | const key = "00db591ead0fd6a43dbff1d8e996288572f92563117c81548d4e3428a5fa503af2"; 11 | try { 12 | const importAddress = nuls.importByKey(2, key, passWord, "tNULS"); 13 | console.log(importAddress); 14 | console.log(importAddress.address === 'tNULSeBaMuBCG7NkSyufjE76CVbPQMrZ5Q1v3s'); 15 | } catch (err) { 16 | console.log(err); 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test/newAddress.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | 3 | /** 4 | * @disc: 创建地址 dome 5 | * @date: 2019-10-18 10:36 6 | * @author: Wave 7 | */ 8 | 9 | let passWord = '';//密码为空 私钥会返回 10 | const newAddress = nuls.newAddress(100, passWord, 'XXX'); 11 | console.log(newAddress); 12 | 13 | //验证地址 14 | let result = nuls.verifyAddress(newAddress.address); 15 | console.log(result); 16 | 17 | //1.0与2.0私钥或公钥生成的地址是否相同 18 | /*let rest = nuls.addressEquals("TTarYnUfsftmm7DrStandCEdd4SNiELS", "tNULSeBaMoG1oaW1JZnh6Ly65Ttp6raeTFBfCG"); 19 | console.log(rest);*/ 20 | -------------------------------------------------------------------------------- /src/test/newAgent.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const {getNulsBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 3 | 4 | /** 5 | * @disc: 创建节点 dome 6 | * @date: 2019-10-18 10:37 7 | * @author: Wave 8 | */ 9 | 10 | let pri = '411fa90f7161a20f4624a4f00167fac6d5afd97a7e6815f60e66106c559564a1'; 11 | let pub = '031c810153d633a5167ec629af771296bad4f26eacfe4034c978afee12b6c4fd44'; 12 | let fromAddress = "tNULSeBaMuBCG7NkSyufjE76CVbPQMrZ5Q1v3s"; 13 | let amount = 2000100000000; 14 | let remark = 'new agent...'; 15 | 16 | let agent = { 17 | agentAddress: fromAddress, 18 | packingAddress: "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG", 19 | rewardAddress: fromAddress, 20 | commissionRate: 12, 21 | deposit: 2000100000000 22 | }; 23 | 24 | //调用新建节点 25 | newAgent(pri, pub, fromAddress, 2, 1, amount, agent); 26 | 27 | /** 28 | * 新建节点 29 | * @param pri 30 | * @param pub 31 | * @param fromAddress 32 | * @param assetsChainId 33 | * @param assetsId 34 | * @param amount 35 | * @param agent 36 | * @returns {Promise<*>} 37 | */ 38 | async function newAgent(pri, pub, fromAddress, assetsChainId, assetsId, amount, agent) { 39 | const balanceInfo = await getNulsBalance(fromAddress); 40 | let transferInfo = { 41 | fromAddress: fromAddress, 42 | assetsChainId: assetsChainId, 43 | assetsId: assetsId, 44 | amount: amount, 45 | fee: 100000 46 | }; 47 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 4); 48 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 4, agent); 49 | let txhex = await nuls.transactionSerialize(pri, pub,tAssemble); 50 | //console.log(txhex); 51 | let result = await validateTx(txhex); 52 | if (result) { 53 | console.log(result.data.value); 54 | let results = await broadcastTx(txhex); 55 | if (results && result.data.value) { 56 | console.log("交易完成") 57 | } else { 58 | console.log("广播交易失败") 59 | } 60 | } else { 61 | console.log("验证交易失败") 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/test/registercrosschain.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const sdk = require('../api/sdk'); 3 | const {getNulsBalance, countFee, validateTx, broadcastTx, mutiInputsOrOutputs} = require('./api/util'); 4 | 5 | /** 6 | * @disc:注册跨链交易 7 | * @date: 2019-10-17 15:50 8 | * @author: Wave 9 | */ 10 | 11 | let chain = { 12 | chainId: 99, 13 | addressType: "1",//1 使用NULS框架构建的链 生态内,2生态外" 14 | chainName: "test1", 15 | addressPrefix: "XXXX", 16 | magicNumber: 10066, 17 | supportInflowAsset: true, 18 | verifierList: ["XXXcA7kaeQMPaiRNPpQSEP8S8tNXDFeC5vnEy", "XXXcA7kaiK3YhCdSxfXaaffHupBDPjm3veiEE", "XXXcA7kaYY2QrRFX7Le9YdwtzQ9JvtRUU37bx"], 19 | minAvailableNodeNum: 3, 20 | maxSignatureCount: 200, 21 | signatureBFTRatio: 66 22 | }; 23 | let asset = { 24 | assetId: 1, 25 | symbol: "XXX", 26 | assetName: "XXX", 27 | initNumber: 10000000000000, 28 | decimalPlaces: 8 29 | }; 30 | 31 | let fromAddress = "tNULSeBaMpVdwtAD2k33tiCbEsPXhpV3E6Zvgp"; 32 | let pri = '4776e429194e9a1c0669a962df4b9f46745a19b2b6fa04e02304ce3ad54ad791'; 33 | 34 | //注册跨链交易 35 | registerChainAndAsset(pri, fromAddress, chain, asset); 36 | 37 | async function registerChainAndAsset(pri, address, chainInfo, assetInfo) { 38 | const balanceInfo = await getNulsBalance(address); 39 | if (!balanceInfo.nonce) { 40 | console.log("get balance failed!"); 41 | return; 42 | } 43 | let pub = sdk.getPub(pri); 44 | //跨链交易消耗3000nuls=1600转账+800锁定+600销毁 45 | let transferInfo = { 46 | assetsChainId: 2, 47 | assetsId: 1, 48 | fee: 100000, 49 | from: { 50 | fromAddress: address, 51 | amount: 300000000000 52 | }, 53 | to: [ 54 | {toAddress: "tNULSeBaMpQTyMygD2DLtW8pPBxHRqjjZqfyMh", amount: 160000000000}, 55 | {toAddress: address, amount: 80000000000, lockTime: -1}, 56 | { 57 | toAddress: sdk.getStringAddress(2, null, "000000000000000000000000000000000000000000000000000000000000000000", "tNULS"), 58 | amount: 60000000000 59 | } 60 | ] 61 | }; 62 | let inOrOutputs = await mutiInputsOrOutputs(transferInfo, balanceInfo, 11); 63 | let tAssemble = [];//交易组装 64 | let txhex = "";//交易签名 65 | if (inOrOutputs.success) { 66 | let txData = { 67 | address: address, 68 | chainInfo: chainInfo, 69 | assetInfo: assetInfo 70 | }; 71 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, '', 11, txData); 72 | //获取手续费 73 | let newFee = countFee(tAssemble, 1); 74 | //手续费大于0.001的时候重新组装交易及签名 75 | if (transferInfo.fee !== newFee) { 76 | transferInfo.fee = newFee; 77 | inOrOutputs = await mutiInputsOrOutputs(transferInfo, balanceInfo, 11); 78 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, '', 11, txData); 79 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 80 | } else { 81 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 82 | } 83 | console.log(inOrOutputs.data.inputs); 84 | console.log(inOrOutputs.data.outputs); 85 | } else { 86 | console.log(inOrOutputs.data); 87 | return; 88 | } 89 | console.log(txhex); 90 | let result = await validateTx(txhex); 91 | console.log(result); 92 | if (result.success) { 93 | console.log(result.data.value); 94 | let results = await broadcastTx(txhex); 95 | if (results && results.value) { 96 | console.log("交易完成") 97 | } else { 98 | console.log("广播交易失败") 99 | } 100 | } else { 101 | console.log("验证交易失败:" + result.error) 102 | } 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/test/setAlias.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const sdk = require('../api/sdk') 3 | const {getNulsBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 4 | 5 | /** 6 | * @disc: 设置别名 dome 7 | * @params: 8 | * @date: 2019-10-18 10:38 9 | * @author: Wave 10 | */ 11 | 12 | let pri = '4100e2f88c3dba08e5000ed3e8da1ae4f1e0041b856c09d35a26fb399550f530'; 13 | let pub = '020e19418ed26700b0dba720dcc95483cb4adb1b5f8a103818dab17d5b05231854'; 14 | let fromAddress = "tNULSeBaMu38g1vnJsSZUCwTDU9GsE5TVNUtpD"; 15 | //黑洞地址 16 | let toAddress = 'tNULSeBaMhZnRteniCy3UZqPjTbnWKBPHX1a5d'; 17 | let amount = 100000000; 18 | let remark = 'set alias....'; 19 | 20 | //调用设置别名 21 | setAlias(pri, pub, fromAddress, toAddress, 2, 1, amount, remark); 22 | 23 | /** 24 | * 设置别名 25 | * @param pri 26 | * @param pub 27 | * @param fromAddress 28 | * @param toAddress 29 | * @param assetsChainId 30 | * @param assetsId 31 | * @param amount 32 | * @param remark 33 | * @returns {Promise} 34 | */ 35 | async function setAlias(pri, pub, fromAddress, toAddress, assetsChainId, assetsId, amount, remark) { 36 | const balanceInfo = await getNulsBalance(fromAddress); 37 | let transferInfo = { 38 | fromAddress: fromAddress, 39 | toAddress: toAddress, 40 | assetsChainId: assetsChainId, 41 | assetsId: assetsId, 42 | amount: amount, 43 | fee: 100000 44 | }; 45 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 3); 46 | let aliasInfo = { 47 | fromAddress: fromAddress, 48 | alias: 'wave' 49 | }; 50 | //交易组装 51 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 3, aliasInfo); 52 | console.log(tAssemble); 53 | //获取hash 54 | let hash = await tAssemble.getHash(); 55 | console.log(hash); 56 | //交易签名 57 | let txSignature = await sdk.getSignData(hash.toString('hex'), pri); 58 | console.log(txSignature); 59 | //通过拼接签名、公钥获取HEX 60 | let signData = await sdk.appSplicingPub(txSignature.signValue, pub); 61 | tAssemble.signatures = signData; 62 | let txhex = tAssemble.txSerialize().toString("hex"); 63 | console.log(txhex.toString('hex')); 64 | 65 | /*let getHex = await sdk.appSplicingPub(txSignature); 66 | console.log(getHex); 67 | 68 | let txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 69 | console.log(txhex);*/ 70 | let result = await validateTx(txhex.toString('hex')); 71 | console.log(result); 72 | if (result) { 73 | console.log(result.data.value); 74 | let results = await broadcastTx(txhex); 75 | if (results && result.data.value) { 76 | console.log("交易完成") 77 | } else { 78 | console.log("广播交易失败") 79 | } 80 | } else { 81 | console.log("验证交易失败") 82 | } 83 | } 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/test/stopAgent.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const {getNulsBalance, countFee, inputsOrOutputs, validateTx, broadcastTx, agentDeposistList} = require('./api/util'); 3 | 4 | /** 5 | * @disc: 注销节点 dome 6 | * @date: 2019-10-18 10:38 7 | * @author: Wave 8 | */ 9 | 10 | let pri = '777e333556edb17564ea45f84dce0f5fbea884123924575213c7a30cb3c9375410'; 11 | let pub = '027d8d404b0aaa834491999a0212ef7e432da69c6462857566f80a2c81e259e7b2'; 12 | let fromAddress = "NULSd6HgfzPGhFsZX16hHgneY25YKs6v6LvmX"; 13 | let amount = 2000000000000; 14 | let remark = 'stop agent....'; 15 | 16 | //调用注销节点 17 | stopAgent(pri, pub, fromAddress, 1, 1, amount, '7018c41307132d3e4709c3f50bae235e6f028a267b291930520bdb25f9d24195'); 18 | 19 | /** 20 | * 注销节点 21 | * @param pri 22 | * @param pub 23 | * @param fromAddress 24 | * @param assetsChainId 25 | * @param assetsId 26 | * @param amount 27 | * @param agentHash 28 | * @returns {Promise} 29 | */ 30 | async function stopAgent(pri, pub, fromAddress, assetsChainId, assetsId, amount, agentHash) { 31 | const balanceInfo = await getNulsBalance(fromAddress); 32 | //console.log(balanceInfo); 33 | let transferInfo = { 34 | fromAddress: fromAddress, 35 | assetsChainId: assetsChainId, 36 | assetsId: assetsId, 37 | amount: amount, 38 | fee: 100000, 39 | depositHash: agentHash, 40 | }; 41 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 9); 42 | //console.log(inOrOutputs); 43 | let newInputs = inOrOutputs.data.inputs; 44 | //console.log(newInputs); 45 | let newOutputs = []; 46 | //console.log(newOutputs); 47 | const depositList = await agentDeposistList(agentHash); 48 | //console.log(depositList); 49 | //console.log(depositList); 50 | for (let itme of depositList.list) { 51 | newInputs.push({ 52 | address: itme.address, 53 | assetsChainId: assetsChainId, 54 | assetsId: assetsId, 55 | amount: itme.amount, 56 | locked: -1, 57 | nonce: itme.txHash.substring(agentHash.length - 16)//这里是hash的最后16个字符 58 | }); 59 | newOutputs.push({ 60 | address: itme.address, assetsChainId: assetsChainId, 61 | assetsId: assetsId, amount: itme.amount, lockTime: 0 62 | }); 63 | } 64 | let addressArr = []; 65 | let newOutputss = []; 66 | newOutputs.forEach(function (item) { 67 | let i; 68 | if ((i = addressArr.indexOf(item.address)) > -1) { 69 | //console.log(result, i); 70 | newOutputss[i].amount = Number(newOutputss[i].amount) + Number(item.amount); 71 | } else { 72 | addressArr.push(item.address); 73 | newOutputss.push({ 74 | address: item.address, 75 | amount: item.amount, 76 | assetsChainId: item.assetsChainId, 77 | assetsId: item.assetsId, 78 | lockTime: item.lockTime, 79 | }) 80 | } 81 | }); 82 | newOutputss.unshift(inOrOutputs.data.outputs[0]); 83 | 84 | //console.log(newInputs); 85 | //console.log(newOutputss); 86 | 87 | let tAssemble = await nuls.transactionAssemble(newInputs, newOutputss, remark, 9, agentHash); 88 | //console.log(tAssemble); 89 | let txhex = ''; 90 | //获取手续费 91 | let newFee = countFee(tAssemble, 1); 92 | //手续费大于0.001的时候重新组装交易及签名 93 | if (transferInfo.fee !== newFee) { 94 | transferInfo.fee = newFee; 95 | inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 9); 96 | newInputs = inOrOutputs.data.inputs; 97 | newOutputs = inOrOutputs.data.outputs; 98 | for (let itme of depositList.list) { 99 | newInputs.push({ 100 | address: itme.address, 101 | assetsChainId: assetsChainId, 102 | assetsId: assetsId, 103 | amount: itme.amount, 104 | locked: -1, 105 | nonce: itme.txHash.substring(agentHash.length - 16)//这里是hash的最后16个字符 106 | }); 107 | newOutputs.push({ 108 | address: itme.address, assetsChainId: assetsChainId, 109 | assetsId: assetsId, amount: itme.amount, lockTime: 0 110 | }); 111 | } 112 | tAssemble = await nuls.transactionAssemble(newInputs, newOutputs, remark, 9, agentHash); 113 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 114 | } else { 115 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 116 | } 117 | //console.log(txhex); 118 | let result = await validateTx(txhex); 119 | //console.log(result); 120 | if (result) { 121 | let results = await broadcastTx(txhex); 122 | //console.log(results); 123 | if (results && result.value) { 124 | console.log("交易完成") 125 | } else { 126 | console.log("广播交易失败") 127 | } 128 | } else { 129 | console.log("验证交易失败") 130 | } 131 | } 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/test/take.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const {getNulsBalance, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 3 | 4 | /** 5 | * @disc: 退出共识 dome 6 | * @date: 2019-10-18 10:39 7 | * @author: Wave 8 | */ 9 | 10 | let pri = '94d344417d6faa55e3017709dd6b837bac2bc1769e3a4b516ac9a981465ac03c'; 11 | let pub = '02403cb49ac24ff9555b073ce981e28bed5e81438b2c715a14d06bd248ea1d0091'; 12 | let fromAddress = "tNULSeBaMfwpGBmn8xuKABPWUbdtsM2cMoinnn"; 13 | let amount = 210000000000; 14 | let remark = 'niels test alias....'; 15 | 16 | //退出共识 17 | take(pri, pub, fromAddress, 2, 1, amount, 'f556c7d05dd30c1080759e88e5934ff8981df2bf0dabd287dfee63b490bece50'); 18 | 19 | /** 20 | * 退出共识 21 | * @param pri 22 | * @param pub 23 | * @param fromAddress 24 | * @param assetsChainId 25 | * @param assetsId 26 | * @param amount 27 | * @param depositHash 28 | * @returns {Promise} 29 | */ 30 | async function take(pri, pub, fromAddress, assetsChainId, assetsId, amount, depositHash) { 31 | const balanceInfo = await getNulsBalance(fromAddress); 32 | let transferInfo = { 33 | fromAddress: fromAddress, 34 | assetsChainId: assetsChainId, 35 | assetsId: assetsId, 36 | amount: amount, 37 | fee: 100000, 38 | depositHash: depositHash 39 | }; 40 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 6); 41 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.inputs, inOrOutputs.outputs, remark, 6, depositHash); 42 | let txhex = await nuls.transactionSerialize(pri, pub,tAssemble); 43 | //console.log(txhex); 44 | let result = await validateTx(txhex); 45 | if (result) { 46 | console.log(result.value); 47 | let results = await broadcastTx(txhex); 48 | if (results && result.value) { 49 | console.log("交易完成") 50 | } else { 51 | console.log("广播交易失败") 52 | } 53 | } else { 54 | console.log("验证交易失败") 55 | } 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/test/testAes.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const sdk = require('../api/sdk'); 3 | 4 | 5 | const prikeyhex = "x"; 6 | 7 | 8 | 9 | // let result = nuls.decrypteOfAES(prikeyhex,"jian1021!@#$") 10 | 11 | 12 | // console.log(result) 13 | 14 | 15 | console.log(nuls.getAddressByPub(9,1,"x","NERVE")) 16 | -------------------------------------------------------------------------------- /src/test/tradingOrder.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const sdk = require('../api/sdk') 3 | const {getBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 4 | 5 | /** 6 | * @disc: 创建交易对 dome 7 | * @params: 8 | * @date: 2019-12-9 10:38 9 | * @author: vivi 10 | */ 11 | 12 | let pri = '4100e2f88c3dba08e5000ed3e8da1ae4f1e0041b856c09d35a26fb399550f530'; 13 | let pub = '020e19418ed26700b0dba720dcc95483cb4adb1b5f8a103818dab17d5b05231854'; 14 | let address = "tNULSeBaMu38g1vnJsSZUCwTDU9GsE5TVNUtpD"; 15 | let remark = 'create tradingOrder....'; 16 | let txType = 29; 17 | let fee = 100000; //手续费 18 | 19 | let defaultAsset = { //本链默认资产,用于生成手续费 20 | assetsChainId: 2, 21 | assetsId: 1 22 | }; 23 | 24 | let tradingOrderInfo = { 25 | tradingHash: '2560584b3b33df9676f86230846e666fd645696129799d77ee043269f614862c', //交易对hash 26 | address: address, //挂单委托人 27 | orderType: 1, //委托挂单类型 1:买单,2:卖单 28 | assetsChainId: 2, 29 | assetsId: 1, 30 | amount: 10000000000, //挂单金额 31 | price: 10000000, //单价 32 | feeAddress: config.feeAddress, 33 | feeScale: config.feeScale 34 | }; 35 | 36 | //调用委托挂单 37 | tradingOrder(tradingOrderInfo); 38 | 39 | /** 40 | * 委托挂单 41 | * @param pri 42 | * @param pub 43 | * @param fromAddress 44 | * @param toAddress 45 | * @param assetsChainId 46 | * @param assetsId 47 | * @param amount 48 | * @param remark 49 | * @returns {Promise} 50 | */ 51 | async function tradingOrder(tradingOrderInfo) { 52 | let inOrOutputs = await createCoinData(tradingOrderInfo); 53 | 54 | //交易组装 55 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, txType, tradingOrderInfo); 56 | console.log(tAssemble); 57 | //获取hash 58 | let hash = await tAssemble.getHash(); 59 | console.log(hash); 60 | //交易签名 61 | let txSignature = await sdk.getSignData(hash.toString('hex'), pri); 62 | console.log(txSignature); 63 | //通过拼接签名、公钥获取HEX 64 | let signData = await sdk.appSplicingPub(txSignature.signValue, pub); 65 | tAssemble.signatures = signData; 66 | let txhex = tAssemble.txSerialize().toString("hex"); 67 | console.log(txhex.toString('hex')); 68 | } 69 | 70 | async function createCoinData(tradingOrderInfo) { 71 | const balanceInfo = await getBalance(defaultAsset.assetsChainId, tradingOrderInfo.assetsChainId, tradingOrderInfo.assetsId, tradingOrderInfo.address); 72 | let inputs = [], outputs = []; 73 | let input = { 74 | address: tradingOrderInfo.address, 75 | assetsChainId: tradingOrderInfo.assetsChainId, 76 | assetsId: tradingOrderInfo.assetsId, 77 | amount: tradingOrderInfo.amount, 78 | locked: 0, 79 | nonce: balanceInfo.nonce 80 | }; 81 | //判断用户的挂单委托资产是否是本链的默认资产 82 | if (tradingOrderInfo.assetsChainId === defaultAsset.assetsChainId && tradingOrderInfo.assetsId === defaultAsset.assetsId) { 83 | //如果是,生成input的时候,将委托金额和手续费一起收 84 | input.amount += fee; 85 | inputs.push(input); 86 | } else { 87 | //如果不是要额外收取手续费 88 | inputs.push(input); 89 | const balanceInfo = await getBalance(defaultAsset.assetsChainId, defaultAsset.assetsChainId, defaultAsset.assetsId, tradingOrderInfo.address); 90 | inputs.push({ 91 | address: tradingOrderInfo.address, 92 | assetsChainId: tradingOrderInfo.assetsChainId, 93 | assetsId: tradingOrderInfo.assetsId, 94 | amount: fee, 95 | locked: 0, 96 | nonce: balanceInfo.nonce 97 | }); 98 | } 99 | 100 | outputs.push({ 101 | address: tradingOrderInfo.address, 102 | assetsChainId: tradingOrderInfo.assetsChainId, 103 | assetsId: tradingOrderInfo.assetsId, 104 | amount: tradingOrderInfo.amount, 105 | lockTime: -2 106 | }); 107 | return {success: true, data: {inputs: inputs, outputs: outputs}}; 108 | } 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/test/tradingOrderCancel.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const sdk = require('../api/sdk'); 3 | 4 | /** 5 | * @disc: 撤销委托挂单 dome 6 | * @date: 2019-12-9 10:38 7 | * @author: vivi 8 | */ 9 | 10 | let pri = '9ce21dad67e0f0af2599b41b515a7f7018059418bab892a7b68f283d489abc4b'; 11 | let pub = '03958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3'; 12 | let address = "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG"; 13 | let remark = 'cancel tradingOrder....'; 14 | let txType = 30; 15 | let fee = 100000; //手续费 16 | //本链默认资产,用于生成手续费 17 | let defaultAsset = {assetsChainId: 2, assetsId: 1}; 18 | 19 | //正常情况,这个数据是通过查询orderHash的nonce值接口查询到 20 | let tradingOrderInfo = { 21 | orderHash: 'f4ef24c225cc2af33902a3f7d147760d21407039ee98ec6dd74303f969171a5d', //委托挂单hash 22 | address: address, //撤销挂单委托人 23 | orderType: 1, //委托挂单类型 1:买单,2:卖单 24 | nonce: "69db314e5fd02b6b",//通过解决接口查询nonce 25 | leftAmount: 88700391787 //撤销金额 26 | 27 | }; 28 | 29 | //正常情况,这个数据是通过交易对详情接口查询出来的 30 | let coinTrading = { 31 | baseAssetChainId: 2, 32 | baseAssetId: 2, 33 | quoteAssetChainId: 2, 34 | quoteAssetId: 1 35 | }; 36 | 37 | //调用委托挂单 38 | tradingOrderCancel(tradingOrderInfo); 39 | 40 | /** 41 | * 委托挂单 42 | * @param tradingOrderInfo 43 | * @returns {Promise} 44 | */ 45 | async function tradingOrderCancel(tradingOrderInfo) { 46 | let inOrOutputs = await createCoinData(tradingOrderInfo, coinTrading); 47 | //交易组装 48 | let tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, txType, tradingOrderInfo); 49 | console.log(tAssemble); 50 | //获取hash 51 | let hash = await tAssemble.getHash(); 52 | console.log(hash); 53 | //交易签名 54 | let txSignature = await sdk.getSignData(hash.toString('hex'), pri); 55 | console.log(txSignature); 56 | //通过拼接签名、公钥获取HEX 57 | let signData = await sdk.appSplicingPub(txSignature.signValue, pub); 58 | tAssemble.signatures = signData; 59 | let txhex = tAssemble.txSerialize().toString("hex"); 60 | console.log(txhex.toString('hex')); 61 | } 62 | 63 | async function createCoinData(tradingOrderInfo, coinTrading) { 64 | let inputs = [], outputs = []; 65 | //首先通过订单信息组装解锁from 66 | let orderInput = { 67 | address: tradingOrderInfo.address, 68 | assetsChainId: coinTrading.baseAssetChainId, 69 | assetsId: coinTrading.baseAssetId, 70 | amount: tradingOrderInfo.leftAmount, 71 | locked: -1, 72 | nonce: tradingOrderInfo.nonce 73 | }; 74 | if (tradingOrderInfo.type === 1) { 75 | orderInput.assetsChainId = coinTrading.quoteAssetChainId; 76 | orderInput.assetsId = coinTrading.quoteAssetId; 77 | } 78 | inputs.push(orderInput); 79 | 80 | //如果手续费不足,需要添加手续费 81 | if (orderInput.assetsChainId !== defaultAsset.assetsChainId || orderInput.assetsId !== defaultAsset.assetsId || orderInput.amount < fee) { 82 | //通过获取用户当前余额组装手续费from 83 | // const balanceInfo = await getBalance(defaultAsset.assetsChainId, defaultAsset.assetsChainId, defaultAsset.assetsId, tradingOrderInfo.address); 84 | inputs.push({ 85 | address: tradingOrderInfo.address, 86 | assetsChainId: defaultAsset.assetsChainId, 87 | assetsId: defaultAsset.assetsId, 88 | amount: fee, 89 | locked: 0, 90 | nonce: "85e00519bbb5f5d8" 91 | }); 92 | } 93 | 94 | //组装to 95 | if (orderInput.assetsChainId !== defaultAsset.assetsChainId || orderInput.assetsId !== defaultAsset.assetsId || orderInput.amount < fee) { 96 | outputs.push({ 97 | address: tradingOrderInfo.address, 98 | assetsChainId: orderInput.assetsChainId, 99 | assetsId: orderInput.assetsId, 100 | amount: orderInput.amount, 101 | lockTime: 0 102 | }); 103 | } else { 104 | outputs.push({ 105 | address: tradingOrderInfo.address, 106 | assetsChainId: orderInput.assetsChainId, 107 | assetsId: orderInput.assetsId, 108 | amount: orderInput.amount - fee, 109 | lockTime: 0 110 | }); 111 | } 112 | 113 | return {success: true, data: {inputs: inputs, outputs: outputs}}; 114 | } 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/test/transfer.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | const txs = require('../model/txs'); 3 | const BufferReader = require("../utils/bufferreader"); 4 | const {getNulsBalance, countFee, inputsOrOutputs, validateTx, broadcastTx} = require('./api/util'); 5 | 6 | /** 7 | * @disc: 转账 dome 8 | * @date: 2019-10-18 10:40 9 | * @author: Wave 10 | */ 11 | 12 | let pri = 'x'; 13 | let pub = '03958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3'; 14 | let fromAddress = "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG"; 15 | let toAddress = 'tNULSeBaMsvfuGcosTR5dedtk8ksdfarrQWz3X'; 16 | let amount = 10000000; 17 | let remark = 'coin test'; 18 | //调用 19 | // transferTransaction(pri, pub, fromAddress, toAddress, 2, 1, amount, remark); 20 | 21 | /** 22 | * 转账交易 23 | * @param pri 24 | * @param pub 25 | * @param fromAddress 26 | * @param toAddress 27 | * @param assetsChainId 28 | * @param assetsId 29 | * @param amount 30 | * @param remark 31 | * @returns {Promise} 32 | */ 33 | async function transferTransaction(pri, pub, fromAddress, toAddress, assetsChainId, assetsId, amount, remark) { 34 | const balanceInfo = await getNulsBalance(fromAddress); 35 | 36 | let transferInfo = { 37 | fromAddress: fromAddress, 38 | toAddress: toAddress, 39 | assetsChainId: assetsChainId, 40 | assetsId: assetsId, 41 | amount: amount, 42 | fee: 100000 43 | }; 44 | let inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 2); 45 | let tAssemble = [];//交易组装 46 | let txhex = "";//交易签名 47 | if (inOrOutputs.success) { 48 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 2); 49 | //获取手续费 50 | let newFee = countFee(tAssemble, 1); 51 | //手续费大于0.001的时候重新组装交易及签名 52 | if (transferInfo.fee !== newFee) { 53 | transferInfo.fee = newFee; 54 | inOrOutputs = await inputsOrOutputs(transferInfo, balanceInfo, 2); 55 | tAssemble = await nuls.transactionAssemble(inOrOutputs.data.inputs, inOrOutputs.data.outputs, remark, 2); 56 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 57 | } else { 58 | txhex = await nuls.transactionSerialize(pri, pub, tAssemble); 59 | } 60 | } else { 61 | console.log(inOrOutputs.data) 62 | } 63 | console.log(txhex); 64 | let result = await validateTx(txhex); 65 | if (result.success) { 66 | console.log(result.data.value); 67 | let results = await broadcastTx(txhex); 68 | if (results && results.value) { 69 | console.log("交易完成") 70 | } else { 71 | console.log("广播交易失败") 72 | } 73 | } else { 74 | console.log("验证交易失败:" + result.error) 75 | } 76 | } 77 | 78 | let hex = "02005fd2a96700008c0117020001f7ec6473df12e751d64cf20a8baa7edd50810f8102000100a0b33201000000000000000000000000000000000000000000000000000000000811f5e4619e0a12c2000117020001c712dcb7ad82a943470a9a23fae87c50068e465602000100002d310100000000000000000000000000000000000000000000000000000000000000000000000000"; 79 | // let tx = new txs.Transaction(); 80 | // let bufferReader = new BufferReader(Buffer.from(hex, "hex"), 0); 81 | // tx.parse(bufferReader); 82 | 83 | // let signedTx = nuls.transactionSerialize(pri, pub, tx); 84 | // console.log(signedTx); 85 | console.log(nuls.signTxHex(pri, pub, hex)); 86 | 87 | -------------------------------------------------------------------------------- /src/test/v1Tov2.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../api/sdk'); 2 | 3 | /** 4 | * @disc: 验证V1.0与V2.0地址是否相同 dome 5 | * @date: 2019-10-18 10:40 6 | * @author: Wave 7 | */ 8 | 9 | let addressV2 = nuls.addressV1ToV2("TTarKL8DjsoXmn2EAYTnzC5KK8oxNULS",1); 10 | console.log(addressV2); 11 | addressV2 = nuls.addressV1ToV2("Nsdwnd4auFisFJKU6iDvBxTdPkeg8qkB",1); 12 | console.log(addressV2); 13 | -------------------------------------------------------------------------------- /src/test/verifyAddress.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | 3 | /** 4 | * @disc: 地址验证 dome 5 | * @date: 2019-10-18 10:41 6 | * @author: Wave 7 | */ 8 | 9 | let address = 'NULSd6Hgam8YajetEDnCoJBdEFkMNP41PfH7y'; 10 | console.log(nuls.verifyAddress(address)); 11 | -------------------------------------------------------------------------------- /src/test/verifyProgramEncodePacked.js: -------------------------------------------------------------------------------- 1 | const nuls = require('../index'); 2 | 3 | var txKey = "b03858bb-c265-4e2d-b383-df7a4c4a87d5"; 4 | var sender = "tNULSeBaMoixxbUovqmzPyJ2AwYFAX2evKbuy9"; 5 | var nulsAmount = "20000000"; 6 | var tokenAmount = "0"; 7 | var assetKey = ""; 8 | var receiver = "tNULSeBaMnrs6JKrCy6TQdzYJZkMZJDng7QAsD"; 9 | 10 | function testEncode() { 11 | let args = [txKey, sender, nulsAmount, tokenAmount, assetKey, receiver]; 12 | let result = nuls.programEncodePacked(args); 13 | console.log('result', result); 14 | } 15 | 16 | function testDecode() { 17 | let args = [txKey, sender, nulsAmount, tokenAmount, assetKey, receiver]; 18 | let result = nuls.programEncodePacked(args); 19 | let parseResult = nuls.parseProgramEncodePacked(result); 20 | console.log('parseResult', parseResult); 21 | } 22 | testEncode(); 23 | 24 | const Signature = require('elliptic/lib/elliptic/ec/signature'); 25 | const signature = { 26 | r: 'bb09696750985b79948be8ec8f975aa2078ff74dbae1eb3a8dd3ec5673d68856', 27 | s: '502696adf22e6143aac3b3c9fd0c49c6a2210aaa3f8143c9b10b90194477d88d' 28 | }; 29 | 30 | // 创建 Signature 对象 31 | const sigObj = new Signature(signature); 32 | 33 | // 转换为 DER 格式 34 | const derSignature = sigObj.toDER(); 35 | 36 | // 输出 DER 格式化的签名 37 | console.log('DER-formatted signature:', Buffer.from(derSignature).toString('hex')); 38 | 39 | -------------------------------------------------------------------------------- /src/test/verifySig.js: -------------------------------------------------------------------------------- 1 | const sdk = require('../api/sdk'); 2 | var secp256k1 = require("secp256k1"); 3 | var rs = require('jsrsasign/lib/jsrsasign.js'); 4 | 5 | //验证签名是否正确 6 | 7 | let account = { 8 | pri: 9 | '5968bbe187f97d78ea93413b083acbecdba1db61e3beb3f0c5e10238fe2dbf5f', 10 | pub: 11 | '04b0358da1571511fb24d078746db64de1c90ec64db9840142b5680201ca80d747970eb8d4e9c2c6e1611704a441e002feddc7074ca5b630ef22259a9d7cc862b0', 12 | address: 'XXXcA7kaimujixnBjjya8BLkPuKPijSv5yxpJ' 13 | } 14 | ; 15 | 16 | // 30440220 17 | // hello 18 | let hashHex = dataToHex("hello"); 19 | 20 | let signVal = sdk.signature(hashHex, account.pri); 21 | 22 | let publickey = secp256k1.publicKeyConvert(Buffer.from(account.pub, "hex"), false); 23 | 24 | let result1 = sdk.verifySign(hashHex, signVal, publickey.toString('hex')); 25 | 26 | console.log(Buffer.from(hashHex, "hex").toString("hex") == ''); 27 | console.log(Buffer.from(hashHex, "hex").toString("hex") === hashHex); 28 | console.log(Buffer.from(hashHex, "hex").toString("hex")); 29 | console.log(Buffer.from(hashHex, "utf8").toString("hex")); 30 | console.log(signVal); 31 | console.log(result1); 32 | console.log(account.pri.length); 33 | 34 | function dataToHex(data) { 35 | let _data = Buffer.from(data, "hex").toString("hex"); 36 | let isHex = _data != '' && _data === data; 37 | if (isHex) { 38 | return data; 39 | } 40 | return Buffer.from(data, "utf8").toString("hex"); 41 | } 42 | console.log('sdk.verifySign', sdk.verifySign( 43 | hashHex, 44 | '304502200dfed1d5b45e706b2c7edbca9e19a3c681e41c83b293511a0846541c670dabb9022100fa597d4ad69a9f7ba1b2026e6e6fe2657019448ec6bc964da93d5eec1190259d', 45 | '0347ede10670ddbbfea359242673169528d184f8ef2e586c15d686aa49dddc555f')); 46 | 47 | 48 | function dataToHex1(data) { 49 | try { 50 | return Buffer.from(data, "hex").toString("hex"); 51 | } catch (e) { 52 | return Buffer.from(data, "utf8").toString("hex"); 53 | } 54 | } 55 | 56 | function dataToHex2(data) { 57 | try { 58 | let _data = Buffer.from(data, "hex").toString("hex"); 59 | let isHex = _data != '' && _data === data; 60 | if (isHex) { 61 | return data; 62 | } 63 | return Buffer.from(data, "utf8").toString("hex"); 64 | } catch (e) { 65 | return Buffer.from(data, "utf8").toString("hex"); 66 | } 67 | } 68 | 69 | console.log(dataToHex("30440220")); 70 | console.log(dataToHex("hi")); 71 | console.log('sdk.verifySign', sdk.verifySign( 72 | hashHex, 73 | '3045022100d624826b02c5d01203b93847315e3a68026217d3c1af49f2676762a81d3da2e1022008aafb78b79e4f28197e890add5248db2dee06057fd96485030514efbc27911a', 74 | '0347ede10670ddbbfea359242673169528d184f8ef2e586c15d686aa49dddc555f')); 75 | 76 | var testSig = function () { 77 | let hash = '63a1802f22fd9b7bd9663317649f57af2dd7a2f1deee82e4d6028d62cdbd57b5'; 78 | let pri = '00db591ead0fd6a43dbff1d8e996288572f92563117c81548d4e3428a5fa503af2'; 79 | 80 | let signVal = sdk.signature(hashHex, pri); 81 | let pub = sdk.getPub(pri); 82 | 83 | let result = { 84 | "pubkey": pub, 85 | "signData": signVal 86 | }; 87 | console.log(result); 88 | } 89 | // testSig(); 90 | -------------------------------------------------------------------------------- /src/utils/bn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var $ = require('./preconditions'); 5 | var _ = require('lodash'); 6 | 7 | var reversebuf = function(buf) { 8 | var buf2 = Buffer.alloc(buf.length); 9 | for (var i = 0; i < buf.length; i++) { 10 | buf2[i] = buf[buf.length - 1 - i]; 11 | } 12 | return buf2; 13 | }; 14 | 15 | BN.Zero = new BN(0); 16 | BN.One = new BN(1); 17 | BN.Minus1 = new BN(-1); 18 | 19 | BN.fromNumber = function(n) { 20 | $.checkArgument(_.isNumber(n)); 21 | return new BN(n); 22 | }; 23 | 24 | BN.fromString = function(str, base) { 25 | $.checkArgument(_.isString(str)); 26 | return new BN(str, base); 27 | }; 28 | 29 | BN.fromBuffer = function(buf, opts) { 30 | if (typeof opts !== 'undefined' && opts.endian === 'little') { 31 | buf = reversebuf(buf); 32 | } 33 | var hex = buf.toString('hex'); 34 | var bn = new BN(hex, 16); 35 | return bn; 36 | }; 37 | 38 | /** 39 | * Instantiate a BigNumber from a "signed magnitude buffer" 40 | * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative)) 41 | */ 42 | BN.fromSM = function(buf, opts) { 43 | var ret; 44 | if (buf.length === 0) { 45 | return BN.fromBuffer(Buffer.from([0])); 46 | } 47 | 48 | var endian = 'big'; 49 | if (opts) { 50 | endian = opts.endian; 51 | } 52 | if (endian === 'little') { 53 | buf = reversebuf(buf); 54 | } 55 | 56 | if (buf[0] & 0x80) { 57 | buf[0] = buf[0] & 0x7f; 58 | ret = BN.fromBuffer(buf); 59 | ret.neg().copy(ret); 60 | } else { 61 | ret = BN.fromBuffer(buf); 62 | } 63 | return ret; 64 | }; 65 | 66 | 67 | BN.prototype.toNumber = function() { 68 | return parseInt(this.toString(10), 10); 69 | }; 70 | 71 | BN.prototype.toBuffer = function(opts) { 72 | var buf, hex; 73 | if (opts && opts.size) { 74 | hex = this.toString(16, 2); 75 | var natlen = hex.length / 2; 76 | buf = Buffer.from(hex, 'hex'); 77 | 78 | if (natlen === opts.size) { 79 | buf = buf; 80 | } else if (natlen > opts.size) { 81 | buf = BN.trim(buf, natlen); 82 | } else if (natlen < opts.size) { 83 | buf = BN.pad(buf, natlen, opts.size); 84 | } 85 | } else { 86 | hex = this.toString(16, 2); 87 | buf = Buffer.from(hex, 'hex'); 88 | } 89 | 90 | if (typeof opts !== 'undefined' && opts.endian === 'little') { 91 | buf = reversebuf(buf); 92 | } 93 | 94 | return buf; 95 | }; 96 | 97 | BN.prototype.toSMBigEndian = function() { 98 | var buf; 99 | if (this.cmp(BN.Zero) === -1) { 100 | buf = this.neg().toBuffer(); 101 | if (buf[0] & 0x80) { 102 | buf = Buffer.concat([Buffer.from([0x80]), buf]); 103 | } else { 104 | buf[0] = buf[0] | 0x80; 105 | } 106 | } else { 107 | buf = this.toBuffer(); 108 | if (buf[0] & 0x80) { 109 | buf = Buffer.concat([Buffer.from([0x00]), buf]); 110 | } 111 | } 112 | 113 | if (buf.length === 1 & buf[0] === 0) { 114 | buf = Buffer.from([]); 115 | } 116 | return buf; 117 | }; 118 | 119 | BN.prototype.toSM = function(opts) { 120 | var endian = opts ? opts.endian : 'big'; 121 | var buf = this.toSMBigEndian(); 122 | 123 | if (endian === 'little') { 124 | buf = reversebuf(buf); 125 | } 126 | return buf; 127 | }; 128 | 129 | /** 130 | * Create a BN from a "ScriptNum": 131 | * This is analogous to the constructor for CScriptNum in bitcoind. Many ops in 132 | * bitcoind's script interpreter use CScriptNum, which is not really a proper 133 | * bignum. Instead, an error is thrown if trying to input a number bigger than 134 | * 4 bytes. We copy that behavior here. A third argument, `size`, is provided to 135 | * extend the hard limit of 4 bytes, as some usages require more than 4 bytes. 136 | */ 137 | BN.fromScriptNumBuffer = function(buf, fRequireMinimal, size) { 138 | var nMaxNumSize = size || 4; 139 | $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow')); 140 | if (fRequireMinimal && buf.length > 0) { 141 | // Check that the number is encoded with the minimum possible 142 | // number of bytes. 143 | // 144 | // If the most-significant-byte - excluding the sign bit - is zero 145 | // then we're not minimal. Note how this test also rejects the 146 | // negative-zero encoding, 0x80. 147 | if ((buf[buf.length - 1] & 0x7f) === 0) { 148 | // One exception: if there's more than one byte and the most 149 | // significant bit of the second-most-significant-byte is set 150 | // it would conflict with the sign bit. An example of this case 151 | // is +-255, which encode to 0xff00 and 0xff80 respectively. 152 | // (big-endian). 153 | if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) { 154 | throw new Error('non-minimally encoded script number'); 155 | } 156 | } 157 | } 158 | return BN.fromSM(buf, { 159 | endian: 'little' 160 | }); 161 | }; 162 | 163 | /** 164 | * The corollary to the above, with the notable exception that we do not throw 165 | * an error if the output is larger than four bytes. (Which can happen if 166 | * performing a numerical operation that results in an overflow to more than 4 167 | * bytes). 168 | */ 169 | BN.prototype.toScriptNumBuffer = function() { 170 | return this.toSM({ 171 | endian: 'little' 172 | }); 173 | }; 174 | 175 | BN.trim = function(buf, natlen) { 176 | return buf.slice(natlen - buf.length, buf.length); 177 | }; 178 | 179 | BN.pad = function(buf, natlen, size) { 180 | var rbuf = Buffer.alloc(size); 181 | for (var i = 0; i < buf.length; i++) { 182 | rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]; 183 | } 184 | for (i = 0; i < size - natlen; i++) { 185 | rbuf[i] = 0; 186 | } 187 | return rbuf; 188 | }; 189 | 190 | module.exports = BN; 191 | -------------------------------------------------------------------------------- /src/utils/buffer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var buffer = require('buffer'); 4 | var assert = require('assert'); 5 | 6 | var js = require('./js'); 7 | var $ = require('./preconditions'); 8 | 9 | function equals(a, b) { 10 | if (a.length !== b.length) { 11 | return false; 12 | } 13 | var length = a.length; 14 | for (var i = 0; i < length; i++) { 15 | if (a[i] !== b[i]) { 16 | return false; 17 | } 18 | } 19 | return true; 20 | } 21 | 22 | module.exports = { 23 | /** 24 | * Fill a buffer with a value. 25 | * 26 | * @param {Buffer} buffer 27 | * @param {number} value 28 | * @return {Buffer} 29 | */ 30 | fill: function fill(buffer, value) { 31 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 32 | $.checkArgumentType(value, 'number', 'value'); 33 | var length = buffer.length; 34 | for (var i = 0; i < length; i++) { 35 | buffer[i] = value; 36 | } 37 | return buffer; 38 | }, 39 | 40 | /** 41 | * Return a copy of a buffer 42 | * 43 | * @param {Buffer} original 44 | * @return {Buffer} 45 | */ 46 | copy: function(original) { 47 | var buffer = Buffer.alloc(original.length); 48 | original.copy(buffer); 49 | return buffer; 50 | }, 51 | 52 | /** 53 | * Returns true if the given argument is an instance of a buffer. Tests for 54 | * both node's Buffer and Uint8Array 55 | * 56 | * @param {*} arg 57 | * @return {boolean} 58 | */ 59 | isBuffer: function isBuffer(arg) { 60 | return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array; 61 | }, 62 | 63 | /** 64 | * Returns a zero-filled byte array 65 | * 66 | * @param {number} bytes 67 | * @return {Buffer} 68 | */ 69 | emptyBuffer: function emptyBuffer(bytes) { 70 | $.checkArgumentType(bytes, 'number', 'bytes'); 71 | var result = new buffer.Buffer(bytes); 72 | for (var i = 0; i < bytes; i++) { 73 | result.write('\0', i); 74 | } 75 | return result; 76 | }, 77 | 78 | /** 79 | * Concatenates a buffer 80 | * 81 | * Shortcut for buffer.Buffer.concat 82 | */ 83 | concat: buffer.Buffer.concat, 84 | 85 | equals: equals, 86 | equal: equals, 87 | 88 | /** 89 | * Transforms a number from 0 to 255 into a Buffer of size 1 with that value 90 | * 91 | * @param {number} integer 92 | * @return {Buffer} 93 | */ 94 | integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { 95 | $.checkArgumentType(integer, 'number', 'integer'); 96 | return new buffer.Buffer([integer & 0xff]); 97 | }, 98 | 99 | /** 100 | * Transform a 4-byte integer into a Buffer of length 4. 101 | * 102 | * @param {number} integer 103 | * @return {Buffer} 104 | */ 105 | integerAsBuffer: function integerAsBuffer(integer) { 106 | $.checkArgumentType(integer, 'number', 'integer'); 107 | var bytes = []; 108 | bytes.push((integer >> 24) & 0xff); 109 | bytes.push((integer >> 16) & 0xff); 110 | bytes.push((integer >> 8) & 0xff); 111 | bytes.push(integer & 0xff); 112 | return Buffer.from(bytes); 113 | }, 114 | 115 | /** 116 | * Transform the first 4 values of a Buffer into a number, in little endian encoding 117 | * 118 | * @param {Buffer} buffer 119 | * @return {number} 120 | */ 121 | integerFromBuffer: function integerFromBuffer(buffer) { 122 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 123 | return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; 124 | }, 125 | 126 | /** 127 | * Transforms the first byte of an array into a number ranging from -128 to 127 128 | * @param {Buffer} buffer 129 | * @return {number} 130 | */ 131 | integerFromSingleByteBuffer: function integerFromBuffer(buffer) { 132 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 133 | return buffer[0]; 134 | }, 135 | 136 | /** 137 | * Transforms a buffer into a string with a number in hexa representation 138 | * 139 | * Shorthand for buffer.toString('hex') 140 | * 141 | * @param {Buffer} buffer 142 | * @return {string} 143 | */ 144 | // bufferToHex: function bufferToHex(buffer) { 145 | // $.checkArgumentType(buffer, 'Buffer', 'buffer'); 146 | // return buffer.toString('hex'); 147 | // }, 148 | 149 | /** 150 | * Reverse a buffer 151 | * @param {Buffer} param 152 | * @return {Buffer} 153 | */ 154 | reverse: function reverse(param) { 155 | var ret = new buffer.Buffer(param.length); 156 | for (var i = 0; i < param.length; i++) { 157 | ret[i] = param[param.length - i - 1]; 158 | } 159 | return ret; 160 | }, 161 | 162 | /** 163 | * Transforms an hexa encoded string into a Buffer with binary values 164 | * 165 | * Shorthand for Buffer(string, 'hex') 166 | * 167 | * @param {string} string 168 | * @return {Buffer} 169 | */ 170 | hexToBuffer: function hexToBuffer(string) { 171 | assert(js.isHexa(string)); 172 | return new buffer.Buffer(string, 'hex'); 173 | }, 174 | 175 | bufferToHex: function bufferToHex(buf) { 176 | return buf.reduce((r,d)=>{ 177 | let hex = d.toString(16); 178 | if(hex.length === 1){ 179 | hex = "0" + hex; 180 | } 181 | return r + hex; 182 | },"") 183 | } 184 | }; 185 | 186 | module.exports.NULL_HASH = module.exports.fill(Buffer.alloc(32), 0); 187 | module.exports.EMPTY_BUFFER = Buffer.alloc(0); 188 | -------------------------------------------------------------------------------- /src/utils/bufferreader.js: -------------------------------------------------------------------------------- 1 | let BigInteger = require("bigi"); 2 | 3 | var BufferReader = function (buffer, cursor) { 4 | this.buf = buffer; 5 | this.cursor = cursor; 6 | 7 | } 8 | 9 | BufferReader.prototype.getCursor = function () { 10 | return this.cursor; 11 | }; 12 | BufferReader.prototype.getBuffer = function () { 13 | return this.buf; 14 | }; 15 | 16 | BufferReader.prototype.slice = function (length) { 17 | var result = this.buf.slice(this.cursor, this.cursor + length); 18 | this.cursor += length; 19 | return result; 20 | }; 21 | 22 | BufferReader.prototype.readUInt64LE = function () { 23 | var bytes = this.slice(8); 24 | return (bytes[0] & 0xff) | 25 | ((bytes[1] & 0xff) << 8) | 26 | ((bytes[2] & 0xff) << 16) | 27 | ((bytes[3] & 0xff) << 24) | 28 | ((bytes[4] & 0xff) << 32) | 29 | ((bytes[5] & 0xff) << 40) | 30 | ((bytes[6] & 0xff) << 48) | 31 | ((bytes[7] & 0xff) << 56); 32 | }; 33 | BufferReader.prototype.readUInt32LE = function () { 34 | var result = this.buf.readUInt32LE(this.cursor); 35 | this.cursor += 4; 36 | return result; 37 | }; 38 | BufferReader.prototype.readUInt16LE = function () { 39 | var result = this.buf.readUInt16LE(this.cursor); 40 | this.cursor += 2; 41 | return result; 42 | }; 43 | BufferReader.prototype.readUInt8 = function () { 44 | var result = this.buf.readUInt8(this.cursor); 45 | this.cursor += 1; 46 | return result; 47 | }; 48 | BufferReader.prototype.readBytesByLength = function () { 49 | var length = this.readVarInt(); 50 | var result = this.slice(length); 51 | return result; 52 | }; 53 | BufferReader.prototype.isFinished = function () { 54 | return this.buf.length == this.cursor; 55 | }; 56 | BufferReader.prototype.readBoolean = function () { 57 | result = this.buf.readUInt8(); 58 | this.cursor += 1; 59 | return result != 0; 60 | }; 61 | BufferReader.prototype.readBigInteger = function () { 62 | var bytes = this.slice(32); 63 | var value = new BigInteger(bytes.reverse()); 64 | return value.toString(); 65 | }; 66 | 67 | BufferReader.prototype.readVarInt = function () { 68 | var first = 0xFF & this.buf.readInt8(this.cursor); 69 | var result = first; 70 | if (first < 253) { 71 | this.cursor += 1; 72 | } else if (first == 253) { 73 | result = this.buf.readInt16LE(this.cursor + 1) 74 | this.cursor += 3; 75 | } else if (first == 254) { 76 | result = this.buf.readUInt32LE(this.cursor + 1) 77 | this.cursor += 5; 78 | } else { 79 | result = this.buf.readUInt64LE(this.cursor + 1) 80 | this.cursor += 9; 81 | } 82 | return result; 83 | }; 84 | 85 | 86 | module.exports = BufferReader; -------------------------------------------------------------------------------- /src/utils/bufferwriter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bufferUtil = require('./buffer'); 4 | var assert = require('assert'); 5 | 6 | var BufferWriter = function BufferWriter(obj) { 7 | if (!(this instanceof BufferWriter)) 8 | return new BufferWriter(obj); 9 | this.bufLen = 0; 10 | if (obj) 11 | this.set(obj); 12 | else 13 | this.bufs = []; 14 | }; 15 | 16 | BufferWriter.prototype.set = function(obj) { 17 | this.bufs = obj.bufs || this.bufs || []; 18 | this.bufLen = this.bufs.reduce(function(prev, buf){ return prev + buf.length; }, 0); 19 | return this; 20 | }; 21 | 22 | BufferWriter.prototype.toBuffer = function() { 23 | return this.concat(); 24 | }; 25 | 26 | BufferWriter.prototype.concat = function() { 27 | return Buffer.concat(this.bufs, this.bufLen); 28 | }; 29 | 30 | BufferWriter.prototype.write = function(buf) { 31 | assert(bufferUtil.isBuffer(buf)); 32 | this.bufs.push(buf); 33 | this.bufLen += buf.length; 34 | return this; 35 | }; 36 | 37 | BufferWriter.prototype.writeReverse = function(buf) { 38 | assert(bufferUtil.isBuffer(buf)); 39 | this.bufs.push(bufferUtil.reverse(buf)); 40 | this.bufLen += buf.length; 41 | return this; 42 | }; 43 | 44 | BufferWriter.prototype.writeUInt8 = function(n) { 45 | var buf = Buffer.alloc(1); 46 | buf.writeUInt8(n, 0); 47 | this.write(buf); 48 | return this; 49 | }; 50 | 51 | BufferWriter.prototype.writeUInt16BE = function(n) { 52 | var buf = Buffer.alloc(2); 53 | buf.writeUInt16BE(n, 0); 54 | this.write(buf); 55 | return this; 56 | }; 57 | 58 | BufferWriter.prototype.writeUInt16LE = function(n) { 59 | var buf = Buffer.alloc(2); 60 | buf.writeUInt16LE(n, 0); 61 | this.write(buf); 62 | return this; 63 | }; 64 | 65 | BufferWriter.prototype.writeUInt32BE = function(n) { 66 | var buf = Buffer.alloc(4); 67 | buf.writeUInt32BE(n, 0); 68 | this.write(buf); 69 | return this; 70 | }; 71 | 72 | BufferWriter.prototype.writeInt32LE = function(n) { 73 | var buf = Buffer.alloc(4); 74 | buf.writeInt32LE(n, 0); 75 | this.write(buf); 76 | return this; 77 | }; 78 | 79 | BufferWriter.prototype.writeUInt32LE = function(n) { 80 | var buf = Buffer.alloc(4); 81 | buf.writeUInt32LE(n, 0); 82 | this.write(buf); 83 | return this; 84 | }; 85 | 86 | BufferWriter.prototype.writeUInt64BEBN = function(bn) { 87 | var buf = bn.toBuffer({size: 8}); 88 | this.write(buf); 89 | return this; 90 | }; 91 | 92 | BufferWriter.prototype.writeUInt64LEBN = function(bn) { 93 | var buf = bn.toBuffer({size: 8}); 94 | this.writeReverse(buf); 95 | return this; 96 | }; 97 | 98 | BufferWriter.prototype.writeVarintNum = function(n) { 99 | var buf = BufferWriter.varintBufNum(n); 100 | this.write(buf); 101 | return this; 102 | }; 103 | 104 | BufferWriter.prototype.writeVarintBN = function(bn) { 105 | var buf = BufferWriter.varintBufBN(bn); 106 | this.write(buf); 107 | return this; 108 | }; 109 | 110 | BufferWriter.varintBufNum = function(n) { 111 | var buf = undefined; 112 | if (n < 253) { 113 | buf = Buffer.alloc(1); 114 | buf.writeUInt8(n, 0); 115 | } else if (n < 0x10000) { 116 | buf = Buffer.alloc(1 + 2); 117 | buf.writeUInt8(253, 0); 118 | buf.writeUInt16LE(n, 1); 119 | } else if (n < 0x100000000) { 120 | buf = Buffer.alloc(1 + 4); 121 | buf.writeUInt8(254, 0); 122 | buf.writeUInt32LE(n, 1); 123 | } else { 124 | buf = Buffer.alloc(1 + 8); 125 | buf.writeUInt8(255, 0); 126 | buf.writeInt32LE(n & -1, 1); 127 | buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); 128 | } 129 | return buf; 130 | }; 131 | 132 | BufferWriter.varintBufBN = function(bn) { 133 | var buf = undefined; 134 | var n = bn.toNumber(); 135 | if (n < 253) { 136 | buf = Buffer.alloc(1); 137 | buf.writeUInt8(n, 0); 138 | } else if (n < 0x10000) { 139 | buf = Buffer.alloc(1 + 2); 140 | buf.writeUInt8(253, 0); 141 | buf.writeUInt16LE(n, 1); 142 | } else if (n < 0x100000000) { 143 | buf = Buffer.alloc(1 + 4); 144 | buf.writeUInt8(254, 0); 145 | buf.writeUInt32LE(n, 1); 146 | } else { 147 | var bw = new BufferWriter(); 148 | bw.writeUInt8(255); 149 | bw.writeUInt64LEBN(bn); 150 | var buf = bw.concat(); 151 | } 152 | return buf; 153 | }; 154 | 155 | module.exports = BufferWriter; 156 | -------------------------------------------------------------------------------- /src/utils/hash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var crypto = require('crypto'); 4 | var BufferUtil = require('./buffer'); 5 | var $ = require('./preconditions'); 6 | 7 | var Hash = module.exports; 8 | 9 | Hash.sha1 = function(buf) { 10 | $.checkArgument(BufferUtil.isBuffer(buf)); 11 | return crypto.createHash('sha1').update(buf).digest(); 12 | }; 13 | 14 | Hash.sha1.blocksize = 512; 15 | 16 | Hash.sha256 = function(buf) { 17 | $.checkArgument(BufferUtil.isBuffer(buf)); 18 | return crypto.createHash('sha256').update(buf).digest(); 19 | }; 20 | 21 | Hash.sha256.blocksize = 512; 22 | 23 | Hash.sha256sha256 = function(buf) { 24 | $.checkArgument(BufferUtil.isBuffer(buf)); 25 | return Hash.sha256(Hash.sha256(buf)); 26 | }; 27 | 28 | Hash.ripemd160 = function(buf) { 29 | $.checkArgument(BufferUtil.isBuffer(buf)); 30 | return crypto.createHash('ripemd160').update(buf).digest(); 31 | }; 32 | 33 | Hash.sha256ripemd160 = function(buf) { 34 | $.checkArgument(BufferUtil.isBuffer(buf)); 35 | return Hash.ripemd160(Hash.sha256(buf)); 36 | }; 37 | 38 | Hash.sha512 = function(buf) { 39 | $.checkArgument(BufferUtil.isBuffer(buf)); 40 | return crypto.createHash('sha512').update(buf).digest(); 41 | }; 42 | 43 | Hash.sha512.blocksize = 1024; 44 | 45 | Hash.hmac = function(hashf, data, key) { 46 | //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code 47 | //http://tools.ietf.org/html/rfc4868#section-2 48 | $.checkArgument(BufferUtil.isBuffer(data)); 49 | $.checkArgument(BufferUtil.isBuffer(key)); 50 | $.checkArgument(hashf.blocksize); 51 | 52 | var blocksize = hashf.blocksize / 8; 53 | 54 | if (key.length > blocksize) { 55 | key = hashf(key); 56 | } else if (key < blocksize) { 57 | var fill = Buffer.alloc(blocksize); 58 | fill.fill(0); 59 | key.copy(fill); 60 | key = fill; 61 | } 62 | 63 | var o_key = Buffer.alloc(blocksize); 64 | o_key.fill(0x5c); 65 | 66 | var i_key = Buffer.alloc(blocksize); 67 | i_key.fill(0x36); 68 | 69 | var o_key_pad = Buffer.alloc(blocksize); 70 | var i_key_pad = Buffer.alloc(blocksize); 71 | for (var i = 0; i < blocksize; i++) { 72 | o_key_pad[i] = o_key[i] ^ key[i]; 73 | i_key_pad[i] = i_key[i] ^ key[i]; 74 | } 75 | 76 | return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); 77 | }; 78 | 79 | Hash.sha256hmac = function(data, key) { 80 | return Hash.hmac(Hash.sha256, data, key); 81 | }; 82 | 83 | Hash.sha512hmac = function(data, key) { 84 | return Hash.hmac(Hash.sha512, data, key); 85 | }; 86 | -------------------------------------------------------------------------------- /src/utils/js.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | /** 6 | * Determines whether a string contains only hexadecimal values 7 | * 8 | * @name JSUtil.isHexa 9 | * @param {string} value 10 | * @return {boolean} true if the string is the hexa representation of a number 11 | */ 12 | var isHexa = function isHexa(value) { 13 | if (!_.isString(value)) { 14 | return false; 15 | } 16 | return /^[0-9a-fA-F]+$/.test(value); 17 | }; 18 | 19 | /** 20 | * @namespace JSUtil 21 | */ 22 | module.exports = { 23 | /** 24 | * Test if an argument is a valid JSON object. If it is, returns a truthy 25 | * value (the json object decoded), so no double JSON.parse call is necessary 26 | * 27 | * @param {string} arg 28 | * @return {Object|boolean} false if the argument is not a JSON string. 29 | */ 30 | isValidJSON: function isValidJSON(arg) { 31 | var parsed; 32 | if (!_.isString(arg)) { 33 | return false; 34 | } 35 | try { 36 | parsed = JSON.parse(arg); 37 | } catch (e) { 38 | return false; 39 | } 40 | if (typeof(parsed) === 'object') { 41 | return true; 42 | } 43 | return false; 44 | }, 45 | isHexa: isHexa, 46 | isHexaString: isHexa, 47 | 48 | /** 49 | * Clone an array 50 | */ 51 | cloneArray: function(array) { 52 | return [].concat(array); 53 | }, 54 | 55 | /** 56 | * Define immutable properties on a target object 57 | * 58 | * @param {Object} target - An object to be extended 59 | * @param {Object} values - An object of properties 60 | * @return {Object} The target object 61 | */ 62 | defineImmutable: function defineImmutable(target, values) { 63 | Object.keys(values).forEach(function(key){ 64 | Object.defineProperty(target, key, { 65 | configurable: false, 66 | enumerable: true, 67 | value: values[key] 68 | }); 69 | }); 70 | return target; 71 | }, 72 | /** 73 | * Checks that a value is a natural number, a positive integer or zero. 74 | * 75 | * @param {*} value 76 | * @return {Boolean} 77 | */ 78 | isNaturalNumber: function isNaturalNumber(value) { 79 | return typeof value === 'number' && 80 | isFinite(value) && 81 | Math.floor(value) === value && 82 | value >= 0; 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /src/utils/preconditions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // var errors = require('../errors'); 4 | var _ = require('lodash'); 5 | 6 | module.exports = { 7 | checkState: function(condition, message) { 8 | if (!condition) { 9 | throw new errors.InvalidState(message); 10 | } 11 | }, 12 | checkArgument: function(condition, argumentName, message, docsPath) { 13 | if (!condition) { 14 | throw new errors.InvalidArgument(argumentName, message, docsPath); 15 | } 16 | }, 17 | checkArgumentType: function(argument, type, argumentName) { 18 | argumentName = argumentName || '(unknown name)'; 19 | if (_.isString(type)) { 20 | if (type === 'Buffer') { 21 | var buffer = require('buffer'); // './buffer' fails on cordova & RN 22 | if (!buffer.Buffer.isBuffer(argument)) { 23 | throw new errors.InvalidArgumentType(argument, type, argumentName); 24 | } 25 | } else if (typeof argument !== type) { 26 | throw new errors.InvalidArgumentType(argument, type, argumentName); 27 | } 28 | } else { 29 | if (!(argument instanceof type)) { 30 | throw new errors.InvalidArgumentType(argument, type.name, argumentName); 31 | } 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function valueOfstring(obj) { 4 | return obj === null ? null : obj.toString(); 5 | } 6 | 7 | function isBlank(str) { 8 | return null === str || str.trim().length === 0; 9 | } 10 | 11 | module.exports = { 12 | stringToByte(str) { 13 | let bytes = []; 14 | let len, c; 15 | len = str.length; 16 | for (let i = 0; i < len; i++) { 17 | c = str.charCodeAt(i); 18 | if (c >= 0x010000 && c <= 0x10FFFF) { 19 | bytes.push(((c >> 18) & 0x07) | 0xF0); 20 | bytes.push(((c >> 12) & 0x3F) | 0x80); 21 | bytes.push(((c >> 6) & 0x3F) | 0x80); 22 | bytes.push((c & 0x3F) | 0x80); 23 | } else if (c >= 0x000800 && c <= 0x00FFFF) { 24 | bytes.push(((c >> 12) & 0x0F) | 0xE0); 25 | bytes.push(((c >> 6) & 0x3F) | 0x80); 26 | bytes.push((c & 0x3F) | 0x80); 27 | } else if (c >= 0x000080 && c <= 0x0007FF) { 28 | bytes.push(((c >> 6) & 0x1F) | 0xC0); 29 | bytes.push((c & 0x3F) | 0x80); 30 | } else { 31 | bytes.push(c & 0xFF); 32 | } 33 | } 34 | return bytes; 35 | }, 36 | 37 | twoDimensionalArray: function twoDimensionalArray(args, types) { 38 | if (args.length === 0) { 39 | return null; 40 | } else if (args.length !== types.length) { 41 | throw "args number error"; 42 | } else { 43 | let length = args.length; 44 | let two = new Array(length); 45 | let arg = void 0; 46 | for (let i = 0; i < length; i++) { 47 | arg = args[i]; 48 | if (arg == null) { 49 | two[i] = []; 50 | continue; 51 | } 52 | if (typeof arg === 'string') { 53 | let argStr = arg; 54 | // 非String类型参数,若传参是空字符串,则赋值为空一维数组,避免数字类型转化异常 -> 空字符串转化为数字 55 | if (types != null && isBlank(argStr) && 'String' !== types[i]) { 56 | two[i] = []; 57 | } else if (types != null && !isBlank(argStr) && types[i].indexOf('[]') >= 0) { 58 | let arrayArg = eval(argStr); 59 | if (Array.isArray(arrayArg)) { 60 | let len = arrayArg.length; 61 | let result = new Array(len); 62 | for (let k = 0; k < len; k++) { 63 | result[k] = valueOfstring(arrayArg[k]); 64 | } 65 | two[i] = result; 66 | } else { 67 | throw "array arg error"; 68 | } 69 | } else { 70 | two[i] = [argStr]; 71 | } 72 | } else if (Array.isArray(arg)) { 73 | let len = arg.length; 74 | let result = new Array(len); 75 | for (let k = 0; k < len; k++) { 76 | result[k] = valueOfstring(arg[k]); 77 | } 78 | two[i] = result; 79 | } else { 80 | two[i] = [valueOfstring(arg)]; 81 | } 82 | } 83 | return two; 84 | } 85 | } 86 | }; 87 | 88 | 89 | --------------------------------------------------------------------------------