diff --git a/packages/jellyfish-api-core/__tests__/category/wallet/dumpPrivKey.test.ts b/packages/jellyfish-api-core/__tests__/category/wallet/dumpPrivKey.test.ts new file mode 100644 index 0000000000..cf78084d18 --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/wallet/dumpPrivKey.test.ts @@ -0,0 +1,37 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import { ContainerAdapterClient } from '../../container_adapter_client' +import waitForExpect from 'wait-for-expect' + +describe('DumpPrivKey', () => { + const container = new MasterNodeRegTestContainer() + const client = new ContainerAdapterClient(container) + + beforeAll(async () => { + await container.start() + await container.waitForReady() + await container.waitForWalletCoinbaseMaturity() + await container.waitForWalletBalanceGTE(101) + }) + + afterAll(async () => { + await container.stop() + }) + + it('should reveal private key of given address', async () => { + await waitForExpect(async () => { + const address = 'mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU' + const privateKey = await client.wallet.dumpPrivKey(address) + + expect(typeof privateKey).toStrictEqual('string') + expect(privateKey).toStrictEqual('cRiRQ9cHmy5evDqNDdEV8f6zfbK6epi9Fpz4CRZsmLEmkwy54dWz') + }) + }) + + it('should throw and error when invalid DFI address is provided', async () => { + await waitForExpect(async () => { + const invalidAddress = 'invalidAddress' + + await expect(client.wallet.dumpPrivKey(invalidAddress)).rejects.toThrow('Invalid Defi address') + }) + }) +}) diff --git a/packages/jellyfish-api-core/__tests__/category/wallet/importPrivkey.test.ts b/packages/jellyfish-api-core/__tests__/category/wallet/importPrivkey.test.ts new file mode 100644 index 0000000000..6480ef4ba4 --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/wallet/importPrivkey.test.ts @@ -0,0 +1,45 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import { ContainerAdapterClient } from '../../container_adapter_client' + +describe('ImportPrivKey', () => { + const container = new MasterNodeRegTestContainer() + const client = new ContainerAdapterClient(container) + + beforeAll(async () => { + await container.start() + await container.waitForReady() + await container.waitForWalletCoinbaseMaturity() + }) + + afterAll(async () => { + await container.stop() + }) + + it('should import private key without failing ', async () => { + const privatekey = await client.wallet.dumpPrivKey(await client.wallet.getNewAddress()) + const promise = client.wallet.importPrivKey(privatekey) + + await expect(promise).resolves.not.toThrow() + }) + + it('should import private key with rescan set to false', async () => { + const privateKey = await client.wallet.dumpPrivKey(await client.wallet.getNewAddress()) + const promise = client.wallet.importPrivKey(privateKey, '', false) + + await expect(promise).resolves.not.toThrow() + }) + + it('should import private key with label passed', async () => { + const privateKey = await client.wallet.dumpPrivKey(await client.wallet.getNewAddress('testing')) + const promise = client.wallet.importPrivKey(privateKey, 'testing') + + await expect(promise).resolves.not.toThrow() + }) + + it('should fail and throw an error with invalid private key', async () => { + const privateKey = 'invalidPrivateKey' + const promise = client.wallet.importPrivKey(privateKey) + + await expect(promise).rejects.toThrow('Invalid private key encoding') + }) +}) diff --git a/packages/jellyfish-api-core/__tests__/category/wallet.test.ts b/packages/jellyfish-api-core/__tests__/category/wallet/wallet.test.ts similarity index 99% rename from packages/jellyfish-api-core/__tests__/category/wallet.test.ts rename to packages/jellyfish-api-core/__tests__/category/wallet/wallet.test.ts index 6548a2dab3..f5d594cdbb 100644 --- a/packages/jellyfish-api-core/__tests__/category/wallet.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/wallet/wallet.test.ts @@ -1,6 +1,6 @@ -import { ContainerAdapterClient } from '../container_adapter_client' +import { ContainerAdapterClient } from '../../container_adapter_client' import { MasterNodeRegTestContainer, RegTestContainer } from '@defichain/testcontainers' -import { BigNumber, wallet } from '../../src' +import { BigNumber, wallet } from '../../../src' import waitForExpect from 'wait-for-expect' import { UTXO, @@ -9,7 +9,7 @@ import { SendToAddressOptions, Mode, SendManyOptions -} from '../../src/category/wallet' +} from '../../../src/category/wallet' describe('getBalance', () => { describe('regtest', () => { diff --git a/packages/jellyfish-api-core/src/category/wallet.ts b/packages/jellyfish-api-core/src/category/wallet.ts index a22748ee1e..fc9ca2e743 100644 --- a/packages/jellyfish-api-core/src/category/wallet.ts +++ b/packages/jellyfish-api-core/src/category/wallet.ts @@ -249,6 +249,27 @@ export class Wallet { 'bignumber' ) } + + /** + * Reveals the private key corresponding to an address. + * + * @param {string} address The DFI address for the private key. + * @return {Promise} + */ + async dumpPrivKey (address: string): Promise { + return await this.client.call('dumpprivkey', [address], 'number') + } + + /** + * Adds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup. + * + * @param {string} privkey The private key (see dumpprivkey) + * @param {string} [label=""] current label if address exists, otherwise "". + * @param {boolean} [rescan=true] Rescan the wallet for transactions + */ + async importPrivKey (privkey: string, label: string = '', rescan: boolean = true): Promise { + return await this.client.call('importprivkey', [privkey, label, rescan], 'number') + } } export interface UTXO { diff --git a/website/docs/jellyfish/api/wallet.md b/website/docs/jellyfish/api/wallet.md index e0cad446c0..cecf1e23fc 100644 --- a/website/docs/jellyfish/api/wallet.md +++ b/website/docs/jellyfish/api/wallet.md @@ -279,3 +279,23 @@ enum Mode { CONSERVATIVE = 'CONSERVATIVE' } ``` + +## dumpPrivKey + +Reveals the private key corresponding to an address. + +```ts title="client.wallet.dumpPrivKey()" +interface wallet { + dumpPrivKey (address: string): Promise +} +``` + +## importPrivKey + +Adds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup. + +```ts title="client.wallet.importPrivKey()" +interface wallet { + importPrivKey (privkey: string, label: string = "", rescan: boolean = true): Promise +} +```