nerve-sdk-js
Version:
nerve nerve-js nerve-sdk nerve-js-sdk
553 lines (509 loc) • 17.5 kB
JavaScript
const randomBytes = require('randombytes');
const BigInteger = require('bigi');
const ecurve = require('ecurve');
const CryptoJS = require('crypto-js');
const sha256 = require('sha256');
const rs = require('jsrsasign');
const bs58 = require('bs58');
const cryptos = require("crypto");
const iv = CryptoJS.enc.Hex.parse('0000000000000000');
const bufferUtils = require("../utils/buffer");
const Hash = require("../utils/hash");
const Serializers = require("./serializers");
const secp256k1 = require("secp256k1");
const programEncodePacked = require("../model/ProgramEncodePacked");
const BufferReader = require("../utils/bufferreader");
const ethers = require("ethers");
/**
* 将数字转为6个字节的字节数组
* @param value
* @returns {*|Buffer}
*/
function toUInt16LE(value) {
let 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;
}
};
const _l1GasUsedOnScroll = new ethers.utils.BigNumber(21000);
const _l1GasUsedOnOptimismOrBase = new ethers.utils.BigNumber(18000);
const _l1GasUsedOnManta = new ethers.utils.BigNumber(18000);
const scalarOnScroll = new ethers.utils.BigNumber(1150000000);
const dynamicOverheadOnOptimismOrBase = 684000000;
const precision = new ethers.utils.BigNumber(1000000000);
const 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 () {
let keys = {};
let randombytes = randomBytes(32);
randombytes[0] = randombytes[0] >> 1;
let privateKey = bufferUtils.bufferToHex(Buffer.from(randombytes, 'hex'));
keys['pri'] = privateKey;
keys['pub'] = this.getPub(privateKey);
return keys;
},
/**
* 获取公钥
* @param privateKey 私钥
* @returns {string}
*/
getPub: function (privateKey) {
let privateKeyBuf = Buffer.from(privateKey, 'hex');
let val = BigInteger.fromBuffer(privateKeyBuf);
if (val.compareTo(BigInteger.valueOf(1)) <= 0) {
throw "private key is wrong!";
}
let ecparams = ecurve.getCurveByName('secp256k1');
let curvePt = ecparams.G.multiply(val);
let publicKey = curvePt.getEncoded(true);
return publicKey.toString('hex');
},
/**
* 获取地址的bytes
* @param stringAddress
*/
getBytesAddress: function (stringAddress) {
stringAddress = '' + stringAddress;
if (stringAddress.startsWith('NULS')) {
stringAddress = stringAddress.substring(5);
} else if (stringAddress.startsWith('tNULS')) {
stringAddress = stringAddress.substring(6);
} else {
for (let i = 0; i < stringAddress.length; i++) {
let val = stringAddress.charAt(i);
if (val.charCodeAt(0) >= 97) {
stringAddress = stringAddress.substring(i + 1);
break;
}
}
}
let bytes = bs58.decode(stringAddress);
return bytes.slice(0, bytes.length - 1);
},
/**
* 根据byte[] 获取 地址字符串
* @param stringAddress
*/
getStringAddressByBytes: function (bytes) {
var chainId = (bytes[0] & 0xff) |
((bytes[1] & 0xff) << 8);
let tempBuffer = Buffer.allocUnsafe(bytes.length + 1);
let xor = 0x00;
let temp = "";
for (let 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();
}
let constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
/**
* 验证地址
* @param stringAddress
* @returns {{}}
*/
verifyAddress: function (stringAddress) {
let result = {};
stringAddress = '' + stringAddress;
if (stringAddress.startsWith('NULS')) {
stringAddress = stringAddress.substring(5);
} else if (stringAddress.startsWith('tNULS')) {
stringAddress = stringAddress.substring(6);
} else {
for (let i = 0; i < stringAddress.length; i++) {
let val = stringAddress.charAt(i);
if (val.charCodeAt(0) >= 97) {
stringAddress = stringAddress.substring(i + 1);
break;
}
}
}
let bytes = bs58.decode(stringAddress);
result.chainId = bytes.readUInt16LE(0);
result.type = bytes.readInt8(2);
let temp = '';
let xor = 0x00;
for (let 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 (chainId, pri, pub, prefix) {
return this.getStringAddressBase(chainId, 1, pri, pub, prefix);
},
getStringSpecAddress: function (chainId, type, pub, prefix) {
let pubBuffer = Buffer.from(pub, 'hex');
let val = BigInteger.fromBuffer(pubBuffer);
let sha = cryptos.createHash('sha256').update(pubBuffer).digest();
let pubkeyHash = cryptos.createHash('ripemd160').update(sha).digest();
let chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]);
let addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([type]), pubkeyHash]);
let xor = 0x00;
let temp = "";
let tempBuffer = Buffer.allocUnsafe(addrBuffer.length + 1);
for (let 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();
}
let constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
/**
* 根据公钥、私钥获取智能合约地址字符串
* @param chainId
* @returns {*}
*/
getStringContractAddress: function (chainId) {
let 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 (chainId, type, pri, pub, prefix) {
if (!pub) {
pub = this.getPub(pri)
}
let pubBuffer = Buffer.from(pub, 'hex');
let val = BigInteger.fromBuffer(pubBuffer);
if (val.compareTo(BigInteger.valueOf(1)) <= 0) {
throw "public key is wrong!";
}
let sha = cryptos.createHash('sha256').update(pubBuffer).digest();
let pubkeyHash = cryptos.createHash('ripemd160').update(sha).digest();
let chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]);
let addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([type]), pubkeyHash]);
let xor = 0x00;
let temp = "";
let tempBuffer = Buffer.allocUnsafe(addrBuffer.length + 1);
for (let 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();
}
let constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
addressV1ToV2: function (addressV1, chainId) {
if (!addressV1) {
return;
}
let bytesV1 = bs58.decode(addressV1);
let pubkeyHash = Buffer.alloc(20);
bytesV1.copy(pubkeyHash, 0, 3, 23)
let chainIdBuffer = Buffer.concat([Buffer.from([0xFF & chainId >> 0]), Buffer.from([0xFF & chainId >> 8])]);
let addrBuffer = Buffer.concat([chainIdBuffer, Buffer.from([1]), pubkeyHash]);
let xor = 0x00;
let temp = "";
let tempBuffer = Buffer.allocUnsafe(addrBuffer.length + 1);
for (let i = 0; i < addrBuffer.length; i++) {
temp = addrBuffer[i];
temp = temp > 127 ? temp - 256 : temp;
tempBuffer[i] = temp;
xor ^= temp
}
tempBuffer[addrBuffer.length] = xor;
let 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";
}
let constant = ['a', 'b', 'c', 'd', 'e'];
return prefix + constant[prefix.length - 1] + bs58.encode(tempBuffer);
},
/**
* AES 加密
* @param value
* @param password
* @returns {string}
*/
encrypteByAES: function (value, password) {
let key = CryptoJS.enc.Hex.parse(sha256(password));
let srcs = CryptoJS.enc.Hex.parse(value);
let 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 (encryptedValue, password) {
let key = CryptoJS.enc.Hex.parse(sha256(password));
let encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedValue);
let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
let 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 (dataHex, priHex) {
let ec = new rs.KJUR.crypto.ECDSA({'curve': 'secp256k1'});
return ec.signHex(dataHex, priHex);
},
/**
* 签名 tx
* @param tx
* @param priHex
* @param pubHex
*/
signatureTx: function (tx, priHex, pubHex) {
let pub = Buffer.from(pubHex, 'hex');
let hash = tx.getHash();
let sigHex = this.signature(hash.toString('hex'), priHex);
let signValue = Buffer.from(sigHex, 'hex');
let 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 (hashHex, priHex) {
let pub = this.getPub(priHex);
let sigHex = this.signature(hashHex, priHex);
return {"pub": pub.toString('hex'), "signValue": sigHex};
},
/**
* App签名,拼接公钥
* @param signValue
* @param pubHex
*/
appSplicingPub: function appSplicingPub(signValue, pubHex) {
let bw = new Serializers();
bw.writeBytesWithLength(Buffer.from(pubHex, 'hex'));
bw.writeBytesWithLength(Buffer.from(signValue, 'hex'));
return bw.getBufWriter().toBuffer();
},
/**
* 签名 tx
* @param tx
* @param priHex
*/
signatureTransaction: function (tx, priHex) {
let hash = tx.getHash();
let sigHex = this.signature(hash.toString('hex'), priHex);
return Buffer.from(sigHex, 'hex');
},
/**
* 验证签名
* @param dataHex
* @param signHex
* @param pubHex
* @returns {*}
*/
verifySign: function (dataHex, signHex, pubHex) {
let ec = new rs.KJUR.crypto.ECDSA({'curve': 'secp256k1'});
let 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 (seriHex) {
let sha256 = cryptos.createHash('SHA256');
let data = Buffer.from(seriHex, 'hex');
sha256.update(data);
return sha256.digest('hex');
},
/**
* sha256转buf
* @param buf
* @returns {*}
*/
getSha256TiwceBuf: function (buf) {
return Hash.sha256sha256(buf);
},
/**
* 获取owner
* @param txHash
* @param fromIndex
* @returns {string}
*/
getOwner: function (txHash, fromIndex) {
let buf = toUInt16LE(fromIndex);
return txHash + buf.toString("hex");
},
/**
* 获取txhash
* @param transaction
* @returns {*}
*/
getTxHash: function (transaction) {
let bytes = transaction.serializeForHash();
transaction.hash = this.getSha256TiwceBuf(bytes);
return transaction.hash;
},
addressEquals: function (addressV1, addressV2) {
let bytesV1 = bs58.decode(addressV1);
bytesV1 = bytesV1.slice(2, bytesV1.length - 1);
let bytesV2 = this.getBytesAddress(addressV2);
bytesV2 = bytesV2.slice(2, bytesV2.length);
return bytesV1.equals(bytesV2);
},
getVarIntLength: function (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 (buffer, cursor) {
},
newProgramEncodePacked: function (args) {
let encodePacked = new programEncodePacked.ProgramEncodePacked();
if (args) {
encodePacked.argsCount = args.length;
encodePacked.args = args;
}
return encodePacked.serialize().toString('hex');
},
parseProgramEncodePacked: function (data) {
let encodePacked = new programEncodePacked.ProgramEncodePacked();
let bufferReader = new BufferReader(Buffer.from(data, "hex"), 0);
encodePacked.parse(bufferReader);
return encodePacked.args;
},
getL1Fee: function (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);
}
}
};