# Release Stuck Transactions Network congestion or low transaction fees may prevent a transaction sent to the node from being included in a block. If a transaction remains unprocessed for a certain period after submission (10 minutes on EVM chain, 60 minutes on Bitcoin), Fordefi marks it as STUCK. Fordefi provides two ways to resolve a stuck transaction: - **Accelerate**: Resend the original transaction with a higher fee. - **Cancel**: Replace the original transaction with a higher-fee transaction that sends funds back to yourself, effectively nullifying the original. These methods, collectively referred to as **releasing** the transaction, are available on **EVM chains** and on **Bitcoin**. The underlying mechanics are similar across the two chain types: - On EVM chains, the replacement transaction uses the same nonce as the original and a higher gas price. - On Bitcoin, the replacement transaction uses the same UTXOs, a higher sequence number, and an increased fee per byte. To cancel a transaction on Bitcoin, the replacement transaction spends the same UTXOs but sends the funds back to your own address, effectively nullifying the original. In both cases, the higher fee incentivizes miners to include the replacement transaction in a block, making it more likely to be mined than the original. Once the replacement is mined, the original becomes ineligible to be mined and is dropped by nodes. ### Release a stuck transaction Learn more about [releasing](/user-guide/manage-transactions/release-transaction) transactions using the Fordefi web console. To programmatically release a transaction, you need to call the [Release Transaction](/api/openapi/transactions/release_transaction_api_v1_transactions__id__release_post) API by sending a `POST` request to the `/api/v1/transactions/{id}/release` endpoint, where `{id}` is the ID of the original transaction. Since releasing a transacton creates a new transaction, it is a sensitive operation and thus requires [signing the request](/developers/authentication#request-signing). The following examples demonstrate how to release a transaction in different programming languages: Shell ```shell #!bash ACCESS_TOKEN='' PRIVATE_KEY_FILE='' ENDPOINT='' BODY='' TIMESTAMP="$(($(date +%s) * 1000))" SIGNATURE="$(echo -n "${ENDPOINT}|${TIMESTAMP}|${BODY}" | openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} | base64 | tr -d \\n)" echo -n "${ENDPOINT}|${TIMESTAMP}|${BODY}" curl -v "https://api.fordefi.com${ENDPOINT}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "x-signature: ${SIGNATURE}" \ -H "x-timestamp: ${TIMESTAMP}" \ -d "${BODY}" ``` Python ```py import requests import base64 import json import datetime import ecdsa import hashlib access_token = "" private_key_file = "" path = "" request_json = timestamp = datetime.datetime.now().strftime("%s") request_body = json.dumps(request_json) payload = f"{path}|{timestamp}|{request_body}" with open(private_key_file, "r") as f: signing_key = ecdsa.SigningKey.from_pem(f.read()) signature = signing_key.sign( data=payload.encode(), hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der ) resp_tx = requests.post( f"https://api.fordefi.com{path}", headers={ "Authorization": f"Bearer {access_token}", "x-signature": base64.b64encode(signature), "x-timestamp": timestamp.encode(), }, data=request_body, ) ``` Javascript ```js const crypto = require("crypto"); const fs = require('fs'); const accessToken = "" const privateKeyFile = "" const path = "" const requestJson = const gatewayHost = "api.fordefi.com" const requestBody = JSON.stringify(requestJson) const timestamp = new Date().getTime(); const payload = `${path}|${timestamp}|${requestBody}`; const secretPem = fs.readFileSync(privateKeyFile, 'utf8'); const privateKey = crypto.createPrivateKey(secretPem); const sign = crypto.createSign('SHA256').update(payload, 'utf8').end(); const signature = sign.sign(privateKey, 'base64'); fetch(`https://${gatewayHost}${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${accessToken}`, 'X-Timestamp': timestamp, 'X-Signature': signature, }, body: requestBody, }).then((response) => response.text()) .then((json) => console.log(json)); ``` Rust ```rust // Using crate p256 = { version = "0.12.0", features = ["pem"] } use base64::{engine::general_purpose, Engine as _}; use p256::ecdsa::{signature::Signer, Signature, SigningKey}; use std::fs; use std::time::{SystemTime, UNIX_EPOCH}; // This is the main function fn main() -> Result<(), Box> { let access_token = ""; let private_key_file = ""; let path = ""; let request_body = r#" "#; let gateway_host = "api.fordefi.com"; let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_millis() .to_string(); let payload = format!("{path}|{timestamp}|{request_body}"); let priv_pem = fs::read_to_string(private_key_file).expect("Failed to read pem file"); let private_key = p256::SecretKey::from_sec1_pem(&priv_pem).expect("Failed to decode pem key"); let signing_key: SigningKey = private_key.into(); let signature: Signature = signing_key.sign(payload.as_bytes()); let formatted_signature = general_purpose::STANDARD.encode(signature.to_der().to_bytes()); let client = reqwest::blocking::Client::new(); let res = client .post(format!("https://{gateway_host}{path}")) .body(request_body) .bearer_auth(access_token) .header("Content-Type", "application/json") .header("X-Timestamp", timestamp) .header("X-Signature", formatted_signature) .send()? .text()?; println!("Result: {res}"); Ok(()) } ``` #### Transaction information Once cancelled or accelerated, the original transaction includes a `child_transaction_id` field, which contains the id of the newly created replacement transaction. The replacement transactions points back to the original transaction in its `parent_transaction_id` field and also has its `is_cancelation` or `is_acceleration` fields set. You can obtain the transaction objects that contain these data using the [Get Transaction endpoint](/api/openapi/transactions/get_transaction_api_v1_transactions__id__get). ### Release a stuck transaction - advanced method for EVM chains Acceleration is usually the preferred method for releasing a stuck transaction. However, when the original stuck transaction is no longer relevant, canceling it is the simplest solution. The downside of canceling is that it sends an "empty" transaction, which still incurs gas fees. To avoid paying this fee, you can replace the stuck transaction with a different transaction instead of an empty one. Create your desired transaction and use the `custom_nonce` field in the [Create Transaction](https://documentation.fordefi.com/redoc#operation/create_transaction_api_v1_transactions_post) call to reuse the nonce from the stuck transaction. This new transaction will then replace the stuck transaction. Here's how: ```json { "vault_id": "16b5aa12-509e-4944-b656-cf096515d627", "signer_type": "api_signer", "type": "evm_transaction", "details": { "type": "evm_raw_transaction", "chain": "ethereum_mainnet", "to": "0x565697B5DD1F7Bdc61f774807057D058E5A27cbC", "value": "0", "data": { "type": "hex", "hex_data": "0x0d1d7ae50000000000000000000000000000000000000000000000000000000000000006" }, "custom_nonce": "47890", } } ```