nerve-sdk-js
Version:
nerve nerve-js nerve-sdk nerve-js-sdk
656 lines (559 loc) • 18.9 kB
JavaScript
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
var randomBytes = require('randombytes');
var BigInteger = require('bigi');
var ecurve = require('ecurve');
var CryptoJS = require('crypto-js');
var sha256 = require('sha256');
var rs = require('jsrsasign');
var bs58 = require('bs58');
var cryptos = require("crypto");
var iv = CryptoJS.enc.Hex.parse('0000000000000000');
var bufferUtils = require("../utils/buffer");
var Hash = require("../utils/hash");
var Serializers = require("./serializers");
var secp256k1 = require("secp256k1");
var programEncodePacked = require("../model/ProgramEncodePacked");
var BufferReader = require("../utils/bufferreader");
var ethers = require("ethers");
var Signature = require("elliptic/lib/elliptic/ec/signature");
var message = "Tip: You are signing a NerveNetwork transaction. Please confirm your transaction information carefully. Once the transaction is broadcast on the blockchain, there is no way to cancel your transaction.\n\n提示:您正在签署一笔NerveNetwork交易,请仔细确认您的交易信息。交易一旦在区块链上广播,将无法取消。\n\nTransaction Hash:\n";
/**
* 将数字转为6个字节的字节数组
* @param value
* @returns {*|Buffer}
*/
function toUInt16LE(value) {
var buf = Buffer.alloc(2);
buf.writeInt16LE(value, 0);
return buf;
}
/**
*
* @param str
* @returns {boolean}
*/
String.prototype.startWith = function (str) {
if (str == null || str === "" || this.length === 0 || str.length > this.length) {
return false;
}
if (this.substr(0, str.length) === str) {
return true;
} else {
return false;
}
};
var _l1GasUsedOnScroll = new ethers.utils.BigNumber(21000);
var _l1GasUsedOnOptimismOrBase = new ethers.utils.BigNumber(18000);
var _l1GasUsedOnManta = new ethers.utils.BigNumber(18000);
var scalarOnScroll = new ethers.utils.BigNumber(1150000000);
var dynamicOverheadOnOptimismOrBase = 684000000;
var precision = new ethers.utils.BigNumber(1000000000);
var dynamicOverheadOnManta = new ethers.utils.BigNumber(1);
function getL1FeeOnScroll(_l1GasUsed, ethNetworkGasPrice) {
return _l1GasUsed.mul(ethNetworkGasPrice).mul(scalarOnScroll).div(precision);
}
function getL1FeeOnOptimismOrBase(_l1GasUsed, ethNetworkGasPrice) {
return _l1GasUsed.mul(dynamicOverheadOnOptimismOrBase).mul(ethNetworkGasPrice).div(precision);
}
function getL1FeeOnManta(_l1GasUsed, ethNetworkGasPrice) {
return _l1GasUsed.mul(dynamicOverheadOnManta).mul(ethNetworkGasPrice);
}
module.exports = {
CONTRACT_CONSTRUCTOR: "<init>",
CONTRACT_MAX_GASLIMIT: 10000000,
CONTRACT_MINIMUM_PRICE: 25,
/**
* 生成公私钥对
* @returns {{}}
*/
newEcKey: function newEcKey() {
var keys = {};
var randombytes = randomBytes(32);
randombytes[0] = randombytes[0] >> 1;
var privateKey = bufferUtils.bufferToHex(Buffer.from(randombytes, 'hex'));
keys['pri'] = privateKey;
keys['pub'] = this.getPub(privateKey);
return keys;
},
/**
* 获取公钥
* @param privateKey 私钥
* @returns {string}
*/
getPub: function getPub(privateKey) {
var privateKeyBuf = Buffer.from(privateKey, 'hex');
var val = BigInteger.fromBuffer(privateKeyBuf);
if (val.compareTo(BigInteger.valueOf(1)) <= 0) {
throw "private key is wrong!";
}
var ecparams = ecurve.getCurveByName('secp256k1');
var curvePt = ecparams.G.multiply(val);
var publicKey = curvePt.getEncoded(true);
return publicKey.toString('hex');
},
/**
* 获取地址的bytes
* @param stringAddress
*/
getBytesAddress: function getBytesAddress(stringAddress) {
stringAddress = '' + stringAddress;
if (stringAddress.startsWith('NULS')) {
stringAddress = stringAddress.substring(5);
} else if (stringAddress.startsWith('tNULS')) {
stringAddress = stringAddress.substring(6);
} else {
for (var i = 0; i < stringAddress.length; i++) {
var val = stringAddress.charAt(i);
if (val.charCodeAt(0) >= 97) {
stringAddress = stringAddress.substring(i + 1);
break;
}
}
}
var bytes = bs58.decode(stringAddress);
return bytes.slice(0, bytes.length - 1);
},
/**
* 根据byte[] 获取 地址字符串
* @param stringAddress
*/
getStringAddressByBytes: function getStringAddressByBytes(bytes) {
var chainId = bytes[0] & 0xff | (bytes[1] & 0xff) << 8;
var tempBuffer = Buffer.allocUnsafe(bytes.length + 1);
var xor = 0x00;
var temp = "";
for (var i = 0; i < bytes.length; i++) {
temp = bytes[i];
temp = temp > 127 ? temp - 256 : temp;
tempBuffer[i] = temp;
xor ^= temp;
}
tempBuffer[bytes.length] = xor;
if (1 === chainId) {
prefix = 'NULS';
} else if (2 === chainId) {
prefix = "tNULS";
} else if (5 === chainId) {
prefix = "TNVT";
} else if (9 === chainId) {
prefix = "NERVE";
} else if (prefix) {
prefix = prefix.toUpperCase();
} else {
prefix = bs58.encode(chainIdBuffer).toUpperCase();
}
var constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
/**
* 验证地址
* @param stringAddress
* @returns {{}}
*/
verifyAddress: function verifyAddress(stringAddress) {
var result = {};
stringAddress = '' + stringAddress;
if (stringAddress.startsWith('NULS')) {
stringAddress = stringAddress.substring(5);
} else if (stringAddress.startsWith('tNULS')) {
stringAddress = stringAddress.substring(6);
} else {
for (var i = 0; i < stringAddress.length; i++) {
var val = stringAddress.charAt(i);
if (val.charCodeAt(0) >= 97) {
stringAddress = stringAddress.substring(i + 1);
break;
}
}
}
var bytes = bs58.decode(stringAddress);
result.chainId = bytes.readUInt16LE(0);
result.type = bytes.readInt8(2);
var temp = '';
var xor = 0x00;
for (var _i = 0; _i < bytes.length - 1; _i++) {
temp = bytes[_i];
temp = temp > 127 ? temp - 256 : temp;
bytes[_i] = temp;
xor ^= temp;
}
if (xor < 0) {
xor = 256 + xor;
}
result.right = xor === bytes[bytes.length - 1];
return result;
},
/**
* 根据公钥、私钥获取地址字符串
* @param chainId
* @param pri
* @param pub
* @param prefix
* @returns {*}
*/
getStringAddress: function getStringAddress(chainId, pri, pub, prefix) {
return this.getStringAddressBase(chainId, 1, pri, pub, prefix);
},
getStringSpecAddress: function getStringSpecAddress(chainId, type, pub, prefix) {
var pubBuffer = Buffer.from(pub, 'hex');
var val = BigInteger.fromBuffer(pubBuffer);
var sha = cryptos.createHash('sha256').update(pubBuffer).digest();
var pubkeyHash = cryptos.createHash('ripemd160').update(sha).digest();
var chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]);
var addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([type]), pubkeyHash]);
var xor = 0x00;
var temp = "";
var tempBuffer = Buffer.allocUnsafe(addrBuffer.length + 1);
for (var i = 0; i < addrBuffer.length; i++) {
temp = addrBuffer[i];
temp = temp > 127 ? temp - 256 : temp;
tempBuffer[i] = temp;
xor ^= temp;
}
tempBuffer[addrBuffer.length] = xor;
if (1 === chainId) {
prefix = 'NULS';
} else if (2 === chainId) {
prefix = "tNULS";
} else if (5 === chainId) {
prefix = "TNVT";
} else if (9 === chainId) {
prefix = "NERVE";
} else if (prefix) {
prefix = prefix.toUpperCase();
} else {
prefix = bs58.encode(chainIdBuffer).toUpperCase();
}
var constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
/**
* 根据公钥、私钥获取智能合约地址字符串
* @param chainId
* @returns {*}
*/
getStringContractAddress: function getStringContractAddress(chainId) {
var addressInfo = this.newEcKey();
return this.getStringAddressBase(chainId, 2, addressInfo.pri, addressInfo.pub);
},
/**
* 根据地址类型、公钥、私钥获取地址字符串
* @param chainId
* @param type
* @param pri
* @param pub
* @param prefix
* @returns {string}
*/
getStringAddressBase: function getStringAddressBase(chainId, type, pri, pub, prefix) {
if (!pub) {
pub = this.getPub(pri);
}
var pubBuffer = Buffer.from(pub, 'hex');
var val = BigInteger.fromBuffer(pubBuffer);
if (val.compareTo(BigInteger.valueOf(1)) <= 0) {
throw "public key is wrong!";
}
var sha = cryptos.createHash('sha256').update(pubBuffer).digest();
var pubkeyHash = cryptos.createHash('ripemd160').update(sha).digest();
var chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]);
var addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([type]), pubkeyHash]);
var xor = 0x00;
var temp = "";
var tempBuffer = Buffer.allocUnsafe(addrBuffer.length + 1);
for (var i = 0; i < addrBuffer.length; i++) {
temp = addrBuffer[i];
temp = temp > 127 ? temp - 256 : temp;
tempBuffer[i] = temp;
xor ^= temp;
}
tempBuffer[addrBuffer.length] = xor;
if (1 === chainId) {
prefix = 'NULS';
} else if (2 === chainId) {
prefix = "tNULS";
} else if (5 === chainId) {
prefix = "TNVT";
} else if (9 === chainId) {
prefix = "NERVE";
} else if (prefix) {
prefix = prefix.toUpperCase();
} else {
prefix = bs58.encode(chainIdBuffer).toUpperCase();
}
var constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
addressV1ToV2: function addressV1ToV2(addressV1, chainId) {
if (!addressV1) {
return;
}
var bytesV1 = bs58.decode(addressV1);
var pubkeyHash = Buffer.alloc(20);
bytesV1.copy(pubkeyHash, 0, 3, 23);
var chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]);
var addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([1]), pubkeyHash]);
var xor = 0x00;
var temp = "";
var tempBuffer = Buffer.allocUnsafe(addrBuffer.length + 1);
for (var i = 0; i < addrBuffer.length; i++) {
temp = addrBuffer[i];
temp = temp > 127 ? temp - 256 : temp;
tempBuffer[i] = temp;
xor ^= temp;
}
tempBuffer[addrBuffer.length] = xor;
var prefix = 'NULS';
if (1 === chainId) {
prefix = 'NULS';
} else if (2 === chainId) {
prefix = "tNULS";
} else if (5 === chainId) {
prefix = "TNVT";
} else if (9 === chainId) {
prefix = "NERVE";
}
var constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
/**
* AES 加密
* @param value
* @param password
* @returns {string}
*/
encrypteByAES: function encrypteByAES(value, password) {
var key = CryptoJS.enc.Hex.parse(sha256(password));
var srcs = CryptoJS.enc.Hex.parse(value);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.ciphertext.toString().toLowerCase();
},
/**
* AES 解密
* @param encryptedValue
* @param password
* @returns {string}
*/
decrypteOfAES: function decrypteOfAES(encryptedValue, password) {
var key = CryptoJS.enc.Hex.parse(sha256(password));
var encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedValue);
var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
var decrypt = CryptoJS.AES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypt.toString().toLowerCase();
},
/**
* 签名
* @param dataHex
* @param priHex
* @returns {void|*}
*/
signature: function signature(dataHex, priHex) {
var ec = new rs.KJUR.crypto.ECDSA({
'curve': 'secp256k1'
});
return ec.signHex(dataHex, priHex);
},
/**
* 签名 tx
* @param tx
* @param priHex
* @param pubHex
*/
signatureTx: function signatureTx(tx, priHex, pubHex) {
var pub = Buffer.from(pubHex, 'hex');
var hash = tx.getHash();
var sigHex = this.signature(hash.toString('hex'), priHex);
var signValue = Buffer.from(sigHex, 'hex');
var bw = new Serializers();
bw.writeBytesWithLength(pub);
bw.writeBytesWithLength(signValue);
tx.signatures = bw.getBufWriter().toBuffer();
},
/**
* @disc: hash 私钥签名
* @params: hashHex, priHex
* @date: 2019-12-03 16:59
* @author: Wave
*/
getSignData: function getSignData(hashHex, priHex) {
var pub = this.getPub(priHex);
var sigHex = this.signature(hashHex, priHex);
return {
"pub": pub.toString('hex'),
"signValue": sigHex
};
},
getSignMessageWithPS: function getSignMessageWithPS(hashHex) {
if (hashHex.startsWith('0x')) {
hashHex = hashHex.substring(2);
}
var data = message + hashHex;
var hexMessage = "0x".concat(Buffer.from(data, 'utf8').toString('hex'));
return hexMessage;
},
getSignDataWithPS(hashHex, priHex) {
var _this = this;
return _asyncToGenerator(function* () {
var pub = _this.getPub(priHex);
var data = message + hashHex;
var dataBuffer = Buffer.from(data, 'utf-8'); // 本地签名 OR 调用插件personal_sign
// let signature = await window.ethereum.request({method: 'personal_sign', params: ['0x'+dataBuffer.toString('hex'), account]});
var wallet = new ethers.Wallet(ethers.utils.hexZeroPad(ethers.utils.hexStripZeros('0x' + priHex), 32));
var signature = yield wallet.signMessage(dataBuffer);
signature = signature.slice(2); // 去掉0x
var r = signature.slice(0, 64);
var s = signature.slice(64, 128);
var signatureDER = new Signature({
r,
s
}).toDER("hex");
return {
"pub": pub.toString('hex'),
"signValue": signatureDER
};
})();
},
/**
* App签名,拼接公钥
* @param signValue
* @param pubHex
*/
appSplicingPub: function appSplicingPub(signValue, pubHex) {
var bw = new Serializers();
bw.writeBytesWithLength(Buffer.from(pubHex, 'hex'));
bw.writeBytesWithLength(Buffer.from(signValue, 'hex'));
return bw.getBufWriter().toBuffer();
},
appSplicingPubWithPS: function appSplicingPubWithPS(signValue, pubHex) {
var bw = new Serializers();
bw.writeBytesWithLength(Buffer.from(pubHex, 'hex'));
bw.writeBytesWithLength(Buffer.from(signValue, 'hex'));
bw.writeBoolean(true);
return bw.getBufWriter().toBuffer();
},
/**
* 签名 tx
* @param tx
* @param priHex
*/
signatureTransaction: function signatureTransaction(tx, priHex) {
var hash = tx.getHash();
var sigHex = this.signature(hash.toString('hex'), priHex);
return Buffer.from(sigHex, 'hex');
},
/**
* 验证签名
* @param dataHex
* @param signHex
* @param pubHex
* @returns {*}
*/
verifySign: function verifySign(dataHex, signHex, pubHex) {
var ec = new rs.KJUR.crypto.ECDSA({
'curve': 'secp256k1'
});
var publicKey = secp256k1.publicKeyConvert(Buffer.from(pubHex, "hex"), false).toString("hex");
return ec.verifyHex(dataHex, signHex, publicKey);
},
/**
* 获取hex根据sha256
* @param seriHex
* @returns {*|void|PromiseLike<ArrayBuffer>}
*/
getSha256Hex: function getSha256Hex(seriHex) {
var sha256 = cryptos.createHash('SHA256');
var data = Buffer.from(seriHex, 'hex');
sha256.update(data);
return sha256.digest('hex');
},
/**
* sha256转buf
* @param buf
* @returns {*}
*/
getSha256TiwceBuf: function getSha256TiwceBuf(buf) {
return Hash.sha256sha256(buf);
},
/**
* 获取owner
* @param txHash
* @param fromIndex
* @returns {string}
*/
getOwner: function getOwner(txHash, fromIndex) {
var buf = toUInt16LE(fromIndex);
return txHash + buf.toString("hex");
},
/**
* 获取txhash
* @param transaction
* @returns {*}
*/
getTxHash: function getTxHash(transaction) {
var bytes = transaction.serializeForHash();
transaction.hash = this.getSha256TiwceBuf(bytes);
return transaction.hash;
},
addressEquals: function addressEquals(addressV1, addressV2) {
var bytesV1 = bs58.decode(addressV1);
bytesV1 = bytesV1.slice(2, bytesV1.length - 1);
var bytesV2 = this.getBytesAddress(addressV2);
bytesV2 = bytesV2.slice(2, bytesV2.length);
return bytesV1.equals(bytesV2);
},
getVarIntLength: function getVarIntLength(varInt) {
if (varInt < 0) {
return 9;
}
if (varInt < 253) {
return 1;
}
if (varInt <= 0xFFFF) {
return 3;
}
if (varInt <= 0xFFFFFFFF) {
return 5;
}
return 9;
},
bufferReadBytesByLength: function bufferReadBytesByLength(buffer, cursor) {},
newProgramEncodePacked: function newProgramEncodePacked(args) {
var encodePacked = new programEncodePacked.ProgramEncodePacked();
if (args) {
encodePacked.argsCount = args.length;
encodePacked.args = args;
}
return encodePacked.serialize().toString('hex');
},
parseProgramEncodePacked: function parseProgramEncodePacked(data) {
var encodePacked = new programEncodePacked.ProgramEncodePacked();
var bufferReader = new BufferReader(Buffer.from(data, "hex"), 0);
encodePacked.parse(bufferReader);
return encodePacked.args;
},
getL1Fee: function getL1Fee(htgChainId, ethNetworkGasPrice) {
switch (htgChainId) {
case 139:
case 138:
case 136:
case 115:
case 129:
return getL1FeeOnOptimismOrBase(_l1GasUsedOnOptimismOrBase, ethNetworkGasPrice);
case 130:
return getL1FeeOnScroll(_l1GasUsedOnScroll, ethNetworkGasPrice);
case 133:
return getL1FeeOnManta(_l1GasUsedOnManta, ethNetworkGasPrice);
default:
return new ethers.utils.BigNumber(0);
}
}
};