Multisig HTTP Server adds some API methods and disables several existing ones.
It's recommended, that you setup API_KEY
for HTTP in general and turn on walletAuth
.
This will make sure no route can be called without authentication.
You will still need to set API_KEY
for http server, which is same as Node HTTP or Wallet HTTP in
bcoin.
Multisig wallet uses cosigner token
s to authenticate cosigners, that are configured by cosigners
when joining. (NOTE: Admin token wont be able to access cosigner APIs. So don't use admin token
as cosigner token.)
There are some routes that do not require authentication or only admin token
can query.
Some endpoints need signatures and public keys, you can check recent updates: signing This document will also include some steps to reproduce signatures.
Some examples:
- PUT /multisig/:id* - used for wallet creation does not need any authentication (you should use
API_KEY
to control access to the API itself). - GET /multisig/:id/proposal/ - can be requested using cosigner token.
- GET /multisig* and DEL /multisig/:id can be requested only with admin
token
. - POST /multisig/join* - will check
joinSignature
. - POST /multisig/:id/proposal - needs
signature
(usingauthPubKey
).
All endpoint definitions contain examples what is data and how to sign. For more details check signing.
Note: this examples will use regtest
network serializations.
This will return list of the available multisig wallets
await client.getWallets(); // returns [ 'mswallet1', 'mswallet2' ]
HTTP Response
{ wallets: [ 'mswallet1', 'mswallet2' ]
Create multisig wallet.
Before creating multisig wallet, client needs to generate secret key, that will be used for joining by other cosigners. Client also needs to pass cosigner data with creation. (Author of the wallet joins on creation.)
Data to sign for joinSignature
:
Data to sign for accountKeyProof
and authPubKey
- description:
walletName || cosignerName || authPubKey || accountKey
- example:
- walletName:
test
(74657374
) - cosignerName:
cosigner1
(636f7369676e657231
) - authPubKey:
033faf1f3e2328c37addb474ef8326312a96f698bd7e18f74f75066bdcef1dd180
- raw account key:
eab4fa05032dca132f80000000acdbf8120f8d5ff1c8b40c10d8a32216746f775f695b7a55219204921f6e98ff035679212b890015d137186010db38ef4a6171da6e5549740ad7486a4896f65700aa02b755
- result:
74657374636f7369676e657231033faf1f3e2328c37addb474ef8326312a96f698bd7e18f74f75066bdcef1dd180eab4fa05032dca132f80000000acdbf8120f8d5ff1c8b40c10d8a32216746f775f695b7a55219204921f6e98ff035679212b890015d137186010db38ef4a6171da6e5549740ad7486a4896f65700aa02b755
- Now we can use
signmessage
rpc or similar apis to get the hash to sign.
- walletName:
Keys (secp256k1):
joinPrivateKey
- key generated by the author to be shared with other cosigners.accountKey
- account key used for generating addresses. (e.g. derived asm/44'/0'/0'
)accountKeyProof
- This is signature of the above message, using derivationaccountKey/0x7fffffff/0
authPubKey
- This key will be used to sign data related to proposals (creationg, rejection).joinSignature
Params (example):
// 2-of-2 multisig wallet
// wallet name: test.
{
// general wallet configs.
"id": "test",
"witness": true,
"m": 2,
"n": 2,
"cosigner": {
// this token will be used for authentication.
"token": "0101010101010101010101010101010101010101010101010101010101010101",
"name": "cosigner1",
"purpose": 44,
// master key fingerprint (not xpub)
"fingerPrint": 2654134519,
// you can put additional data up to 100 bytes.
"data": "63636363636363636363",
// base58 encoded account key. (for example, derived as m/44'/0'/0')
"accountKey": "rpubKBBSxApoKWuxYnNo3YUULJxV1LVT3nawafxrfch37rUn8v1xyt6m6METTUVRy5gMSFnUoheCe6Mba2J1iqxrb1hnDo8ndNVLG7wvc4juT42Y",
// check signing document: Wallet Joining.
"accountKeyProof": "20a304942c61b3bb7e357a18485ed210a291d8c76354f84b6ef191a421fe2800a362e24c0b9b7184ba098e9eaa6cdb9c72eeecac37d0e46bb124f55be24d521e37",
// public key that will be used for signing and verifying: proposal rejection and creation signatures.
"authPubKey": "03fff6ec2e4bb4d2f99b8e9c9bfdc6a72126424714e79a5a5ff42948bee3324099",
},
// signature of the data mentioned above using joinPrivateKey.
"joinSignature": "1fd52de8fe2ebcebdd630035702e3b6d719222b999fe750c84a92faa9c4460494f442051d0bc071205f24dad6a68d766216269af00f23967a3d767cc6d4e0c6c82",
// public key of joinPrivateKey.
"joinPubKey": "02cac403562ce31e3399d004dc6a742048598f3e75fae80f73d1d322c9b7635204"
}
await client.createWallet('name-of-wallet', { ...options });
HTTP Response:
{
"network": "regtest",
"wid": 1,
"id": "test",
"watchOnly": true,
"accountDepth": 1,
"token": null,
"tokenDepth": 0,
"master": {
"encrypted": false
},
"balance": null,
// This will become true when all cosigners join, before that cosigners can't use the wallet.
"initialized": false,
"joinPubKey": "02c16fe174fc1ceb8e25ebb244dad9c3663d408570cfaaa7b4305f7c5279772852",
"cosigners": [
{
"id": 0,
"name": "cosigner1",
"authPubKey": "0388f1eb6e232e98c6354383cb5130a56015fab1fb43eef2bd17f6511ccc0d9a9e",
"joinSignature": "20f6e7874b0977a5e148ccbbf39453772b5765a3aadfa1f6212bb1620e4fc1795337f965ff9b0417da473e617855b3ae432582f66b0d725acba90825a6da4cc71a",
"accountKey": "rpubKBB83sbxiyok5kWNmvHiMmkRpHXWh39WYLuU1zfYwjdhZVwasc4CuHnMrqoUpjAppNyVAw2MUzACiGpge8ZRuaED9QJsbh9fgHdbXLbDHsPe",
"purpose": 44,
"fingerPrint": 3664892090,
"data": "63636363636363636363",
"tokenDepth": 0,
"token": "0101010101010101010101010101010101010101010101010101010101010101"
}
]
}
Join the wallet, you will need joinPrivKey
and walletName
from the wallet author.
For details check wallet creation endpoint.
Params:
{
"cosigner": {
"name": "cosigner2",
"purpose": 44,
"fingerPrint": 2698755706,
"data": "",
"token": "0202020202020202020202020202020202020202020202020202020202020202",
"accountKey": "rpubKBAS32yftCYdYvWgXxEEH7upohWFsXP3dwp1eCNA9R7vYwVoes8bSv4NxPwsuJ4puBRCJWRSUxe1MPqYV78UtdkpGdeue5mG66yM2QGGbXmJ",
"accountKeyProof": "20d8baaec98fe57054e2c131c01a5f83774ff7acdbb2966ffc0e186dd3595a461a52d217bbeff61d6107dfc30a8dcc9099dfd7c9ff9da288d0f326af863e40a296",
"authPubKey": "03bdccfe18655a3fcba674227d0b9f383e49ade32791b140a6181b596e378ec4bf",
},
"joinSignature": "1fbd7825512a1352a461552ddc9349ad98ffbc0c543d4aac40e85b0eb38ac795967034472a1fd3b2578e3ff953a1852c90c4e7313d30c4d70185cfd36b6980c442"
}
await client.joinWallet('name-of-wallet', { ...options });
HTTP Response
{
"network": "regtest",
"wid": 1,
"id": "test",
"watchOnly": true,
"accountDepth": 1,
"token": null,
"tokenDepth": 0,
"master": {
"encrypted": false
},
"balance": null,
"initialized": true,
"joinPubKey": "031dbf621b0a5fb8a29d8144682c75e035b3f1b01aa39287d45ae15f7aaa1bf72c",
"cosigners": [
{
"id": 0,
"name": "cosigner1",
"authPubKey": "02348755bfeae058de77918f09c7f31397333715b83303014eeb36be0ac57f2310",
"joinSignature": "2077152bbab4ad2743af8619f085f3856258b255786b2083532cbe829855d9cbc551cab29777108f23d9385e4821d7e48c66a14eac6462469e06bb3e92995e9712",
"accountKey": "rpubKBAsBfPVMBBeBfD8F4EA5Dk1NAZ2dK7dc9JsE9dq9tDDF73NecpNP4z3gfMWuRm9rLVdSaeTj8BHZbVyHeRtV6UhciDz26pPDEntqCJvqKg2",
"purpose": 44,
"fingerPrint": 3664892090,
"data": "63636363636363636363",
},
{
"id": 1,
"name": "cosigner2",
"authPubKey": "0325e5fb974a2e12f954edb3dd6d851a43d6744784f2a41e12c1060aefb783a702",
"joinSignature": "1fb393639c0f8279ef3377ff0c1bb9067474f41a4b4b7301a2814d64c6abd1fb446b48f361ec91d42d4c9dd589337e98cedc24762618bebed82c2d32e8244587f4",
"accountKey": "rpubKBB7QfFrX68MzrYd7FdcjSnZmg7sPRQzYKQuEfkJGF4BWV68qu23S4wvjwvo8b4sqRwUf7uNCWmDwghKFv6tPnGFjXaY4TXQw9QQTy5zcjfu",
"purpose": 44,
"fingerPrint": 358396470,
"data": "",
"tokenDepth": 0,
"token": "0202020202020202020202020202020202020202020202020202020202020202"
}
]
}
Cosigner authentication.
Get the wallet info.
Query Params:
{
// if we want account details, e.g. address
// NOTE: there are separate account endpoints available as well,
// same as bcoin wallet.
details: true
}
await client.getInfo('name-of-wallet', true);
HTTP Response:
{
"network": "regtest",
"wid": 1,
"id": "test",
"watchOnly": true,
"accountDepth": 1,
"token": null,
"tokenDepth": 0,
"master": {
"encrypted": false
},
"balance": {
"tx": 0,
"coin": 0,
"unconfirmed": 0,
"confirmed": 0
},
"initialized": true,
"joinPubKey": "03fba95156992e6955e16ea7f887c2f158044b73573eb90f6428f3b6e61a6b1836",
"cosigners": [
{
"id": 0,
"name": "cosigner1",
"authPubKey": "02348755bfeae058de77918f09c7f31397333715b83303014eeb36be0ac57f2310",
"joinSignature": "2077152bbab4ad2743af8619f085f3856258b255786b2083532cbe829855d9cbc551cab29777108f23d9385e4821d7e48c66a14eac6462469e06bb3e92995e9712",
"accountKey": "rpubKBAsBfPVMBBeBfD8F4EA5Dk1NAZ2dK7dc9JsE9dq9tDDF73NecpNP4z3gfMWuRm9rLVdSaeTj8BHZbVyHeRtV6UhciDz26pPDEntqCJvqKg2",
"purpose": 44,
"fingerPrint": 3664892090,
"data": "63636363636363636363"
},
{
"id": 1,
"name": "cosigner2",
"authPubKey": "0325e5fb974a2e12f954edb3dd6d851a43d6744784f2a41e12c1060aefb783a702",
"joinSignature": "1fb393639c0f8279ef3377ff0c1bb9067474f41a4b4b7301a2814d64c6abd1fb446b48f361ec91d42d4c9dd589337e98cedc24762618bebed82c2d32e8244587f4",
"accountKey": "rpubKBB7QfFrX68MzrYd7FdcjSnZmg7sPRQzYKQuEfkJGF4BWV68qu23S4wvjwvo8b4sqRwUf7uNCWmDwghKFv6tPnGFjXaY4TXQw9QQTy5zcjfu",
"purpose": 44,
"fingerPrint": 358396470,
"data": ""
}
],
"proposalStats": {
"lockedOwnCoins": 0,
"lockedOwnBalance": 0,
"proposals": 0,
"pending": 0,
"approved": 0,
"rejected": 0
}
}
Delete wallet. Admin Only
await client.removeWallet('name-of-wallet'); // true/false
{
success: true
}
Cosigner authentication.
Change your current token with new one.
Params:
{
// 32 bytes (encoded as hex string)
"newToken": "0303030303030303030303030303030303030303030303030303030303030303"
}
await client.setToken(id, { newToken: ... });
HTTP Response:
{
"id": 0,
"name": "cosigner1",
"authPubKey": "033a0107dd9ecbc720d26dacca1a16d1e3678f03633a9d27542266e50dced1d657",
"joinSignature": "20c32ef0653db6369f66d20ce72250807a19dcd955affa0f4c815e4d229ba8d0105c2f4ba3fa0771d8dd9418da02206cead4cbc0ea0ee51bb68a2d14b699b4bcb0",
"accountKey": "rpubKBAVZYL2jVQnKHyvWXDji7ZFtK7T5V5qJ3KhZZnRNLASNwamupMFM6VkWzxaAFGTUYQkQjsVKMbm1s2NQD19yejH6AJFDWuAss9B6B9REtJG",
"purpose": 44,
"fingerPrint": 516910651,
"data": "63636363636363636363",
"tokenDepth": 1,
"token": "0303030303030303030303030303030303030303030303030303030303030303"
}
Create transaction without signing and locking coins.
See TXOptioins in bcoin docs.
await client.createTX(id, options)
Cosigner authentication.
List existing proposals.
Query Params:
{
pending: true // when true, this will only list pending proposals [default=true]
}
await client.getProposals(id, true);
HTTP Response:
{
"proposals": [{
"id": 0,
"memo": "proposal1",
"tx": null,
// you can check `cosignerDetails` map to check author details.
"author": 1,
"approvals": {},
"rejections": {},
// This is the proposal creation signature that clients need to verify.
"signature": "1f5fb8c6d9df6b13c3d634d28f68398101800ad46ebbd768e72b4fcd38c016e28d42ab3d94d12eb542052e4ba0e3d9f0b8fe44a0cb006c7540cf1bbdfd198f5015",
// These are the HTTP options that were used for proposal creation.
"options": {
"memo": "proposal1",
"timestamp": 1554548312,
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RHTE2sM5byAhYGxc6pnvNN955qAAUvQ5FQ",
"value": 100000000
}
]
}
},
// author sets timestamp
"timestamp": 1554548312,
// server sets createdAt
"createdAt": 1554548312,
"rejectedAt": null,
"approvedAt": null,
"m": 2,
"n": 2,
"statusCode": 0,
"statusMessage": "Proposal is in progress.",
"cosignerDetails": {
"0": {
"id": 0,
"name": "cosigner1",
"authPubKey": "02348755bfeae058de77918f09c7f31397333715b83303014eeb36be0ac57f2310",
"joinSignature": "2077152bbab4ad2743af8619f085f3856258b255786b2083532cbe829855d9cbc551cab29777108f23d9385e4821d7e48c66a14eac6462469e06bb3e92995e9712",
"accountKey": "rpubKBAsBfPVMBBeBfD8F4EA5Dk1NAZ2dK7dc9JsE9dq9tDDF73NecpNP4z3gfMWuRm9rLVdSaeTj8BHZbVyHeRtV6UhciDz26pPDEntqCJvqKg2",
"purpose": 44,
"fingerPrint": 3664892090,
"data": "63636363636363636363"
},
"1": {
"id": 1,
"name": "cosigner2",
"authPubKey": "0325e5fb974a2e12f954edb3dd6d851a43d6744784f2a41e12c1060aefb783a702",
"joinSignature": "1fb393639c0f8279ef3377ff0c1bb9067474f41a4b4b7301a2814d64c6abd1fb446b48f361ec91d42d4c9dd589337e98cedc24762618bebed82c2d32e8244587f4",
"accountKey": "rpubKBB7QfFrX68MzrYd7FdcjSnZmg7sPRQzYKQuEfkJGF4BWV68qu23S4wvjwvo8b4sqRwUf7uNCWmDwghKFv6tPnGFjXaY4TXQw9QQTy5zcjfu",
"purpose": 44,
"fingerPrint": 358396470,
"data": ""
}
}
}]
}
Cosigner authentication.
Create proposal.
Proposal also needs signature to verify that author was the one who created the proposal. See signing
Data to sign:
- description: payload type with JSON serialized proposal options.
- example:
- Wallet name:
test
(hex:74657374
) - Payload type is create:
0
(hex:00
) {"memo":"proposal1","timestamp":1554549769,"txoptions":{"subtractFee":true,"outputs":[{"address":"RSdnT2yZvda2j8ff3cYQzcZB4oqqEmFZDL","value":100000000}]}}
- encoded:
007b226d656d6f223a2270726f706f73616c31222c2274696d657374616d70223a313535343534393736392c2274786f7074696f6e73223a7b227375627472616374466565223a747275652c226f757470757473223a5b7b2261646472657373223a225253646e5432795a766461326a386666336359517a635a42346f7171456d465a444c222c2276616c7565223a3130303030303030307d5d7d7d
- signed using
signmessage
rpc method or similar api.
- Wallet name:
After creating proposal, you still need to approve it.
This will lock coins, so these coins won't be used for
create TX or another proposal creation.
Params:
{
"proposal": {
// some description of the proposal. (up to 100 bytes)
"memo": "proposal1",
// client also sends timestamp for verification purposes. See signing doc.
"timestamp": 1555065103,
// you can check bcoin docs for details
// what are accepted in `txoptions`.
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RWgVixJfGyTCvhmJzEBD6tsBvv1btcTSXJ",
"value": 100000000
}
]
}
},
// signature of data to sign using `authPrivKey`.
"signature": "20b4740aeedee457c4df314d35dc4484bb6c2c1edb525158cabfa7619effd1a0c40154a72d060ad0fb256d2f83aac0ce78ba1d07472cfeda72e1d1fcba2d1001ff"
}
await client.createProposal(id, {
proposal: proposalOptions,
signature: signature
});
HTTP Response:
{
"id": 0,
"memo": "proposal1",
"tx": "010000000001011fde4f1c4fe35700e76c71f4fe2ae301cad918a7d2b6e204a49feb0810ae75770000000000ffffffff01b4d2f505000000001976a9147ce53b17719f95a49b290424f4d03279abdf91e388ac0400000047522103101caa304ee27baf13475d09116235756b22e3d98fd26aa356992244c3bf1c0b2103930cc331ebea62cb6e0094a4e0baeabfd7f9c6575bdffee6169905af0c7e55c352ae00000000",
"author": 1,
"approvals": {},
"rejections": {},
"signature": "208b715dcb5e3b45d1eb6a159af63047534d501e7deb7206ee0aa1b6bfc05db5d73f95587f81e1eb0d7eaee20b57ccbc024f3fac7257735ba2703c754b77feac58",
"options": {
"memo": "proposal1",
"timestamp": 1555065102,
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RLfaUYH5wWJYf9EUTFg25zFvmdzcGgSYH5",
"value": 100000000
}
]
}
},
"timestamp": 1555065102,
"createdAt": 1555065102,
"rejectedAt": null,
"approvedAt": null,
"m": 2,
"n": 2,
"statusCode": 0,
"statusMessage": "Proposal is in progress.",
"cosignerDetails": {
"0": {
"id": 0,
"name": "cosigner1",
"authPubKey": "02348755bfeae058de77918f09c7f31397333715b83303014eeb36be0ac57f2310",
"joinSignature": "2077152bbab4ad2743af8619f085f3856258b255786b2083532cbe829855d9cbc551cab29777108f23d9385e4821d7e48c66a14eac6462469e06bb3e92995e9712",
"accountKey": "rpubKBAsBfPVMBBeBfD8F4EA5Dk1NAZ2dK7dc9JsE9dq9tDDF73NecpNP4z3gfMWuRm9rLVdSaeTj8BHZbVyHeRtV6UhciDz26pPDEntqCJvqKg2",
"purpose": 44,
"fingerPrint": 3664892090,
"data": "63636363636363636363"
},
"1": {
"id": 1,
"name": "cosigner2",
"authPubKey": "0325e5fb974a2e12f954edb3dd6d851a43d6744784f2a41e12c1060aefb783a702",
"joinSignature": "1fb393639c0f8279ef3377ff0c1bb9067474f41a4b4b7301a2814d64c6abd1fb446b48f361ec91d42d4c9dd589337e98cedc24762618bebed82c2d32e8244587f4",
"accountKey": "rpubKBB7QfFrX68MzrYd7FdcjSnZmg7sPRQzYKQuEfkJGF4BWV68qu23S4wvjwvo8b4sqRwUf7uNCWmDwghKFv6tPnGFjXaY4TXQw9QQTy5zcjfu",
"purpose": 44,
"fingerPrint": 358396470,
"data": ""
}
}
}
Cosigner authentication.
Get proposal by proposal id.
Params:
{
// return transaction with proposal info.
tx: true
}
await client.getProposalInfo(id, pid, true);
HTTP Response:
{
"id": 0,
"memo": "proposal1",
"tx": "01000000000101cc5a323d7b52f1ef798254ddacb448da68439255a4a08fb9f4339a2e118fe3810000000000ffffffff01b4d2f505000000001976a914668a3ad48214fa364735b58d391ed15ec584aa9988ac0400000047522103621bd4659c36110df64219bb504db00e02d5d6871565c3c7c6008d91d8d41d4d2103dc953d900278c468603eace16ef7c09b777c8d8e463c40d41ecc18d02c958d8b52ae00000000",
"author": 1,
"approvals": {},
"rejections": {},
"signature": "20b22409672ef0986a18008a30b9e2a1132abfadbc30d3c6aa41373baf2c6f509b2e587249e4b2a8644722f25cc759c14bae5f14220c0367835f338d37556edaec",
"options": {
"memo": "proposal1",
"timestamp": 1554551309,
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RUQcLbkzLUv7FqoCcc8zQqyxAAdBKoSftr",
"value": 100000000
}
]
}
},
"timestamp": 1554551309,
"createdAt": 1554551309,
"rejectedAt": null,
"approvedAt": null,
"m": 2,
"n": 2,
"statusCode": 0,
"statusMessage": "Proposal is in progress.",
"cosignerDetails": {
"0": {
"id": 0,
"name": "cosigner1",
"authPubKey": "02348755bfeae058de77918f09c7f31397333715b83303014eeb36be0ac57f2310",
"joinSignature": "2077152bbab4ad2743af8619f085f3856258b255786b2083532cbe829855d9cbc551cab29777108f23d9385e4821d7e48c66a14eac6462469e06bb3e92995e9712",
"accountKey": "rpubKBAsBfPVMBBeBfD8F4EA5Dk1NAZ2dK7dc9JsE9dq9tDDF73NecpNP4z3gfMWuRm9rLVdSaeTj8BHZbVyHeRtV6UhciDz26pPDEntqCJvqKg2",
"purpose": 44,
"fingerPrint": 3664892090,
"data": "63636363636363636363"
},
"1": {
"id": 1,
"name": "cosigner2",
"authPubKey": "02348755bfeae058de77918f09c7f31397333715b83303014eeb36be0ac57f2310",
"joinSignature": "2077152bbab4ad2743af8619f085f3856258b255786b2083532cbe829855d9cbc551cab29777108f23d9385e4821d7e48c66a14eac6462469e06bb3e92995e9712",
"accountKey": "rpubKBAsBfPVMBBeBfD8F4EA5Dk1NAZ2dK7dc9JsE9dq9tDDF73NecpNP4z3gfMWuRm9rLVdSaeTj8BHZbVyHeRtV6UhciDz26pPDEntqCJvqKg2",
"purpose": 44,
"fingerPrint": 3664892090,
"data": ""
}
}
}
Get transaction details of the proposal. Cosigner authentication.
Query Params:
{
paths: true, // return paths used for each input
scripts: true // return pubScripts
}
await client.getProposalMTX(id, name, options);
HTTP Response:
{
"tx": {
"hash": "fe8fb96918ffd9e67925429b040700024b36e293106de6f57246fee045515302",
"witnessHash": "fe8fb96918ffd9e67925429b040700024b36e293106de6f57246fee045515302",
"fee": 6800,
"rate": 42500,
"mtime": 1554552579,
"version": 1,
"inputs": [
{
"prevout": {
"hash": "5aecd3a218052027f29c8621f941000bee183667e38152e05c9340919bea2e43",
"index": 0
},
"script": "0000004752210211ac31efebfe955f5c3a9b97aef12e876a22f366c6e9b12afdb1902b8e58dac1210352810849cd21a522ec55ae0dc14e16164b85ae4e789f8e1befb5422159fde79452ae",
"witness": "00",
"sequence": 4294967295,
"coin": {
"version": 1,
"height": 1,
"value": 100000000,
"script": "a914cf1d47ba5ac5c07af7cd8945794fd2203aba793287",
"address": "Gcj3NFyv5PH7GgVhDqUsdH9sKFSV1KBMgL",
"coinbase": false
}
}
],
"outputs": [
{
"value": 99993200,
"script": "76a9145b6608d5a175e01fce73f11c957d8182be933a1788ac",
"address": "RHcToTKiDp5ZdiayeXGxyjQZMx5PkYN91j"
}
],
"locktime": 0,
"hex": "0100000001432eea9b9140935ce05281e3673618ee0b0041f921869cf227200518a2d3ec5a000000004b0000004752210211ac31efebfe955f5c3a9b97aef12e876a22f366c6e9b12afdb1902b8e58dac1210352810849cd21a522ec55ae0dc14e16164b85ae4e789f8e1befb5422159fde79452aeffffffff0170c6f505000000001976a9145b6608d5a175e01fce73f11c957d8182be933a1788ac00000000"
},
// maps to inputs
"txs": [
"01000000012908863f569b257d62b273e1a1d247e35a1da0ce2bc399240c4c414ed67178770000000000ffffffff0100e1f5050000000017a914cf1d47ba5ac5c07af7cd8945794fd2203aba79328700000000"
],
"paths": [
{
"branch": 0,
"index": 2,
"receive": true,
"change": false,
"nested": false
}
],
"scripts": null
}
Cosigner authentication.
Approve with signatures, this will verify signatures when submitted. NOTE: This endpoint does not return cosigner details.
Params:
{
// signatures for inputs (can be null), maps to inputs.
"signatures": [
"3044022060c8b70234e946814df040a021f34c6468b7d7cbc2aa070363b6ad86177a793802200b540cc622fed09625bc8ea1ba6e7fa70ca702afa3677e966f2138917b78395e01"
],
// Do we want to broadcast transaction(if our approval was last once)
"broadcast": true
}
await client.approveProposal(id, name, {
signatures: [
"3044022060c8b70234e946814df040a021f34c6468b7d7cbc2aa070363b6ad86177a793802200b540cc622fed09625bc8ea1ba6e7fa70ca702afa3677e966f2138917b78395e01"
],
broadcast: true
});
HTTP Response:
{
"broadcasted": true,
// if you wanted to broadcast and it failed, this will contain error message.
"broadcastError": null,
"proposal": {
"id": 1,
"memo": "proposal2",
"tx": "01000000000101bb9a9ba497d7b092c807b29ee1b4666e2a95a7d549c7ca258c4e916bd7d4e11c0000000000ffffffff01b4d2f505000000001976a914dce85ae1e11c2044aec3cf3fcfdc54fe796a2ad588ac0400483045022100e23caa92fdca32e9c50a186c651e7f54c150f329693a260e18d720148de7d687022041d740178ca29089450cc0b36b5503e28e6825dd1b4f92ba7304cf8d575a4bcb01473044022060c8b70234e946814df040a021f34c6468b7d7cbc2aa070363b6ad86177a793802200b540cc622fed09625bc8ea1ba6e7fa70ca702afa3677e966f2138917b78395e0147522102b7eaa9cbc9494db518f387a8e996abd83291a9ff3ad7d4b74ef7e8f43e67f275210302049c65a18d53a04bfa18672b3cb0de4214de806b36fc939a503fe02fa0743852ae00000000",
"author": 0,
"approvals": {
"0": [
"3045022100e23caa92fdca32e9c50a186c651e7f54c150f329693a260e18d720148de7d687022041d740178ca29089450cc0b36b5503e28e6825dd1b4f92ba7304cf8d575a4bcb01"
],
"1": [
"3044022060c8b70234e946814df040a021f34c6468b7d7cbc2aa070363b6ad86177a793802200b540cc622fed09625bc8ea1ba6e7fa70ca702afa3677e966f2138917b78395e01"
]
},
"rejections": {},
"signature": "20264892b65f9c7d9540e76b0e9d59afc81d4f34f21612122d53d3fa7aa8d2587d04ea73efaa730fec489f77a06476cfa251eca476dc2a3b5d099addc84fdd6a47",
"options": {
"memo": "proposal2",
"timestamp": 1555069077,
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RVRF62ZqRutUHCy5b553ZjNWaQR6TUcb4p",
"value": 100000000
}
]
}
},
"timestamp": 1555069077,
"createdAt": 1555069077,
"rejectedAt": null,
"approvedAt": 1555069077,
"m": 2,
"n": 2,
"statusCode": 1,
"statusMessage": "Proposal has been approved.",
"cosignerDetails": {}
}
}
Cosigner or Admin authentication.
Reject proposal. In order to reject proposal, cosigner needs
to sign proposalOptions
that where used for creating proposal
and are cached in proposal (and signed by author.)
Cosigners will need local authPrivKey
s to sign and signing process
is same as the creation, with one difference:
- walletName:
test
(hex:74657374
) - payload type will be rejection:
0x01
. - so encoded version will be:
017b226d656d6f223a2270726f706f73616c31222c2274696d657374616d70223a313535343534393736392c2274786f7074696f6e73223a7b227375627472616374466565223a747275652c226f757470757473223a5b7b2261646472657373223a225253646e5432795a766461326a386666336359517a635a42346f7171456d465a444c222c2276616c7565223a3130303030303030307d5d7d7d
.
When there are sufficient rejections (Not enough cosigners left to approve transaction) proposal will get rejected and locked coins will be released.
Params:
{
// signed using `authPrivKey` of the cosigner.
"signature":"2030a42cdd77ddefe0ff44012c75d710f990d764b10f4dce43c084e02a62aa871b3b00d1561e5be1632f723dfd3f87cfb25ff56ce033f47e595a1697810d52a5ee"
}
or Admin:
{
"force": true
}
await client.rejectProposal(id, name, {
signature: signature
});
// admin
await adminClient.rejectProposal(id, name, {
force: true
});
HTTP Response:
{
"id": 0,
"memo": "proposal1",
"tx": null,
"author": 1,
"approvals": {},
"rejections": {
"0": "2030a42cdd77ddefe0ff44012c75d710f990d764b10f4dce43c084e02a62aa871b3b00d1561e5be1632f723dfd3f87cfb25ff56ce033f47e595a1697810d52a5ee"
},
"signature": "1fbb47423e669edafaa48f1f05ae4367933d068b39514e30db1e4189b6b66a8be17f533d221206f7158a2bc88502da220cc9bf926ba7a50c9ea4e5c5d6e34cbb4f",
"options": {
"memo": "proposal1",
"timestamp": 1555069254,
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RP9MnZsGon9ue7ymmdZrmPypuPuWK9K75x",
"value": 100000000
}
]
}
},
"timestamp": 1555069254,
"createdAt": 1555069254,
"rejectedAt": 1555069254,
"approvedAt": null,
"m": 2,
"n": 2,
"statusCode": 2,
"statusMessage": "Cosigners rejected the proposal.",
"cosignerDetails": {}
}
Cosigner or admin auth
Get proposal by coin (UTXO hash and index).
No parameters.
await client.getProposalByCoin(id, hash, index);
HTTP Reponse:
{
"id": 1,
"memo": "proposal1",
"tx": null,
"author": 1,
"approvals": {},
"rejections": {},
"signature": "20106466afbc9d95f5f3e37290534f0cb6f6464189d24bf89b2cb40c566c3945e371045d9ab7630b20ad7548bcce0ee83c25bea954e82684cafc1772b49e768d2f",
"options": {
"memo": "proposal1",
"timestamp": 1565901901,
"txoptions": {
"subtractFee": true,
"outputs": [
{
"address": "RSuiCPBrELanmdXeLHoA6VqnHEm5XFsR7h",
"value": 500000000
}
]
}
},
"timestamp": 1565901901,
"createdAt": 1565901901,
"rejectedAt": null,
"approvedAt": null,
"m": 2,
"n": 2,
"statusCode": 0,
"statusMessage": "Proposal is in progress.",
"cosignerDetails": {}
}
You can import and export wallets from the multisigdb with admin token.
HTTP Endpoints return JSON serialized object, but they can be serialized
in Binary format as well, using serializers from /lib/export.js
.
Admin authorization.
await client.export(id);
HTTP Response:
{
"watchOnly": true,
"accountDepth": 1,
"tokenDepth": 0,
"token": "1111111111111111111111111111111111111111111111111111111111111111",
"master": "003e04334be01bfa16e233a073d39172060f41f9c60ff4c9cd76b84a80aa74c8847bdb11e514aae4ac284a9b4f8544dfa61a2bcac17f536383122796ec464a438f018000028a85e0467678fc2499e375a76ecbc3dc",
"joinPubKey": "0308c749ece3230fca2a324623963c6ec20c4be9056b0d0089ecb95f1bfbb29396",
"timestamp": 1564595915,
"accounts": [
{
"name": "default",
"witness": true,
"initialized": true,
"watchOnly": true,
"type": "multisig",
"m": 2,
"n": 2,
"accountIndex": 0,
"receiveDepth": 1,
"changeDepth": 1,
"nestedDepth": 1,
"lookahead": 11,
"accountKey": "rpubKBBV6Y2asgWUBVPmPfaBdufC4RxMoB2HYBxi1bN9bW9Pyodf5TWAJeog7NBsradD5MHe9M7RWkK6p5ZGir6iVHUiQdVSVrKVSU19xYmVQMLV",
"keys": [
"rpubKBBvERPndYY5wx6ibRr7JpsABertsCGLPDkk55TvMpKqtJku89WngaNickRxy6hrRmmzVmByFg1ocKiHmNas4m6RpeTmH7Uzwh9HdKC5fxqW"
]
}
],
"cosigners": [
{
"id": 0,
"name": "cosigner1",
"data": "63636363636363636363",
"purpose": 44,
"fingerPrint": 891844849,
"accountKey": "rpubKBBV6Y2asgWUBVPmPfaBdufC4RxMoB2HYBxi1bN9bW9Pyodf5TWAJeog7NBsradD5MHe9M7RWkK6p5ZGir6iVHUiQdVSVrKVSU19xYmVQMLV",
"authPubKey": "02bad879395e171121982a397d0a8fafb3063eea61d6984824798c08bc85add085",
"joinSignature": "2043d1dfd38115082cd78a7de23d6a2e9a5ccc437022ebc07c8e81e57d8f1797be292683aeea5d43c3f25ff0976718ae0b080f4e132f7084630c4b5b7a3d74a99a",
"token": "0101010101010101010101010101010101010101010101010101010101010101",
"tokenDepth": 0
},
{
"id": 1,
"name": "cosigner2",
"data": "",
"purpose": 44,
"fingerPrint": 2264922574,
"accountKey": "rpubKBBvERPndYY5wx6ibRr7JpsABertsCGLPDkk55TvMpKqtJku89WngaNickRxy6hrRmmzVmByFg1ocKiHmNas4m6RpeTmH7Uzwh9HdKC5fxqW",
"authPubKey": "0203c12bbb10cd45afde168b548765106f8255e43142d1250a1551496d31e23b17",
"joinSignature": "2020342880c3db62e49b6450ce1f55f7334ce5185d6e49e3ae9c2ebe078c82b7f0365e4097fc68ec413606cf3158005daa935941b4a3f36bffee25936b2e25aa15",
"token": "0202020202020202020202020202020202020202020202020202020202020202",
"tokenDepth": 0
}
]
}
Admin authorization.
Params:
{
"id": "wallet-name",
"importOptions": {
// Same object as returned by export.
}
}
HTTP Response:
// Same response as Create Wallet.