diff --git a/package-lock.json b/package-lock.json index 5dd992b4..692fdc1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -374,6 +374,14 @@ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", "dev": true }, + "@types/brorand": { + "version": "1.0.30", + "resolved": "https://registry.npmjs.org/@types/brorand/-/brorand-1.0.30.tgz", + "integrity": "sha1-NmaYVFCddw4TA3xYBMyAlfwcors=", + "requires": { + "@types/node": "*" + } + }, "@types/chai": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz", @@ -8482,6 +8490,16 @@ "typedarray-to-buffer": "^3.1.5" } }, + "xrpl-secret-numbers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xrpl-secret-numbers/-/xrpl-secret-numbers-0.2.1.tgz", + "integrity": "sha512-jC9LVNoX6vKmIGip43uuS+yi/R2hdnI+f9QeFTXzZFN+0SBSaSeBxDeGXV7DoBUn1/9Z+mR0nn4cHsDS/+uQjA==", + "requires": { + "@types/brorand": "^1.0.30", + "brorand": "^1.1.0", + "ripple-keypairs": "^1.0.0" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 1ad861c7..90e7fd38 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "grpc-web": "1.0.7", "ripple-address-codec": "4.1.1", "ripple-binary-codec": "0.2.6", - "ripple-keypairs": "^1.0.0" + "ripple-keypairs": "^1.0.0", + "xrpl-secret-numbers": "^0.2.1" }, "scripts": { "build": "npm run clean && ./scripts/regenerate_protos.sh && npm run lint && tsc -d && copyfiles -u 3 './src/XRP/generated/**/*' ./build/src/XRP/generated", diff --git a/rippled b/rippled index f76a5a31..90d9ca90 160000 --- a/rippled +++ b/rippled @@ -1 +1 @@ -Subproject commit f76a5a3183f0cfb8ba67d0cee252a85ad07caea3 +Subproject commit 90d9ca901d06b9da1653526c234bc4b00e27070b diff --git a/src/XRP/wallet.ts b/src/XRP/wallet.ts index 944afe22..d4594b75 100644 --- a/src/XRP/wallet.ts +++ b/src/XRP/wallet.ts @@ -1,8 +1,8 @@ import * as bip32 from 'bip32' import * as bip39 from 'bip39' import * as rippleKeyPair from 'ripple-keypairs' - -import Utils from '../Common/utils' +import { Account as SecretNumbersAccount } from 'xrpl-secret-numbers' +import Utils from './utils' /** * The default derivation path to use with BIP44. @@ -132,6 +132,26 @@ class Wallet { } } + /** + * Generate a new wallet from the given secret numbers. + * + * @param secretNumbers The given seed for the wallet. + * @param test Whether the address is for use on a test network, defaults to `false`. + * @returns A new wallet from the given seed, or undefined if the seed was invalid. + */ + public static generateWalletFromSecretNumbers( + secretNumbers: string | string[], + test = false, + ): Wallet | undefined { + try { + const account = new SecretNumbersAccount(secretNumbers) + const keyPair = account.getKeypair() + return new Wallet(keyPair.publicKey, keyPair.privateKey, test) + } catch (exception) { + return undefined + } + } + /** * Create a new Wallet object. * diff --git a/test/XRP/wallet.test.ts b/test/XRP/wallet.test.ts index d84a8158..4e432016 100644 --- a/test/XRP/wallet.test.ts +++ b/test/XRP/wallet.test.ts @@ -215,6 +215,56 @@ describe('wallet', function (): void { assert.isUndefined(wallet) }) + it('walletFromSecretNumbers - MainNet', function(): void { + // GIVEN a seed used to generate a wallet on MainNet + const seed = [ + '554872', + '394230', + '209376', + '323698', + '140250', + '387423', + '652803', + '258676', + ] + const isTestNet = false + + // WHEN a wallet is generated from the seed. + const wallet = Wallet.generateWalletFromSecretNumbers(seed, isTestNet) + + // THEN the wallet has the expected address. + assert.equal( + wallet!.getAddress(), + 'XVPCcgRJZmYGpSczab57QWbcoTnP2FQsKrCTFWughwrqBH2', + ) + }) + + it('walletFromSecretNumbers - TestNet', function(): void { + // GIVEN a seed used to generate a wallet on TestNet + const seed = '554872 394230 209376 323698 140250 387423 652803 258676' + const test = true + + // WHEN a wallet is generated from the seed. + const wallet = Wallet.generateWalletFromSecretNumbers(seed, test) + + // THEN the wallet has the expected address. + assert.equal( + wallet!.getAddress(), + 'TVKUp82HRjaHTxPb4QTEJWMXGtcUaQhnGBcv3U9UekYpy9T', + ) + }) + + it('walletFromSecretNumbers - invalid seed', function(): void { + // GIVEN an invalid seed. + const seed = '554872 394230 209372 323695 140250 387423 652803 258676' + + // WHEN a wallet is generated from the seed. + const wallet = Wallet.generateWalletFromSecretNumbers(seed) + + // THEN the wallet is undefined. + assert.isUndefined(wallet) + }) + it('sign', function (): void { // GIVEN a wallet. const testData = derivationPathTestCases.index0