Installation
1 | $ npm i @trustology/trustvault-nodejs-sdk |
Creating a TrustVault Client
1 | // common |
Overview
The SDK wraps the TrustVault GraphQL interface and gives you easy access to core functionalities within the API.
The API can be configured against sandbox (ETH ropsten, BTC testnet3) or production environments.
The SDK is focussed on sub-wallets. This article will help on understanding the differences between wallets and sub-wallets.
If you use the SDK with an external instruction key the SDK provides callbacks for you to sign the correct data when creating a transaction or requesting a policy change on a wallet.
The SDK includes helper methods to ensure the data integrity including validating policy template, publicKey provenance, HMAC webhook payload and digests. This ensures that the digests that need signing contain the input data specified from the SDK. This helps prevents man-in-middle attacks.
It also includes a sample AWS KMS wrapper class for data signing.
The SDK requires an API key, please contact Bitpanda Custody to get one.
See TrustVault Node.js SDK in github
Sign callback
The function that will be called with the data that needs to be signed.
The sign callback is called after the request has been created, passing in the request data that needs to be signed as a parameter. The callback allows you to immediately sign the created request. In production environments it is strongly advised that you confirm the shaSignData
that was passed in your sign callback is what you expect by re-creating the shaSignData
using your original input values.
Sign callback is optional for replacePublicKeyInDefaultSchedule
, sendBitcoin
and sendEthereum
methods. If the sign callback is not given, the created request will not be signed and will stay in AWAITING_SIGNATURES status, the request can then be signed on the iOS device. See request statuses below.
1 | type SignCallback = (signDataBuffer: SignDataBuffer) => Promise<PublicKeySignaturePairBuffer>; |
An example of a sign callback (AWS KMS implementation) can be found here
AWS KMS wrapper class (AwsKmsKeyStore)
This is an example of how you can use AWS KMS to sign transactions via the SDK. You should have your own AWS account, with your own AWS KMS instance, which should be securely locked down via IAM roles.
This sample class, AwsKmsKeyStore
, shows how you can ensure that the correct key from the correct curve is used for signing. It has a method sign
which is an implementation of the signCallback
.
You will need to ensure that your code has the relevant AWS permissions to access your KMS key. The AwsKmsKeyStore
implementation can be found here
Create a new sub-wallet
This allows you to create a new sub-wallet inside an existing wallet. You can use the get sub-wallets to find your existing walletIds. Since a walletId will never change (it can only be deleted). You may consider hard coding the walletId.
Please note: this method will return a Provenance Signature (trustVaultProvenanceSignature
) of the signed PublicKey from the TrustVault API which will be checked against the TrustVault Master Public Key to ensure validity and will then generate the address on the client to ensure the address given (verifiedAddress
) is correct.
1 | const createResponse = await trustVault.createSubWallet({ name: "My subwallet", walletId: "c7e828ed-77a3-4907-b129-651c2377a929", subWalletType: "ETH" }); |
Returns
1 | { |
Get a list of all sub-wallets
This allows you to page through all the sub-wallets. The default is to return 20 items per call. The following code will retrieve all sub-wallets associated with the API key by paging through them 10 at a time. Use with caution if you have hundreds of sub-wallets.
1 | let nextToken; |
Get a single sub-wallet
Retrieve the specific subWallets associated. Use this method to get a specific sub-wallet based on the subWalletId
.
1 | const subWallet = await trustVault.getSubWallet("0bee0ebb-f3b8-47af-a4aa-d7f1755d89e4/ETH/0"); |
Returns
1 | { |
You can additionally, pass an options
object to request balances of the sub-wallet. This will be slightly slower as it will retrieve balances of all assets
1 | const subWallet = await trustVault.getSubWallet("0bee0ebb-f3b8-47af-a4aa-d7f1755d89e4/ETH/0", { includeBalances: true }); |
Send a Bitcoin Transaction
Send a bitcoin transaction. This will still need to be signed by the wallet policy delegates.
1 | const requestId = await trustVault.sendBitcoin(fromSubWalletId, toAddress, amount, speed, signCallback); |
Send an Ethereum Transaction
Send an ethereum transaction. This will still need to be signed by the wallet policy delegates.
NB: Supported Assets are here
1 | fromAddress = "0xbcc817f057950b0df41206c5d7125e6225cae18f" // your TrustVault address to send the transaction from |
Changing the external instruction key of a wallet
Change the external instruction key of a wallet. This is required if you wish to sign transactions yourself rather than on a registered iOS device. This method is useful for testing as it simply changes the policy to allow a single key to sign transactions.
1 | const requestId = await trustVault.replacePublicKeyInDefaultSchedule(walletId, publicKey, signCallback); |
With version 1.5.5 and above you can now generate more complex wallet delegate policy which may be more useful in a production environment.
The delegate schedule is an array of Schedule
s. Each Schedule
is “OR”‘d by TrustVault. Inside each Schedule
is an array of Clause
s. Each Clause
is “AND”‘d. Each Clause
defines a quorum
which is the minimum number of keys that must sign for the Clause
to be satisfied.
The sample below shows a single Schedule
which has 2 Clause
s. Since Clause
s are “AND”‘d, BOTH must be satisifed.
You can read this policy as:
1 of 2 AND 1 of 1.
i.e. If 1 of the 2 keys in the first Clause
has signed AND the 1 key of the second Clause
has signed, this policy is satisfied.
1 |
|
You can also pass a Sign callback
to this method to immediately sign the request. Alternatively, you can wait for the webhook (POLICY_CHANGE_REQUEST_CREATED
) to be received by your API and then sign the item from there. See below for signing the webhook request.
Note: Each delegate listed AND Bitpanda Custody MUST sign the change request before the policy can become active.
Validating and signing a webhook request
Validate the webhook, sign and submit the signature to TrustVault
1 | TrustVault.validateWebhookSignature(req.body, "<YOUR_WEBHOOK_SECRET>", req.headers["X-Sha2-Signature"]); |
NOTE: validateWebhookSignature is a static method
Create a new Bitcoin Address
Create a new bitcoin address for the given subWalletId
1 | const address = await trustVault.createBitcoinAddress(subWalletId); |
Get request
Retrieve the request item associated with the given requestId. Use this method to query the status of your request.
1 | const request = await trustVault.getRequest(requestId); |
Returns
1 | { |
Cancel Request
Cancels a request item associated with the given requestId. If successful, the request will be in USER_CANCELLED status. Throws an error if the request is not in a state that can be cancelled (i.e. not AWAITING_SIGNATURES) See request statuses below
1 | const success = await trustVault.cancelRequest(requestId) |
You can also pass a second optional parameter that specifies the reason for cancelling the request.
1
const success = await trustVault.cancelRequest(requestId, "Reason for cancelling request")
Returns (boolean)
1 | true |
Request Statuses
Request Status | Description |
---|---|
AWAITING_SIGNATURES | the request is still awaiting signatures enough signature before it can be processed |
SIGNED | the request has received enough signatures to be processed |
SUBMITTED | the transaction request has been processed and submitted to the network |
CONFIRMED | the transaction request has been confirmed by the network (1+ confirmation) |
PROCESSED | the request has been successfully processed |
USER_CANCELLED | the request has been cancelled by the user |
ERROR | an error occurred when processing the request |