Skip to content

Commit

Permalink
Merge pull request #10 from vansergen/util
Browse files Browse the repository at this point in the history
Util
  • Loading branch information
vansergen authored Oct 24, 2019
2 parents a858b07 + 4f8abe6 commit ffdfd87
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 3 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"hash_or_height",
"include_mempool",
"template_request",
"fee_delta"
"fee_delta",
"address_type",
"estimate_mode",
"conf_target"
]
}
]
Expand Down
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,70 @@ const state = false;
const result = await client.setnetworkactive({ state });
```

### Util

- [`createmultisig`](https://bitcoin.org/en/developer-reference#createmultisig)

```javascript
const nrequired = 2;
const keys = [
"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd",
"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626"
];
const address_type = "bech32";
const result = await client.createmultisig({ nrequired, keys, address_type });
```

- [`deriveaddresses`](https://bitcoin.org/en/developer-reference#deriveaddresses)

```javascript
const descriptor =
"wpkh([d34db33f/84'/0'/0']tpubD6NzVbkrYhZ4YTN7usjEzYmfu4JKqnfp9RCbDmdKH78vTyuwgQat8vRw5cX1YaZZvFfQrkHrM2XsyfA8cZE1thA3guTBfTkKqbhCDpcKFLG/0/*)#8gfuh6ex";
const range = [0, 2];
const result = await client.deriveaddresses({ descriptor, range });
```

- [`estimatesmartfee`](https://bitcoin.org/en/developer-reference#estimatesmartfee)

```javascript
const conf_target = 2;
const estimate_mode = "ECONOMICAL";
const result = await client.estimatesmartfee({ conf_target, estimate_mode });
```

- [`getdescriptorinfo`](https://bitcoin.org/en/developer-reference#getdescriptorinfo)

```javascript
const descriptor =
"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)";
const result = await client.getdescriptorinfo({ descriptor });
```

- [`signmessagewithprivkey`](https://bitcoin.org/en/developer-reference#signmessagewithprivkey)

```javascript
const privkey = "yourPrivateKey";
const message = "Hello World";
const result = await client.signmessagewithprivkey({ privkey, message });
```

- [`validateaddress`](https://bitcoin.org/en/developer-reference#validateaddress)

```javascript
const address = "1HLoD9E4SDFFPDiYfNYnkBLQ85Y51J3Zb1";
const result = await client.validateaddress({ address });
```

- [`verifymessage`](https://bitcoin.org/en/developer-reference#verifymessage)

```javascript
const address = "myv3xs1BBBhaDVU62LFNBho2zSp4KLBkgK";
const message = "Hello World";
const signature =
"H14/QyrMj8e63GyEXBDDWnWrplXK3OORnMc3B+fEOOisbNFEAQuNB9myAH9qs7h1VNJb1xq1ytPQqiLcmSwwPv8=";
const result = await client.verifymessage({ address, message, signature });
```

### ZMQ

- [`getzmqnotifications`](https://bitcoincore.org/en/doc/0.17.0/rpc/zmq/getzmqnotifications/)
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rpc-bitcoin",
"version": "1.7.0",
"version": "1.8.0",
"description": "A TypeScript library to make RPC and HTTP REST requests to Bitcoin Core",
"main": "build/index.js",
"type": "module",
Expand Down
86 changes: 86 additions & 0 deletions src/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,33 @@ export type SetBanParams = {
absolute?: boolean;
};

export type CreateMultiSigParams = {
nrequired: number;
keys: string[];
address_type?: "legacy" | "p2sh-segwit" | "bech32";
};

export type DeriveAddressesParams = {
descriptor: string;
range?: number | [number, number];
};

export type EstimateSmartFeeParams = {
conf_target: number;
estimate_mode?: "UNSET" | "ECONOMICAL" | "CONSERVATIVE";
};

export type SignMessageWithPrivKeyParams = {
privkey: string;
message: string;
};

export type VerifyMessageParams = {
address: string;
signature: string;
message: string;
};

export class RPCClient extends RESTClient {
wallet?: string;
fullResponse?: boolean;
Expand Down Expand Up @@ -514,6 +541,65 @@ export class RPCClient extends RESTClient {
return this.rpc("setnetworkactive", { state });
}

/**
* @description Creates a multi-signature address with n signature of m keys required.
*/
async createmultisig({
nrequired,
keys,
address_type = "legacy"
}: CreateMultiSigParams) {
return this.rpc("createmultisig", { nrequired, keys, address_type });
}

/**
* @description Derives one or more addresses corresponding to an output descriptor.
*/
async deriveaddresses({ descriptor, range }: DeriveAddressesParams) {
return this.rpc("deriveaddresses", { descriptor, range });
}

/**
* @description Estimates the approximate fee per kilobyte needed for a transaction to begin confirmation within `conf_target` blocks if possible and return the number of blocks for which the estimate is valid.
*/
async estimatesmartfee({
conf_target,
estimate_mode = "CONSERVATIVE"
}: EstimateSmartFeeParams) {
return this.rpc("estimatesmartfee", { conf_target, estimate_mode });
}

/**
* @description Analyses a descriptor.
*/
async getdescriptorinfo({ descriptor }: { descriptor: string }) {
return this.rpc("getdescriptorinfo", { descriptor });
}

/**
* @description Sign a message with the private key of an address.
*/
async signmessagewithprivkey({
privkey,
message
}: SignMessageWithPrivKeyParams) {
return this.rpc("signmessagewithprivkey", { privkey, message });
}

/**
* @description Return information about the given bitcoin address.
*/
async validateaddress({ address }: { address: string }) {
return this.rpc("validateaddress", { address });
}

/**
* @description Verify a signed message
*/
async verifymessage({ address, signature, message }: VerifyMessageParams) {
return this.rpc("verifymessage", { address, signature, message });
}

/**
* @description Returns information about the active ZeroMQ notifications.
*/
Expand Down
135 changes: 135 additions & 0 deletions test/rpc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,141 @@ suite("RPCClient", () => {
});
});

suite("Util", () => {
test(".createmultisig()", async () => {
const nrequired = 2;
const keys = [
"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd",
"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626"
];
const address_type: "bech32" = "bech32";
const params = { nrequired, keys, address_type };
const request = { params, method: "createmultisig", id, jsonrpc };
const result = {
address:
"tb1q0jnggjwnn22a4ywxc2pcw86c0d6tghqkgk3hlryrxl7nmxkylmnqdcdsu7",
redeemScript:
"522103789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd2103dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a6162652ae"
};
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.createmultisig(params);
assert.deepStrictEqual(data, result);
});

test(".deriveaddresses()", async () => {
const descriptor =
"wpkh([d34db33f/84'/0'/0']tpubD6NzVbkrYhZ4YTN7usjEzYmfu4JKqnfp9RCbDmdKH78vTyuwgQat8vRw5cX1YaZZvFfQrkHrM2XsyfA8cZE1thA3guTBfTkKqbhCDpcKFLG/0/*)#8gfuh6ex";
const range: [number, number] = [0, 2];
const params = { descriptor, range };
const request = { params, method: "deriveaddresses", id, jsonrpc };
const result = [
"tb1q7as9cz0t8rfng5f0xdklfgyp0x6ya0tu6ckaqs",
"tb1q0aducdmz77tfu4dhfez8ayycmp2pz6jwy85hhn",
"tb1qsdqewd8upv66txx48qssr0an5r3llaxtwqzytk"
];
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.deriveaddresses(params);
assert.deepStrictEqual(data, result);
});

test(".estimatesmartfee()", async () => {
const estimate_mode: "ECONOMICAL" = "ECONOMICAL";
const params = { conf_target: 2, estimate_mode };
const request = { params, method: "estimatesmartfee", id, jsonrpc };
const result = { feerate: 0.00001, blocks: 2 };
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.estimatesmartfee(params);
assert.deepStrictEqual(data, result);
});

test(".getdescriptorinfo()", async () => {
const descriptor =
"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)";
const params = { descriptor };
const request = { params, method: "getdescriptorinfo", id, jsonrpc };
const result = {
descriptor:
"wpkh([d34db33f/84'/0'/0']0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#n9g43y4k",
isrange: false,
issolvable: true,
hasprivatekeys: false
};
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.getdescriptorinfo(params);
assert.deepStrictEqual(data, result);
});

test(".signmessagewithprivkey()", async () => {
const privkey = "cPGLkRL4zvHfpcEkjPb93GEHth8WZpTJH2YCCoYWS7kHcFFarn8U";
const message = "Hello World";
const params = { privkey, message };
const request = { params, method: "signmessagewithprivkey", id, jsonrpc };
const result =
"IIXi7nhOGKbW2uOW2cmV/BbOvlIDzVu0KTZdvntP634/BRL2DmFSvtwifkDMa+pDKd+eRrTbEi6XVAc82JKTiwA=";
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.signmessagewithprivkey(params);
assert.deepStrictEqual(data, result);
});

test(".validateaddress()", async () => {
const params = { address: "tb1qmv634mfk34sks9z3tcwwncd9ug0why3a0pl4px" };
const request = { params, method: "validateaddress", id, jsonrpc };
const result = {
isvalid: true,
address: "tb1qmv634mfk34sks9z3tcwwncd9ug0why3a0pl4px",
scriptPubKey: "0014db351aed368d616814515e1ce9e1a5e21eeb923d",
isscript: false,
iswitness: true,
witness_version: 0,
witness_program: "db351aed368d616814515e1ce9e1a5e21eeb923d"
};
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.validateaddress(params);
assert.deepStrictEqual(data, result);
});

test(".verifymessage()", async () => {
const address = "myv3xs1BBBhaDVU62LFNBho2zSp4KLBkgK";
const signature =
"H14/QyrMj8e63GyEXBDDWnWrplXK3OORnMc3B+fEOOisbNFEAQuNB9myAH9qs7h1VNJb1xq1ytPQqiLcmSwwPv8=";
const message = "Hello World";
const params = { address, signature, message };
const request = { params, method: "verifymessage", id, jsonrpc };
const result = true;
nock(uri)
.post("/", request)
.times(1)
.basicAuth(auth)
.reply(200, { result, error, id });
const data = await client.verifymessage(params);
assert.deepStrictEqual(data, result);
});
});

suite("Zmq", () => {
test(".getzmqnotifications()", async () => {
const params = {};
Expand Down

0 comments on commit ffdfd87

Please sign in to comment.