Who is this tutorial for:
- API users that DO NOT use their iPhone as the Instruction Key.
- API users that need to implement the functionality in programming languages other than JavaScript
- API users that DO NOT want to use our JavaScript SDK.
Brief Outline
- Get your subWallet id from the User Wallets Details Query
- Create a bitcoin transaction via the Create BTC Transaction Mutation
-
Verify the transaction and that it was sent by TrustVault
- For testing purposes (sandbox environment) you can skip this step
- For Production we highly recommend you verify the data
-
Sign each transaction input
-
If your signing solution requires the pre-image data then use the
input.unverifiedDigestData.signData
and use the SHA256 hashing algorithm -
If your signing solution can sign hash data then use the
input.unverifiedDigestData.shaSignData
-
If your signing solution requires the pre-image data then use the
- Submit the signatures in the same order as the inputs via the Add Signature Mutation
- Poll the status of the transaction to confirm it was sent to the network using the Get Request Item Query
JavaScript Example
Below is a brief example for creating, signing and submitting a BTC transaction. Sandbox users can comment out the verifyBitcoinTransaction
for fast implementation but MUST implement it for Production. The code for verifyBitcoinTransaction
will be made available soon.
import { ApiClient } from "./api-client";
import * as AWS from "aws-sdk";
// Create instance of KMS for key signing
const kms = new AWS.KMS({ apiVersion: "2014-11-01", region: "eu-west-1" });
// Get the public Key (This will need to be your own custom code to pull the PublicKey from the AWS KMS publicKey which is a DER-encoded X.509 public key, also known as SubjectPublicKeyInfo (SPKI),
// Sample code: https://github.com/Trustology/trustvault-nodejs-sdk/blob/master/src/ts/sign-examples/aws-kms.ts
// https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html
const newPublicKey = getUncompressedPublicKeyInHex(await this.kms.getPublicKey({KeyId: "my-key"}).promise())
// For demonstration purposes only. Do not hard code your API key, store it somewhere safe.
const userApiKey = "test-api-key";
// Production
const prodUrl = "https://tapi-production.trustology-prod.com/graphql";
// API reflects the postman query written in JavaScript
const apiClient = new ApiClient(userApiKey, prodUrl);
/**
* Sends a bitcoin transaction with the given parameters
* 1. Creates the bitcoin transaction from the fromSubWalletId with the given parameters
* 2. Validates the returned transaction
* 3. Signs and submits the key signature pairs
* 2. Polls the request status to see if it has been successfully submitted to the network
*
* @param {string} fromSubWalletId - the unique identifier retrieved from the User Wallets Query where the bitcoin transaction will be sent from
* @param {string} toAddress - the address where the bitcoin transaction that will be sent to (we support P2SH, P2PKH, P2WPKH, P2SH-P2WPKH address types)
* @see https://bitcoin.stackexchange.com/a/64852 for an explanation of different bitcoin addresses
* @param {string} amount - the amount to send in satoshi (integer string)
* @param {string} speed - "FAST" | "MEDIUM" | "SLOW"
* @returns {string} requestId - the unique identifier of the created bitcoin transaction request needed for transaction tracking
*/
async function sendBitcoin(fromSubWalletId, toAddress, amount, speed) {
// call createBitcoinTransaction mutation with the parameters to get a well formed bitcoin transaction
const result = await apiClient.createBitcoinTransaction(fromSubWalletId, toAddress, amount, speed);
if (!result.signData || !result.requestId) {
console.error(`Failed to create bitcoin transaction ${JSON.stringify(result)}`);
throw new Error("Failed to create bitcoin transaction");
}
// IMPORTANT: PRODUCTION users are highly recommended to verify the bitcoin transaction (input/outputs are correct and were sent by TrustVault)
verifyBitcoinTransaction(result.signData, fromSubWalletId, toAddress, amount);
// IMPORTANT: PRODUCTION users are highly recommended to NOT use the unverifiedDigestData but instead recreate the digests
const unverifiedSignedDataDigests: string[] = result.signData.transaction.inputs.map(
// If your signing solution requires the pre-image data then use the `input.unverifiedDigestData.signData`.
(input) => input.unverifiedDigestData.shaSignData,
);
// Sign each signRequest with your key pair
const signRequests = unverifiedSignedDataDigests.map((signedDigest) => {
// using you private key pair secured in KMS, sign the digest.
// custom function. Use the sample code "sign" function and pull out the r,s values: https://github.com/Trustology/trustvault-nodejs-sdk/blob/master/src/ts/sign-examples/aws-kms.ts
const { r, s } = signAndReturnRandSSignature(kms, signedDigest);
// convert the r, s bytes signature to hex format
const hexSignature = r.toString("hex", 64) + s.toString("hex", 64);
return {
publicKeySignaturePairs: [
{
publicKey: newPublicKey, // should be in hex string format
signature: hexSignature, // should be in hex string format
},
],
};
});
// submit the addSignature payload and receive back the requestId of your bitcoin transaction request
const requestId = await apiClient.addSignature({
requestId: result.requestId,
signRequests,
});
// Check that your transaction was successfully submitted to the network
const expectedStatus = "SUBMITTED";
const status = await pollRequestStatus(requestId, expectedStatus);
console.info(`request (${requestId}) - status: ${status}`);
return requestId;
}