Withdraw On Chain from Lightning Wallet

Overview

You can withdraw bitcoin from your Lightning wallet to an on-chain address on the main Bitcoin blockchain. This process uses a specific Lightning Express endpoint to make the on-chain withdrawal.

Prerequisites

1. Build, Authenticate, and Send Transaction

Use BitGo Express to build, authenticate, and broadcast an on-chain bitcoin transaction all in one call.

Endpoint: Lightning - Onchain Withdrawal

export BITGO_EXPRESS_HOST="<YOUR_LOCALHOST>"
export COIN="tlntbc"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export WALLET_PASSPHRASE="<YOUR_WALLET_PASSPHRASE>"
export DESTINATION_ADDRESS="<DESTINATION_ADDRESS>"
export AMOUNT_SAT="<AMOUNT_IN_SATS>"
export SATSPERVBYTE="<FEE_RATE_IN_SATS_PER_VBYTE>"
export NUM_BLOCKS="<NUMBER_OF_BLOCKS_FOR_CONFIRMATION>"

curl -X POST \
  http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/$WALLET_ID/lightning/withdraw \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "passphrase": "'"$WALLET_PASSPHRASE"'",     # Wallet passphrase
    "recipients": [                             # Array of recipients for the withdrawal
      {
        "amount": "'"$AMOUNT_SAT"'",            # Amount to send in satoshis
        "address": "'"$DESTINATION_ADDRESS"'"   # Destination Bitcoin address
      }
    ],
    "satsPerVbyte": "'"$SATSPERVBYTE"'"         # Fee rate in satoshis per virtual byte
    "numBlocks": "'"$NUM_BLOCKS"'"              # Target number of blocks for confirmation, used for fee estimation
    "sequenceId": string,                       # Custom identifier for tracking the payment
    "comment": string                           # Additional note or comment for internal reference
  }'
  const { BitGo } = require('bitgo');
  const { getLightningWallet } = require('@bitgo/abstract-lightning');
  const accessToken = '<YOUR_ACCESS_TOKEN>';

  // Initialize the SDK
  const bitgo = new BitGo({
    accessToken: accessToken,
    env: 'test',
    customRootURI: 'https://app.bitgo-test.com',
  });

  // Enter your Lightning wallet
  const walletId = '<YOUR_WALLET_ID>'
  const existingWallet = await bitgo.coin('tlnbtc').wallets().get({ id: walletId });
  const lightningWallet = getLightningWallet(existingWallet);

  const onchainWithdrawal = await lightningWallet.withdrawOnchain({
    recipients: [
      {
        amount: 'amount to be sent in satoshis',
        address: 'destination address'
      }
    ],
    satsPerVbyte: 'fee rate in satoshis per virtual byte',
    passphrase: 'your wallet passphrase',
  });
  console.dir(onchainWithdrawal);

Step Result

If your on-chain withdrawal doesn't require approval, BitGo publishes the transaction to the blockchain. If you Create Policy Rules to require approvals on withdrawals, the transaction remains in a pending-approval status until a wallet admin approves it.

{
    "txRequestId": string,        // Unique identifier for the transaction request
    "txRequestState": delivered,  // State of the transaction request
    "withdrawStatus": {
      "status": delivered,        // Withdrawal status
      "txid": string,             // transaction ID of the on-chain transaction
      "failureReason": string     // Reason for failure if withdrawal failed
    },
    "transfer": {
      "id": string,
      "coin": string,
      "wallet": string,
      "walletType": string,
      "enterprise": string,
      "organization": string,
      "txid": string,
      "state": string,            // initialized, unconfirmed, confirmed
      "type": string,             // send, receive
      "value": number             // millisatoshis
      "valueString": string,      // millisatoshis
      "coinSpecific": {
        "isOffchain": false,
        "invoice": string
      },
    }
}

2. Approve Transaction (Optional)

Note: If you configure an approval requirement for withdrawals, you can't approve your own transactions - another admin must approve them.

Endpoint: Update Pending Approval

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"'"
  }'
const baseCoin = this.bitgoSDK.coin(initialPendingApproval.coin);
const pendingApproval = await baseCoin.pendingApprovals().get({ id: initialPendingApproval.id });
const result = await pendingApproval.approve(params);

Step Result

Once approved, BitGo submits the transaction to a Lightning Network Daemon (LND) for broadcasting to the Bitcoin blockchain.

{
  "id": "655686880765186f0b3e9e88e1bdd0f4",
  "coin": "tbtc4",
  "wallet": "6553e933288be490293ae748efafeaaf",
  "enterprise": "62c5ae8174ac860007aff138a2d74df7",
  "creator": "62ab90e06dfda30007974f0a52a12995",
  "createDate": "2023-11-16T21:15:52.703Z",
  "info": {
    "type": "transactionRequest",
    "transactionRequest": {
      "requestedAmount": "10000",
      "fee": 45242,
      "sourceWallet": "6553e933288be490293ae748efafeaaf",
      "policyUniqueId": "6553e933288be490293ae753",
      "recipients": [
        {
          "address": "2N3sBpM1RnWRMXnEVoUWnM7xtYzL756JE2Q",
          "amount": "10000",
          "_id": "655686880765186f0b3e9e8a"
        }
      ],
      "buildParams": {
        "recipients": [
          {
            "address": "2N3sBpM1RnWRMXnEVoUWnM7xtYzL756JE2Q",
            "amount": "10000"
          }
        ],
        "changeAddressType": [
          "p2trMusig2",
          "p2wsh",
          "p2shP2wsh",
          "p2sh",
          "p2tr"
        ],
        "txFormat": "psbt"
      },
      "coinSpecific": {
        "tbtc4": {
          "txHex": "01000000000101eac5e7d68acfc2349672fb99094e79c2006e5fd663475c8f1eb6f29095970b740100000000ffffffff02102700000000000017a914747e6b7f5db53794b0fc01d95878e0f9b6db96738746c1020000000000220020efb9deaabeab5d62cecc363f24cd6deafcdd14d93d8734f7f01ed3953e732a640500483045022100cd6c221e4cefbb51aa82087d86e7d089b2473eb21ae809dba89eb9f13c4caf19022000f3b7f1b7fec2dc49cbfce35baa69ca37ab9ee8e51c779cde5b98a653f3e142010000695221029bde55661e4f359cf9ca2d1846c235e752f760ed6d65e2018f821253e78b3c722103f2b4a813ab79e4fb46edf3a6a87fb154a85b45810158e949f41a3fce3c9bf574210399a6d766f6d3a3843f8479446ee766b5745dc15c24d1db5149214d27987bd29453ae00000000"
        }
      },
      "validTransaction": "01000000000101eac5e7d68acfc2349672fb99094e79c2006e5fd663475c8f1eb6f29095970b740100000000ffffffff02102700000000000017a914747e6b7f5db53794b0fc01d95878e0f9b6db96738746c1020000000000220020efb9deaabeab5d62cecc363f24cd6deafcdd14d93d8734f7f01ed3953e732a640400483045022100cd6c221e4cefbb51aa82087d86e7d089b2473eb21ae809dba89eb9f13c4caf19022000f3b7f1b7fec2dc49cbfce35baa69ca37ab9ee8e51c779cde5b98a653f3e14201473044022002b246c43722fec49858caf6b0605a0d01a6b6c13c964b84bf272604fd3951780220324ee44ba3ce8febb154c317e688a5f6ed410ad8e2bd77c5678bf1f7f3eb45f601695221029bde55661e4f359cf9ca2d1846c235e752f760ed6d65e2018f821253e78b3c722103f2b4a813ab79e4fb46edf3a6a87fb154a85b45810158e949f41a3fce3c9bf574210399a6d766f6d3a3843f8479446ee766b5745dc15c24d1db5149214d27987bd29453ae00000000",
      "validTransactionHash": "ff40ccd5c8ba75ffdce27d8584b6e8ee625cb3f71f7cbb6d072a445a97c2c8c3"
    }
  },
  "state": "approved",
  "scope": "wallet",
  "userIds": [
    "62ab90e06dfda30007974f0a52a12995",
    "627ff9325a5c1b0007c05a40d15e1522"
  ],
  "approvalsRequired": 1,
  "singleRunResults": [
    {
      "ruleId": "Custody Enterprise Transaction ID Verification",
      "triggered": false,
      "_id": "655686880765186f0b3e9e89"
    }
  ],
  "resolvers": [
    {
      "user": "627ff9325a5c1b0007c05a40d15e1522",
      "date": "2023-11-16T21:33:24.644Z",
      "resolutionType": "pending"
    }
  ]
}
{
  "id": "65568eda6c1568b87f40a6131d4fbc89",
  "coin": "tbtc4",
  "wallet": "6553e933288be490293ae748efafeaaf",
  "enterprise": "62c5ae8174ac860007aff138a2d74df7",
  "creator": "62ab90e06dfda30007974f0a52a12995",
  "createDate": "2023-11-16T21:51:22.221Z",
  "info": {
    "type": "transactionRequest",
    "transactionRequest": {
      "requestedAmount": "20000",
      "fee": 51622,
      "sourceWallet": "6553e933288be490293ae748efafeaaf",
      "policyUniqueId": "6553e933288be490293ae753",
      "recipients": [
        {
          "address": "2MzCZbQ2pcHKBPzhpdeaKBgu52YtqdDv6Le",
          "amount": "10000",
          "_id": "65568eda6c1568b87f40a615"
        },
        {
          "address": "2NDi4jr1DjqpWBU6FJRqq5uaiWihwXJAWSU",
          "amount": "10000",
          "_id": "65568eda6c1568b87f40a616"
        }
      ],
      "buildParams": {
        "recipients": [
          {
            "address": "2MzCZbQ2pcHKBPzhpdeaKBgu52YtqdDv6Le",
            "amount": "10000"
          },
          {
            "address": "2NDi4jr1DjqpWBU6FJRqq5uaiWihwXJAWSU",
            "amount": "10000"
          }
        ],
        "changeAddressType": [
          "p2trMusig2",
          "p2wsh",
          "p2shP2wsh",
          "p2sh",
          "p2tr"
        ],
        "txFormat": "psbt"
      },
      "coinSpecific": {
        "tbtc4": {
          "txHex": "01000000000101c3c8c2975a442a076dbb7c1ff7b35c62eee8b684857de2dcff75bac8d5cc40ff0100000000ffffffff03102700000000000017a9144c47ff958d212988eb5e0407ede223d66d8fdbab87102700000000000017a914e07606a95924b156375a9b3929c2ae63db20e3bd8780a90100000000002200209cb3a333ddbdb7496ad4c7ee8f339ac2e3dfb648e3dfec4b0635b0e5541102610500483045022100883f2c5a762a307380723cad5d536329b45aa2a67ee5c53940551c926902929002203cba824bc6fc01ba6510131b47137dc7b292d96938c89c7e12b891ca039781f601000069522102b2c328f03cb3b1a513adaae92226dfbaeabfdf053ba5057b1922a327798261a22102c0e4a38730d48b220547abe8d6676c9a432245c7c968b5e8e9609a7837c773b021025e180472019c87bc2cdef9e1bc787369e9e5fd6212c5f01549bb96c155e8cdbd53ae00000000"
        }
      },
      "validTransaction": "01000000000101c3c8c2975a442a076dbb7c1ff7b35c62eee8b684857de2dcff75bac8d5cc40ff0100000000ffffffff03102700000000000017a9144c47ff958d212988eb5e0407ede223d66d8fdbab87102700000000000017a914e07606a95924b156375a9b3929c2ae63db20e3bd8780a90100000000002200209cb3a333ddbdb7496ad4c7ee8f339ac2e3dfb648e3dfec4b0635b0e5541102610400483045022100883f2c5a762a307380723cad5d536329b45aa2a67ee5c53940551c926902929002203cba824bc6fc01ba6510131b47137dc7b292d96938c89c7e12b891ca039781f60147304402203c309e14eda12d133d7885deddbf95b15878fc69758bd81bb3b3fbaf1088c8dc02201286da4e0ffde355d399b6659feb2d30db28f26586e0de9d3f8f9a6fb701ac330169522102b2c328f03cb3b1a513adaae92226dfbaeabfdf053ba5057b1922a327798261a22102c0e4a38730d48b220547abe8d6676c9a432245c7c968b5e8e9609a7837c773b021025e180472019c87bc2cdef9e1bc787369e9e5fd6212c5f01549bb96c155e8cdbd53ae00000000",
      "validTransactionHash": "4929b91960acdf2d18076ac6151d0aff96b4f4834f9f78eaf40e78ce05f5c0a4"
    }
  },
  "state": "approved",
  "scope": "wallet",
  "userIds": [
    "62ab90e06dfda30007974f0a52a12995",
    "627ff9325a5c1b0007c05a40d15e1522"
  ],
  "approvalsRequired": 1,
  "singleRunResults": [
    {
      "ruleId": "Custody Enterprise Transaction ID Verification",
      "triggered": false,
      "_id": "65568eda6c1568b87f40a614"
    }
  ],
  "resolvers": [
    {
      "user": "627ff9325a5c1b0007c05a40d15e1522",
      "date": "2023-11-16T21:56:45.511Z",
      "resolutionType": "pending"
    }
  ]
}

Next

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

See Also