PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo-express/node_modules/bitgo/src/v2/coins
Просмотр файла: xrp.js
const BaseCoin = require('../baseCoin');
const crypto = require('crypto');
const querystring = require('querystring');
const ripple = require('../../ripple');
const rippleAddressCodec = require('ripple-address-codec');
const rippleBinaryCodec = require('ripple-binary-codec');
const rippleHashes = require('ripple-hashes');
const rippleKeypairs = require('ripple-keypairs');
const url = require('url');
const prova = require('../../prova');
const Q = require('q');
const common = require('../../common');
const _ = require('lodash');
const Xrp = function() {
// this function is called externally from BaseCoin
// replace the BaseCoin prototype with the local override prototype, which inherits from BaseCoin
// effectively, move the BaseCoin prototype one level away
this.__proto__ = Xrp.prototype;
// TODO: replace dependency with platform IMS
};
Xrp.prototype.__proto__ = BaseCoin.prototype;
/**
* Returns the factor between the base unit and its smallest subdivison
* @return {number}
*/
Xrp.prototype.getBaseFactor = function() {
return 1e6;
};
Xrp.prototype.getChain = function() {
return 'xrp';
};
Xrp.prototype.getFamily = function() {
return 'xrp';
};
/**
* Evaluates whether an address string is valid for this coin
* @param address
*/
Xrp.prototype.isValidAddress = function(address) {
const destinationDetails = url.parse(address);
const queryDetails = querystring.parse(destinationDetails.query);
const destinationAddress = destinationDetails.pathname;
if (!rippleAddressCodec.isValidAddress(destinationAddress)) {
return false;
}
// there are no other properties like destination tags
if (destinationDetails.pathname === address) {
return true;
}
if (!queryDetails.dt) {
// if there are more properties, the query details need to contain the destination tag property
return false;
}
const parsedTag = parseInt(queryDetails.dt);
if (!Number.isSafeInteger(parsedTag)) {
return false;
}
if (parsedTag > 0xFFFFFFFF || parsedTag < 0) {
return false;
}
// the simplest form, reconstruction after the deconstruction, should be deterministic
const normalizedAddress = `${destinationAddress}?dt=${parsedTag}`;
return normalizedAddress === address;
};
/**
* Get fee info from server
* @param params
* @param callback
* @returns {*}
*/
Xrp.prototype.getFeeInfo = function(params, callback) {
return this.bitgo.get(this.url('/public/feeinfo'))
.result()
.nodeify(callback);
};
/**
* Assemble keychain and half-sign prebuilt transaction
* @param params
* - txPrebuild
* - prv
* @returns {{txHex}}
*/
Xrp.prototype.signTransaction = function(params) {
const txPrebuild = params.txPrebuild;
const userPrv = params.prv;
const userKey = prova.HDNode.fromBase58(userPrv).getKey();
const userPrivateKey = userKey.getPrivateKeyBuffer();
const userAddress = rippleKeypairs.deriveAddress(userKey.getPublicKeyBuffer().toString('hex'));
const rippleLib = ripple();
const halfSigned = rippleLib.signWithPrivateKey(txPrebuild.txHex, userPrivateKey.toString('hex'), { signAs: userAddress });
return { halfSigned: { txHex: halfSigned.signedTransaction } };
};
/**
* Ripple requires additional parameters for wallet generation to be sent to the server. The additional parameters are
* the root public key, which is the basis of the root address, two signed, and one half-signed initialization txs
* @param walletParams
* - rootPrivateKey: optional hex-encoded Ripple private key
* @param keychains
* @return {*|Request|Promise.<TResult>|{anyOf}}
*/
Xrp.prototype.supplementGenerateWallet = function(walletParams, keychains) {
const { userKeychain, backupKeychain, bitgoKeychain } = keychains;
const userKey = prova.HDNode.fromBase58(userKeychain.pub).getKey();
const userAddress = rippleKeypairs.deriveAddress(userKey.getPublicKeyBuffer().toString('hex'));
const backupKey = prova.HDNode.fromBase58(backupKeychain.pub).getKey();
const backupAddress = rippleKeypairs.deriveAddress(backupKey.getPublicKeyBuffer().toString('hex'));
const bitgoKey = prova.HDNode.fromBase58(bitgoKeychain.pub).getKey();
const bitgoAddress = rippleKeypairs.deriveAddress(bitgoKey.getPublicKeyBuffer().toString('hex'));
// initially, we need to generate a random root address which has to be distinct from all three keychains
let keyPair = prova.ECPair.makeRandom();
if (walletParams.rootPrivateKey) {
const rootPrivateKey = walletParams.rootPrivateKey;
if (typeof rootPrivateKey !== 'string' || rootPrivateKey.length !== 64) {
throw new Error('rootPrivateKey needs to be a hexadecimal private key string')
}
keyPair = prova.ECPair.fromPrivateKeyBuffer(Buffer.from(walletParams.rootPrivateKey, 'hex'));
}
const privateKey = keyPair.getPrivateKeyBuffer();
const publicKey = keyPair.getPublicKeyBuffer();
const rootAddress = rippleKeypairs.deriveAddress(publicKey.toString('hex'));
let signedMultisigAssignmentTx;
let signedMasterDeactivationTx;
let signedDestinationTagTx;
const self = this;
const rippleLib = ripple();
return self.getFeeInfo()
.then(function(feeInfo) {
// TODO: get recommended fee from server instead of doing number magic
const fee = feeInfo.xrpOpenLedgerFee;
const ledgerVersion = feeInfo.height;
// configure multisigners
const multisigAssignmentTx = {
TransactionType: 'SignerListSet',
Account: rootAddress,
SignerQuorum: 2,
SignerEntries: [
{
SignerEntry: {
Account: userAddress,
SignerWeight: 1
}
},
{
SignerEntry: {
Account: backupAddress,
SignerWeight: 1
}
},
{
SignerEntry: {
Account: bitgoAddress,
SignerWeight: 1
}
}
],
Flags: 2147483648,
LastLedgerSequence: ledgerVersion + 10,
Fee: `${fee}`,
Sequence: 1
};
signedMultisigAssignmentTx = rippleLib.signWithPrivateKey(JSON.stringify(multisigAssignmentTx), privateKey.toString('hex'));
// enforce destination tags
const destinationTagTx = {
TransactionType: 'AccountSet',
Account: rootAddress,
SetFlag: 1,
Flags: 2147483648,
LastLedgerSequence: ledgerVersion + 10,
Fee: `${fee}`,
Sequence: 2
};
signedDestinationTagTx = rippleLib.signWithPrivateKey(JSON.stringify(destinationTagTx), privateKey.toString('hex'));
// disable master key
const masterDeactivationTx = {
TransactionType: 'AccountSet',
Account: rootAddress,
SetFlag: 4,
Flags: 2147483648,
LastLedgerSequence: ledgerVersion + 10,
Fee: `${fee}`,
Sequence: 3
};
signedMasterDeactivationTx = rippleLib.signWithPrivateKey(JSON.stringify(masterDeactivationTx), privateKey.toString('hex'));
// extend the wallet initialization params
walletParams.rootPub = publicKey.toString('hex');
walletParams.initializationTxs = {
setMultisig: signedMultisigAssignmentTx.signedTransaction,
disableMasterKey: signedMasterDeactivationTx.signedTransaction,
forceDestinationTag: signedDestinationTagTx.signedTransaction
};
return walletParams;
});
};
/**
* Explain/parse transaction
* @param params
* - txHex: hexadecimal representation of transaction
* @returns {{displayOrder: [string,string,string,string,string], id: *, outputs: Array, changeOutputs: Array}}
*/
Xrp.prototype.explainTransaction = function(params) {
var transaction = rippleBinaryCodec.decode(params.txHex);
var id = rippleHashes.computeBinaryTransactionHash(params.txHex);
var changeAmount = 0;
var explanation = {
displayOrder: ['id', 'outputAmount', 'changeAmount', 'outputs', 'changeOutputs'],
id: id,
outputs: [],
changeOutputs: []
};
explanation.outputs = [{
address: transaction.Destination + ((transaction.DestinationTag >= 0) ? '?dt=' + transaction.DestinationTag : ''),
amount: transaction.Amount
}];
const spendAmount = transaction.Amount;
explanation.outputAmount = spendAmount;
explanation.changeAmount = changeAmount;
// add fee info if available
if (params.feeInfo) {
explanation.displayOrder.push('fee');
explanation.fee = params.feeInfo;
}
return explanation;
};
module.exports = Xrp;
Выполнить команду
Для локальной разработки. Не используйте в интернете!