-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(jellyfish-api-core): add signMessage RPC (#1934)
**What this PR does / why we need it:** /kind feature **Which issue(s) does this PR fixes?:** Adding `signMessage()` from [Issue#48](#48) This features allow users to sign an arbitrary message using the private key of an address. It requires wallet passphrase to be set with `walletpassphrase` call if the wallet is encrypted. **Additional comments?:** The primary purpose of `signMessage()` is to present a signature to showcase that the funds are in the control of the private key holder. The holder may also generate a signature with custom prefixes to showcase proof of authorisation. Usage Example: [Here](https://bitcoin.stackexchange.com/a/3339/160)
- Loading branch information
Showing
3 changed files
with
146 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
packages/jellyfish-api-core/__tests__/category/wallet/signMessage.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { MasterNodeRegTestContainer } from '@defichain/testcontainers' | ||
import { ContainerAdapterClient } from '../../container_adapter_client' | ||
import { RpcApiError } from '@defichain/jellyfish-api-core' | ||
import { wallet } from '../../../src' | ||
|
||
describe('Sign Message on masternode by unlocking encrpyted wallet', () => { | ||
const container = new MasterNodeRegTestContainer() | ||
const client = new ContainerAdapterClient(container) | ||
|
||
beforeAll(async () => { | ||
await container.start() | ||
await client.call('encryptwallet', ['password'], 'number') | ||
await client.call('walletpassphrase', ['password', 10000], 'number') | ||
}) | ||
|
||
afterAll(async () => { | ||
await container.stop() | ||
}) | ||
|
||
it('should throw error if BECH32 address is provided', async () => { | ||
// getNewAddress() generates a BECH32 address by default | ||
// signMessage() is not compatible with BECH32 address | ||
const address = await client.wallet.getNewAddress() | ||
const message = 'This is a test message' | ||
|
||
const promise = client.wallet.signMessage(address, message) | ||
|
||
await expect(promise).rejects.toThrow(RpcApiError) | ||
await expect(promise).rejects.toMatchObject({ | ||
payload: { | ||
code: -3, | ||
message: 'Address does not refer to key', | ||
method: 'signmessage' | ||
} | ||
}) | ||
}) | ||
|
||
it('should throw error if P2SH address is provided', async () => { | ||
// signMessage() is not compatible with P2SH address | ||
const address = await client.wallet.getNewAddress('', wallet.AddressType.P2SH_SEGWIT) | ||
const message = 'This is a test message' | ||
|
||
const promise = client.wallet.signMessage(address, message) | ||
|
||
await expect(promise).rejects.toThrow(RpcApiError) | ||
await expect(promise).rejects.toMatchObject({ | ||
payload: { | ||
code: -3, | ||
message: 'Address does not refer to key', | ||
method: 'signmessage' | ||
} | ||
}) | ||
}) | ||
|
||
it('should throw error if invalid/no address is provided', async () => { | ||
const message = 'This is a test message' | ||
const promise = client.wallet.signMessage('', message) | ||
|
||
await expect(promise).rejects.toThrow(RpcApiError) | ||
await expect(promise).rejects.toMatchObject({ | ||
payload: { | ||
code: -3, | ||
message: 'Invalid address', | ||
method: 'signmessage' | ||
} | ||
}) | ||
}) | ||
|
||
it('should throw error if address provided does not contain private key', async () => { | ||
const message = 'This is a test message' | ||
const address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB' | ||
const promise = client.wallet.signMessage(address, message) | ||
|
||
await expect(promise).rejects.toThrow(RpcApiError) | ||
await expect(promise).rejects.toMatchObject({ | ||
payload: { | ||
code: -4, | ||
message: 'Private key not available', | ||
method: 'signmessage' | ||
} | ||
}) | ||
}) | ||
|
||
it('should be verifiable using verifyMessage()', async () => { | ||
// signMessage() is compatible with LEGACY address | ||
const address = await client.wallet.getNewAddress('', wallet.AddressType.LEGACY) | ||
const message = 'This is a test message' | ||
|
||
const signature = await client.wallet.signMessage(address, message) | ||
|
||
const verify = await client.call('verifymessage', [address, signature, message], 'number') | ||
expect(verify).toStrictEqual(true) | ||
}) | ||
}) | ||
|
||
describe('Sign Message on masternode without unlocking encrypted wallet', () => { | ||
const container = new MasterNodeRegTestContainer() | ||
const client = new ContainerAdapterClient(container) | ||
|
||
beforeAll(async () => { | ||
await container.start() | ||
await client.call('encryptwallet', ['password'], 'number') | ||
}) | ||
|
||
afterAll(async () => { | ||
await container.stop() | ||
}) | ||
|
||
it('should throw error even with compatible address', async () => { | ||
// signMessage() is compatible with LEGACY address | ||
const address = await client.wallet.getNewAddress('LEGACY example', wallet.AddressType.LEGACY) | ||
const message = 'This is a test message' | ||
|
||
const promise = client.wallet.signMessage(address, message) | ||
|
||
await expect(promise).rejects.toThrow(RpcApiError) | ||
await expect(promise).rejects.toMatchObject({ | ||
payload: { | ||
code: -13, | ||
message: 'Error: Please enter the wallet passphrase with walletpassphrase first.' | ||
} | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters