1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | import * as rippleKeypairs from 'ripple-keypairs';
|
8 | import * as ripple from 'ripple-lib';
|
9 | import { ECPair } from '@bitgo/utxo-lib';
|
10 |
|
11 | import * as binary from 'ripple-binary-codec';
|
12 | import { computeBinaryTransactionHash } from 'ripple-lib/dist/npm/common/hashes';
|
13 |
|
14 | function computeSignature(tx, privateKey, signAs) {
|
15 | const signingData = signAs ?
|
16 | binary.encodeForMultisigning(tx, signAs) : binary.encodeForSigning(tx);
|
17 | return rippleKeypairs.sign(signingData, privateKey);
|
18 | }
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | const signWithPrivateKey = function (txHex, privateKey, options) {
|
28 | let privateKeyBuffer = Buffer.from(privateKey, 'hex');
|
29 | if (privateKeyBuffer.length === 33 && privateKeyBuffer[0] === 0) {
|
30 | privateKeyBuffer = privateKeyBuffer.slice(1, 33);
|
31 | }
|
32 | const publicKey = ECPair.fromPrivateKey(privateKeyBuffer).publicKey.toString('hex').toUpperCase();
|
33 |
|
34 | let tx;
|
35 | try {
|
36 | tx = binary.decode(txHex);
|
37 | } catch (e) {
|
38 | try {
|
39 | tx = JSON.parse(txHex);
|
40 | } catch (e) {
|
41 | throw new Error('txHex needs to be either hex or JSON string for XRP');
|
42 | }
|
43 | }
|
44 | if (tx.TxnSignature || tx.Signers) {
|
45 | throw new Error('transaction must not contain "TxnSignature" or "Signers" properties');
|
46 | }
|
47 |
|
48 | tx.SigningPubKey = (options && options.signAs) ? '' : publicKey;
|
49 |
|
50 | if (options && options.signAs) {
|
51 | const expectedSigner = rippleKeypairs.deriveAddress(publicKey);
|
52 | if (options.signAs !== expectedSigner) {
|
53 | throw new Error('signAs does not match private key');
|
54 | }
|
55 | const signer = {
|
56 | Account: options.signAs,
|
57 | SigningPubKey: publicKey,
|
58 | TxnSignature: computeSignature(tx, privateKey, options.signAs),
|
59 | };
|
60 | tx.Signers = [{ Signer: signer }];
|
61 | } else {
|
62 | tx.TxnSignature = computeSignature(tx, privateKey, undefined);
|
63 | }
|
64 |
|
65 | const serialized = binary.encode(tx);
|
66 | return {
|
67 | signedTransaction: serialized,
|
68 | id: computeBinaryTransactionHash(serialized),
|
69 | };
|
70 | };
|
71 |
|
72 | export = (params): ripple.RippleAPI => {
|
73 | const rippleLib = new ripple.RippleAPI(params);
|
74 | (rippleLib as any).signWithPrivateKey = signWithPrivateKey;
|
75 | return rippleLib;
|
76 | };
|