Resolve Nonce Holes

Identify and resolve nonce holes that cause stuck transactions on ETH-like coins. Includes flows for Custody MPC, Self-Custody MPC (Simple and Manual), and Go Account (Simple and Manual) wallets. See the Guide.

  1. Query the wallet for potentially stuck transactions on ETH-like coins. Stuck transactions caused by nonce holes return "cause": "nonceHole" and "userActionDisabled": false. Save the nonce value from the response for use in the next step.

    You can subscribe to the stuckTx wallet webhook to receive notifications when a transaction becomes stuck. For more information, see Create Wallet Webhooks.

    Prerequisites: You must have completed the Get Started guide and initiated a withdrawal (see Withdraw Overview).

    API Reference

  2. For Custody MPC wallets, create a new transaction that includes the nonce value from the stuck transaction identified in the prior step. Set intentType to "fillNonce" and pass the nonce value to fill the gap, using the Create Transaction Request endpoint.

    Withdrawal flows differ by wallet type. View the end-to-end transaction flow and integration guides for your wallet type at Withdraw Overview.

    API Reference

  3. For self-custody MPC wallets using the simple SDK flow, create a new transaction that includes the nonce value from the stuck transaction identified in the prior step. Set type to "fillNonce" and pass the nonce value to fill the gap, using the BitGo SDK sendMany method.

    The SDK authenticates, unlocks the session, then sends a transaction with type: "fillNonce" and the nonce from the stuck transaction.

    API Reference

  4. For self-custody MPC wallets using the manual REST flow, create a new transaction that includes the nonce value from the stuck transaction identified in the prior step. Set intentType to "fillNonce" and pass the nonce value to fill the gap, using the Create Transaction Request endpoint.

    API Reference

  5. For Go Account wallets using the simple flow, create a new transaction that includes the nonce value from the stuck transaction identified in the prior step. Set type to "fillNonce" and pass the nonce value to fill the gap, using the Send Transaction endpoint through BitGo Express. If withdrawing to another Go Account, pass walletId instead of address.

    API Reference

  6. For Go Account wallets using the manual flow, create a new transaction that includes the nonce value from the stuck transaction identified in the prior step. Set type to "fillNonce" and pass the nonce value to fill the gap, using the Build Transaction endpoint. If sending to another Go Account, use the walletId parameter instead of address.

    API Reference

// 1. Identify Stuck Transactions
export COIN="<ASSET_ID>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  "https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/potentialStuckTxs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
// 2. Custody MPC: Resolve Nonce Holes
export NONCE="<NONCE_VALUE_OF_STUCK_TRANSACTION>"

curl -X POST "https://app.bitgo-test.com/api/v2/wallet/$WALLET_ID/txrequests" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "idempotencyKey": "string",
    "intent": {
      "intentType": "fillNonce",
      "nonce": "'"$NONCE"'",
      "sequenceId": "4dEeycHsDSsCAG1zYPKGSxyPkHQ",
      "feeOptions": {
        "unit": "baseUnit",
        "formula": "fixed",
        "feeType": "base",
        "gasLimit": 0,
        "gasPrice": 0
      },
      "receiveAddress": "string",
      "senderAddressIndex": 0
    },
    "videoApprovers": [
      "585951a5df8380e0e3063e9f",
      "585951a5df8380e0e304a553"
    ],
    "apiVersion": "lite",
    "preview": false
  }'

// 3. Self-Custody MPC (Simple): Resolve Nonce Holes
// Use the JavaScript SDK for this step (see JavaScript tab)
// 4. Self-Custody MPC (Manual): Resolve Nonce Holes
export NONCE="<NONCE_VALUE_OF_STUCK_TRANSACTION>"

curl -X POST "https://app.bitgo-test.com/api/v2/wallet/$WALLET_ID/txrequests" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "idempotencyKey": "string",
    "intent": {
      "intentType": "fillNonce",
      "nonce": "'"$NONCE"'",
      "sequenceId": "4dEeycHsDSsCAG1zYPKGSxyPkHQ",
      "feeOptions": {
        "unit": "baseUnit",
        "formula": "fixed",
        "feeType": "base",
        "gasLimit": 0,
        "gasPrice": 0
      },
      "receiveAddress": "string",
      "senderAddressIndex": 0
    },
    "videoApprovers": [
      "585951a5df8380e0e3063e9f",
      "585951a5df8380e0e304a553"
    ],
    "apiVersion": "lite",
    "preview": false
  }'

