Withdraw from Wallet - Self-Managed TSS Hot (Advanced)

Overview

You withdraw from self-managed TSS hot wallets by submitting transaction-request details to BitGo. BitGo uses the data you pass to construct an unsigned transaction that wallet co-signers can sign and wallet admins can approve. Once the transaction is half signed and approved, you send it to BitGo for final signing and broadcasting to the blockchain.

If you don't need this level of granular control for your withdrawals, see the integration guide for the simple flow.

Prerequisites

1. Request Transaction

Request the transaction by specifying the transaction details and sending them to BitGo.

Endpoint: Create transaction request

  • JavaScript
  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 let params = { recipients: [ { amount: 0.01 * 1e8, address: '2NFfxvXpAWjKng7enFougtvtxxCJ2hQEMo4', }, ], }; wallet.prebuildTransaction(params).then(function (transaction) { // print transaction details console.dir(transaction); }); // This creates and stores a transaction request. If you don't want to store this data, pass the `preview` flag.

Step Result

BitGo uses the data you pass to build an unsigned transaction.

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 { "txRequestId": "string", "version": 0, "latest": true, "walletId": "string", "walletType": "cold", "enterpriseId": "string", "state": "initialized", "date": "2018-05-05T19:46:22.019Z", "userId": "string", "intent": { "nonce": "string", "memo": "string", "intentType": "claim", "sequenceId": "abc123", "comment": "string", "stakingRequestId": "string", "stakingAddress": "string", "amount": { "value": "100", "symbol": "usdc" } }, "pendingApprovalId": "string", "transactions": [ { "state": "initialized", "unsignedTx": { "serializedTxHex": "string", "signableHex": "string", "derivationPath": "string", "feeInfo": { "feeString": "string", "fee": 0 } }, "signatureShares": [ { "from": "user", "to": "user", "share": "string" } ], "txHash": "string" } ] }

2. Sign Transaction

Signing transactions from a TSS wallet is a 3-step process, unless you use external-signing mode, which is only 1 step. See below for details.

  • REST API
  • Express (external-signing mode)

2.1 - Send 1st Key Share to Bitgo

Send BitGo the 1st key share of the signature share.

Note: You can sign multiple transactions at once by passing the signatureShares parameter with the desired key shares for the additional transactions.

Endpoint: Create a signature share for the transaction request

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST /api/v2/wallet/{walletId}/txrequests/{id}/signatureshares Request Body { "signatureShare": { "from": "user", "to": "user", "share": "string" }, "signatureShares": [ { "from": "user", "to": "user", "share": "string" } ], "signerShare": "string", "userPublicGpgKey": "string" // Required for ECDSA assets, such as ETH and MATIC }
Substep Result
  • JSON
1 2 3 4 5 { "from": "user", "to": "user", "share": "string" }

2.2 - Get 2nd Key Share from BitGo

Endpoint: Get transaction requests by wallet

  • JSON
1 GET /api/v2/wallet/{walletId}/txrequests

Substep Result

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 { "txRequests": [ { "txRequestId": "string", "version": 0, "latest": true, "walletId": "string", "walletType": "cold", "enterpriseId": "string", "state": "initialized", "date": "2018-05-05T19:46:22.019Z", "userId": "string", "intent": { "nonce": "string", "memo": "string", "intentType": "claim", "sequenceId": "abc123", "comment": "string", "stakingRequestId": "string", "stakingAddress": "string", "amount": { "value": "100", "symbol": "usdc" } }, "pendingApprovalId": "string", "unsignedTxs": [ { "serializedTxHex": "string", "signableHex": "string", "derivationPath": "string", "feeInfo": { "feeString": "string", "fee": 0 } } ], "signatureShares": [ { "from": "user", "to": "user", "share": "string" } ], "txHashes": [ "string" ] } ], "nextBatchPrevId": "string" }

2.3 - Send Complete Key Share to BitGo

Endpoint: Create a signature share for the transaction request

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST /api/v2/wallet/{walletId}/txrequests/{id}/signatureshares Request Body { "signatureShare": { "from": "user", "to": "user", "share": "string" }, "signatureShares": [ { "from": "user", "to": "user", "share": "string" } ], "signerShare": "string", "userPublicGpgKey": "string" // Required for ECDSA assets, such as ETH and MATIC }
Substep Result

BitGo receives the complete key share and the transaction becomes half-signed, awaiting final signature from BitGo using the BitGo key.

  • JSON
1 2 3 4 5 { "from": "user", "to": "user", "share": "string" }

Step Result

The transaction remains in a pending-approval status until a wallet admin approves it.

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 { "error": "triggered all transactions policy", "pendingApproval": { "id": "65529448bd87efe59c3b0156ddfce867", // admin who approves the transaction needs this ID "coin": "tbtc", "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "enterprise": "62c5ae8174ac860007aff138a2d74df7", "creator": "62ab90e06dfda30007974f0a52a12995", "createDate": "2023-11-13T21:25:28.022Z", "info": { "type": "transactionRequest", "transactionRequest": { "requestedAmount": "10000", "fee": 20451, "sourceWallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "policyUniqueId": "654ec786c07fe8dc0dcfe03f", "recipients": [ { "address": "2N1UvKhtSHLUa9YomSH7n9YMFCkMG2pbmsQ", "amount": "10000", "_id": "65529448bd87efe59c3b0158" } ], "buildParams": {}, "coinSpecific": { "tbtc": { "txHex": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e7016605cd506ddd7041762d50000000023220020510ded26d712922bbb61bc68ef6766f836a03527820cbdc8b1551914eb467dafffffffff02102700000000000017a9145a581567fd2a630e61e34a696ab3bb887972886d87ad0f010000000000225120850d0ab466d15cb1565dd528d4d9709f3e46f41d41fe6d94aa01378e626983990500483045022100db45a8d94ee2144f7e29baa855d94a2bf0120707a7ab2fc93734ed94af972c460220558d00b91275aafc7805dfaaf9ab796adbe9f4e66dc467f7eb93b790671a323201000069522103c10ac628c880629ed0fd2a0563a898f4882baca45e15668a4d3064cf1ea379882103e56f84be4460080618ef869bb7b07096880760f748ba23efab533c2359f923bd21020ae81372264b5eac5c9dc7fe0b9a32bad00771c3a2c71f6e2c971823c3182ed653ae00000000" } } } }, "state": "pending", "scope": "wallet", "userIds": [ // admins who can approve the transaction "62ab90e06dfda30007974f0a52a12995", "621d08a634ad8a0007fcddffd7c429cc" ], "approvalsRequired": 1, "singleRunResults": [ { "ruleId": "Custodial Enterprise Transaction ID Verification", "triggered": false, "_id": "65529448bd87efe59c3b0157" } ], "resolvers": [] }, "triggeredPolicy": "654ec786c07fe8dc0dcfe03f205e2524" }

4. Approve Transaction

Note: You can't approve your own transactions - another admin must approve them.

Endpoint: Update Pending Approval

  • cURL
  • JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 export APPROVAL_ID="<APPROVAL_ID>" export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>" export OTP="<YOUR_OTP>" curl -X PUT \ https://app.bitgo-test.com/api/v2/pendingApprovals/$APPROVAL_ID \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -d '{ "state": "approved", "otp": "'"$OTP"'" }'

Step Result

Once approved, BitGo rebuilds the half-signed transaction, applying the most up-to-date fees.

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 { "id": "65529448bd87efe59c3b0156ddfce867", "coin": "tbtc", "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "enterprise": "62c5ae8174ac860007aff138a2d74df7", "creator": "62ab90e06dfda30007974f0a52a12995", "createDate": "2023-11-13T21:25:28.022Z", "info": { "type": "transactionRequest", "transactionRequest": { "requestedAmount": "10000", "fee": 20451, "sourceWallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "policyUniqueId": "654ec786c07fe8dc0dcfe03f", "recipients": [ { "address": "2N1UvKhtSHLUa9YomSH7n9YMFCkMG2pbmsQ", "amount": "10000", "_id": "65529448bd87efe59c3b0158" } ], "coinSpecific": { "tbtc": { "txHex": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e7016605cd506ddd7041762d50000000023220020510ded26d712922bbb61bc68ef6766f836a03527820cbdc8b1551914eb467dafffffffff02102700000000000017a9145a581567fd2a630e61e34a696ab3bb887972886d87ad0f010000000000225120850d0ab466d15cb1565dd528d4d9709f3e46f41d41fe6d94aa01378e626983990500483045022100db45a8d94ee2144f7e29baa855d94a2bf0120707a7ab2fc93734ed94af972c460220558d00b91275aafc7805dfaaf9ab796adbe9f4e66dc467f7eb93b790671a323201000069522103c10ac628c880629ed0fd2a0563a898f4882baca45e15668a4d3064cf1ea379882103e56f84be4460080618ef869bb7b07096880760f748ba23efab533c2359f923bd21020ae81372264b5eac5c9dc7fe0b9a32bad00771c3a2c71f6e2c971823c3182ed653ae00000000" } }, "validTransaction": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e7016605cd506ddd7041762d50000000023220020510ded26d712922bbb61bc68ef6766f836a03527820cbdc8b1551914eb467dafffffffff02102700000000000017a9145a581567fd2a630e61e34a696ab3bb887972886d87ad0f010000000000225120850d0ab466d15cb1565dd528d4d9709f3e46f41d41fe6d94aa01378e626983990400483045022100db45a8d94ee2144f7e29baa855d94a2bf0120707a7ab2fc93734ed94af972c460220558d00b91275aafc7805dfaaf9ab796adbe9f4e66dc467f7eb93b790671a323201473044022049e20c0073f42c9636408efc6c833ebf0e1a8ef13e8cb818dde2f4e2af7f7b7f022000cb3a321d65605b9d51d7f87e34306169607646c8d54a44011b021eff3dbe500169522103c10ac628c880629ed0fd2a0563a898f4882baca45e15668a4d3064cf1ea379882103e56f84be4460080618ef869bb7b07096880760f748ba23efab533c2359f923bd21020ae81372264b5eac5c9dc7fe0b9a32bad00771c3a2c71f6e2c971823c3182ed653ae00000000", "validTransactionHash": "5ea8d2b93997ed9fa3597a2f3113817c8216f573a0278c2533bb5db50fdb0dff" } }, "state": "approved", "scope": "wallet", "userIds": [ "62ab90e06dfda30007974f0a52a12995", "621d08a634ad8a0007fcddffd7c429cc" ], "approvalsRequired": 1, "singleRunResults": [ { "ruleId": "Custodial Enterprise Transaction ID Verification", "triggered": false, "_id": "65529448bd87efe59c3b0157" } ], "resolvers": [ { "user": "621d08a634ad8a0007fcddffd7c429cc", "date": "2023-11-13T21:44:27.794Z", "resolutionType": "pending" } ] }

3. Send Transaction

Using the txHex returned in the prior step, send the half-signed transaction to BitGo.

Endpoint: Send a Half-Signed Transaction

  • cURL
  • JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 export COIN="<ASSET_ID>" export WALLET_ID="<YOUR_WALLET_ID>" export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>" curl -X POST \ https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/tx/send \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -d '{ "halfSigned": { "txHex": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e7016605cd506ddd7041762d50000000023220020510ded26d712922bbb61bc68ef6766f836a03527820cbdc8b1551914eb467dafffffffff02102700000000000017a9145a581567fd2a630e61e34a696ab3bb887972886d87ad0f010000000000225120850d0ab466d15cb1565dd528d4d9709f3e46f41d41fe6d94aa01378e626983990500483045022100db45a8d94ee2144f7e29baa855d94a2bf0120707a7ab2fc93734ed94af972c460220558d00b91275aafc7805dfaaf9ab796adbe9f4e66dc467f7eb93b790671a323201000069522103c10ac628c880629ed0fd2a0563a898f4882baca45e15668a4d3064cf1ea379882103e56f84be4460080618ef869bb7b07096880760f748ba23efab533c2359f923bd21020ae81372264b5eac5c9dc7fe0b9a32bad00771c3a2c71f6e2c971823c3182ed653ae00000000" } }'

Step Result

BitGo applies the final signature using the BitGo key and broadcasts the transaction to the blockchain.

  • JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 { "transfer": { "entries": [ { "address": "2NAVwU9KtPyE4h3RyHkhbLgQQvrc4EuSXD3", // sender address "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "value": -100000, "valueString": "-100000" }, { "address": "2Mw241n14gJx2PcK2kijidZ2BPGeJBdwp1A", // receiver address "value": 10000, "valueString": "10000", "isChange": false, "isPayGo": false }, { "address": "tb1pq9m0lqjg4lfa0rj9wzjjjumk3l6vecndt8wla5756ktre6h6fexqg7z0vq", // change address that collects the UTXO "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "value": 70013, "valueString": "70013", "isChange": true, "isPayGo": false } ], "id": "65528cde229f765c57a8f4d1eb762908", "coin": "tbtc", "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0", "walletType": "hot", "enterprise": "62c5ae8174ac860007aff138a2d74df7", "txid": "c68916ddc1672ec62c474ef0839ec479ad9b2dabc2249177ce6be6247f81dfe7", "txidType": "transactionHash", "height": 999999999, "heightId": "999999999-65528cde229f765c57a8f4d1eb762908", "date": "2023-11-13T20:53:51.445Z", "type": "send", "value": -29987, "valueString": "-29987", "intendedValueString": "-29987", "baseValue": -10000, "baseValueString": "-10000", "baseValueWithoutFees": -10000, "baseValueWithoutFeesString": "-10000", "feeString": "19987", "payGoFee": 0, "payGoFeeString": "0", "usd": -11.0275843085, "usdRate": 36774.55, "state": "signed", "instant": false, "isReward": false, "isFee": false, "tags": [ "654ec786c07fe8dc0dcfe03916ec5bb0", "62c5ae8174ac860007aff138a2d74df7" ], "history": [ { "date": "2023-11-13T20:53:51.444Z", "action": "signed" }, { "date": "2023-11-13T20:53:50.646Z", "user": "62ab90e06dfda30007974f0a52a12995", "action": "created" } ], "signedDate": "2023-11-13T20:53:51.444Z", "vSize": 225, "metadata": [], "signedTime": "2023-11-13T20:53:51.444Z", "createdTime": "2023-11-13T20:53:50.646Z" }, "txid": "c68916ddc1672ec62c474ef0839ec479ad9b2dabc2249177ce6be6247f81dfe7", "tx": "01000000000101c76ddd01e185e12e995c6f4f36bd440867296d3f224751d73432d465be93478100000000232200204fe0358ee98bef039832fa3a4dc96cb4b265448f3d89c4a05a997a3481f3da6effffffff02102700000000000017a9142962c500562c9db56434702a629ff08fcbd5add0877d110100000000002251200176ff8248afd3d78e4570a52973768ff4cce26d59ddfed3d4d5963ceafa4e4c0400483045022100c4db3db14398d5cc4c9a2a3e4a8fa4fa3b8960ad80eb840e51e182f7561cf6c102207a6410e68aaf7327a1daed83838a39b96e37e22783d879a838640035b6059bcc0147304402205888b2863bb8fc296ed51374db2d03c7fdc746fd0d6c5ceebbe2246bb76b67840220730c8b8395285767ef1049c40cd6cbdecfb5ecfefd795ac2053b28b7a6b0790f0169522103a4c6a0aa167ef75fcf4a96c53b2dd20aee3afa19d1bc2ec4354328ae87c0976621022e4d77a9d0fecafc7ad4f9cfd9144082cf146b27de945ba26d22f26438c5784b2103ee2fef2c21d48bbd0d3813c71269fca6e1bff51e676b1f0131aa29afceb08f8853ae00000000", "status": "signed" }

Next

You can view your completed withdrawal in BitGo or on a blockchain explorer.

See Also