Withdrawal

Only the address set as the controller address or withdrawal address can initiate a validator exit via our smart contract.

To initiate a withdrawal in the Ethereum network using the Staking API, follow these steps:

  1. Create a serialized transaction to initiate the withdrawal process for active validators and send it as a POST request to /api/v1/eth/staking/direct/tx/withdrawal. Use https://api-test.p2p.org for testing or https://api.p2p.org for production.

    Example request:

    curl --request POST \
         --url https://api.p2p.org/api/v1/eth/staking/direct/tx/withdrawal \
         --header 'accept: application/json' \
         --header 'authorization: Bearer <token>' \
         --header 'content-type: application/json' \
         --data '
    {
      "pubkeys": [
        "0xffC08FcD7cFeF5c70fB2b0e1f2A8EaA690AaE2bDFfa5dBEc4dEef31DcC0B19eB1f9Cebe3E2fe9eefBD9a1BDF6FD89b39"
      ]
    }
    '
    
    • pubkeys — list of validators public keys.

    Example response:

    {
       "result": {
          "serializeTx": "0x02f902d705808301674e8508530af16e830186a094681a1b3441c6bfb12f91651efd9f02c83c0702938901bc16d674ec800000b902a44f498c730000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030aa5f27070a21d79455c4a9b73c0aa4a8b1a65a1fb530d7fd8e6cd23aa16660679ac43ee4861098f6d9166aed3a4d8abb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002001000000000000000000000028c84612d37de9209018ad96167f12169b653e9a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060978c565cd915f4e885b4201093d1501697610eb9ee99b9b60b70434dc330e98d5b42927725304ded48483a8b8f39506d09bcb22ee18d4f6b50257946ac5ee360385308d95c0e2bc963902d42e985c29ee489aa3c989ac1561c952a6424f107a800000000000000000000000000000000000000000000000000000000000000014cb452f6e3f10ba2175c86a0284f53fcb61404b458393391abc3d5622e3e55cdc0",
          "to": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
          "gasLimit": "",
          "data": "",
          "value": "",
          "chainId": "",
          "type": "",
          "maxFeePerGas": "",
          "maxPriorityFeePerGas" : ""
       }      
    }
    
    • serializeTx — serialized unsigned transaction.
    • to — recipient address for this transaction.
    • gasLimit — maximum gas limit for this block.
    • data — transaction data.
    • value — amount this transaction is sending in Wei.
    • chainId — chain ID this transaction is authorized on, as specified by EIP-155.
    • typeEIP-2718 type of this transaction envelope.
    • maxFeePerGas — maximum price per unit of gas this transaction will pay for the combined EIP-1559 block's base fee and this transaction's priority fee in Wei.
    • maxPriorityFeePerGas — price per unit of gas in Wei, which is added to the EIP-1559 block's base fee. This added fee is used to incentivize miners to prioritize this transaction.
  2. Sign and broadcast the transaction:

    require("dotenv").config();
    const ethers = require("ethers");
    
    async function signAndBroadcast() {
      console.log("Started");
    
      // Enter the serialized transaction
      const rawTransaction = process.env.RAW_TRANSACTION;
    
      // Enter the private key of the address used to transfer the stake amount
      const privateKey = process.env.PRIVATE_KEY;
    
      // Enter the selected RPC URL
      const rpcURL = process.env.RPC_URL;
    
      // Initialize the provider using the RPC URL
      const provider = new ethers.providers.JsonRpcProvider(rpcURL);
    
      // Initialize a new Wallet instance
      const wallet = new ethers.Wallet(privateKey, provider);
    
      // Parse the raw transaction
      const tx = ethers.utils.parseTransaction(rawTransaction);
    
      tx.nonce = await provider.getTransactionCount(wallet.address);
    
      // Enter the max fee per gas and prirorty fee
      tx.maxFeePerGas = ethers.utils.parseUnits(
        process.env.MAX_FEE_PER_GAS_IN_GWEI,
        "gwei"
      );
      tx.maxPriorityFeePerGas = ethers.utils.parseUnits(
        process.env.MAX_PRIORITY_FEE_IN_GWEI,
        "gwei"
      );
    
      // Sign the transaction
      const signedTransaction = await wallet.signTransaction(tx);
    
      // Send the signed transaction
      const transactionResponse = await provider.sendTransaction(signedTransaction);
    
      return transactionResponse;
    }
    
    signAndBroadcast()
      .then((transactionResponse) => {
        console.log(
          "Transaction broadcasted, transaction hash:",
          transactionResponse.hash
        );
      })
      .catch((error) => {
        console.error("Error:", error);
      })
      .finally(() => {
        console.log("Finished");
      });
    
    

What's Next?