// 5. Go Account (Simple): Resolve Nonce Holes
export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export COIN="<OFC_ASSET_ID>"
export ADDRESS="<DESTINATION_ADDRESS_OR_ID_HASH>"
export GO_ACCOUNT="<DESTINATION_WALLET_ID>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
export WALLET_PASSPHRASE="<YOUR_WALLET_PASSPHRASE>"
export NONCE="<NONCE_VALUE_OF_STUCK_TRANSACTION>"

curl -X POST \
  http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/$WALLET_ID/sendcoins \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "address": "'"$ADDRESS"'",
    "walletId": "'"$GO_ACCOUNT"'",
    "amount": "'"$AMOUNT"'",
    "walletPassphrase": "'"$WALLET_PASSPHRASE"'",
    "type": "fillNonce",
    "nonce": "'"$NONCE"'"
  }'

// 6. Go Account (Manual): Resolve Nonce Holes
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
export ADDRESS="<DESTINATION_ADDRESS>"
export NONCE="<NONCE_VALUE_OF_STUCK_TRANSACTION>"

curl -X POST \
  https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/tx/build \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "type": "fillNonce",
    "nonce": "'"$NONCE"'",
    "idfSignedTimestamp": "2025-01-28T10:55:38.732Z",
    "idfUserId": "628ca09d1b78a6022750254f0777561a",
    "idfVersion": 1,
    "instant": false,
    "preview": false,
    "recipients": [
      {
        "amount": "'"$AMOUNT"'",
        "address": "'"$ADDRESS"'"
      }
    ],
    "sequenceId": "4dEeycHsDSsCAG1zYPKGSxyPkHQ"
  }'
Response
// 1. Identify Stuck Transactions Response
[
  {
    "nonce": 200000,
    "txHex": "01000000000101d...a53aec8b11400",
    "txId": "b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26",
    "sendTransfer": {
      "baseValueString": "2000000",
      "bitgoOrg": "BitGo Trust",
      "coin": "hteth",
      "date": "2025-01-24T14:15:22Z",
      "enterprise": "59cd72485007a239fb00282ed480da1f",
      "history": [
        {
          "action": "created",
          "date": "2025-01-24T14:15:22Z",
          "txid": "b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26",
          "user": "59cd72485007a239fb00282ed480da1f"
        }
      ],
      "id": "59cd72485007a239fb00282ed480da1f",
      "organization": "59cd72485007a239fb00282ed480da1f",
      "pendingApproval": "664ed267aad92c62a183ac5f28883495",
      "state": "initialized",
      "txid": "b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26",
      "type": "send",
      "valueString": "2000000",
      "wallet": "59cd72485007a239fb00282ed480da1f",
      "walletType": "custodial"
    },
    "cause": "nonceHole",
    "gasAccelerationFee": {
      "gasPrice": "200000",
      "maxFeePerGas": "200000",
      "maxPriorityFeePerGas": "200000"
    },
    "userActionDisabled": false
  }
]

// Resolve Nonce Holes Response (applies to all wallet types)
{
  "txRequestId": "string",
  "version": 0,
  "latest": true,
  "walletId": "string",
  "walletType": "cold",
  "enterpriseId": "string",
  "state": "initialized",
  "date": {},
  "createdDate": {},
  "userId": "string",
  "initiatedBy": "string",
  "updatedBy": "string",
  "intent": {
    "intentType": "fillNonce",
    "nonce": "string",
    "sequenceId": "string",
    "comment": "string",
    "feeOptions": {
      "unit": "baseUnit",
      "formula": "fixed",
      "feeType": "base",
      "gasLimit": 0,
      "gasPrice": 0
    },
    "receiveAddress": "string",
    "senderAddressIndex": 0
  },
  "pendingApprovalId": "string",
  "isCanceled": true
}