> ## Documentation Index
> Fetch the complete documentation index at: https://docs.p2p.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting Started

> Restake Ethereum with EigenLayer using the P2P.org Restaking API.

The EigenLayer restaking flow includes the following steps:

1. Create EigenPod address: construct a serialized transaction to generate an EigenPod address, which your validator can use as a withdrawal address.
2. Create Staking Request: set up nodes for staking using P2P infrastructure.
3. Check Request Status: check the status of the node set-up operation.
4. Prepare Staking Transaction: construct a serialized transaction to deposit the stake amount with a smart contract.
5. Verify Withdrawal Credentials: construct a serialized transaction to verify the validator withdrawal credentials on-chain.
6. Delegate Restake to Operator: construct a serialized transaction to delegate the restake amount to the EigenLayer node operator.

[Get an authentication token](/docs/authentication) to start using Restaking API.

Request examples are provided using [cURL](https://curl.se/).

***

## 1. Create eigenPod address

1. Retrieve a serialized transaction to generate an EigenPod address by sending a POST request to [/api/v1/eth/staking/eigenlayer/tx/create-pod](/reference/eth-eigen-create-pod).

   Example request:

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/create-pod \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>'
       --header 'content-type: application/json'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/create-pod", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/create-pod",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/create-pod", nil)
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

Example response:

<CodeGroup>
  ```json theme={null}
  {
      "result": {
        "serializeTx": "0x02f902d705808301674e8508530af16e830186a094681a1b3441c6bfb12f91651efd9f02c83c0702938901bc16d674ec800000b902a44f498c730000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030aa5f27070a21d79455c4a9b73c0aa4a8b1a65a1fb530d7fd8e6cd23aa16660679ac43ee4861098f6d9166aed3a4d8abb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002001000000000000000000000028c84612d37de9209018ad96167f12169b653e9a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060978c565cd915f4e885b4201093d1501697610eb9ee99b9b60b70434dc330e98d5b42927725304ded48483a8b8f39506d09bcb22ee18d4f6b50257946ac5ee360385308d95c0e2bc963902d42e985c29ee489aa3c989ac1561c952a6424f107a800000000000000000000000000000000000000000000000000000000000000014cb452f6e3f10ba2175c86a0284f53fcb61404b458393391abc3d5622e3e55cdc0",
        "to": "0x30770d7E3e71112d7A6b7259542D1f680a70e315",
        "gasLimit": "10000000",
        "data": "0x84d81062",
        "value": "0",
        "chainId": "17000",
        "type": "2",
        "maxFeePerGas": "1000040",
        "maxPriorityFeePerGas": "1000000"
      },
      "error": {}
    }
  ```
</CodeGroup>

* `serializeTx` — serialized <Tooltip tip="A transaction that must be signed and broadcasted to the blockchain network.">unsigned transaction</Tooltip>.
* `to` — recipient address for this transaction.
* `gasLimit` — maximum <Tooltip tip="A measure of computational effort required to execute a transaction or smart contract on a blockchain. Users must pay a gas fee, usually in the native token, to have their transactions processed by the network.">gas</Tooltip> 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](https://eips.ethereum.org/EIPS/eip-155).
* `type` — [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) type of this transaction envelope.
* `maxFeePerGas` — maximum price per unit of gas this transaction will pay for the combined [EIP-1559](https://eips.ethereum.org/EIPS/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](https://eips.ethereum.org/EIPS/eip-1559) block's base fee. This added fee is used to incentivize miners to prioritize this transaction.

2. Use `serializeTx` to [sign and send](/docs/signing-transaction-eth) the signed transaction to the Ethereum network.

   By broadcasting this transaction, you are generating an EigenPod address. The Ethereum address used to sign this transaction will become the `eigenPodOwnerAddress`.

## 2. Create staking request

1. Prepare`id` that is an arbitrary UUID. Generate it in one of the following ways:

   * [Online UUID Generator](https://www.uuidgenerator.net/)
   * [uuid npm package](https://www.npmjs.com/package/uuid)

2. Set up staking nodes through the P2P infrastructure by sending a POST request with the `RESTAKING` type to [/api/v1/eth/staking/direct/nodes-request/create](/reference/eth-nodes-request-create).

   Example request:

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/create \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>' \
       --header 'content-type: application/json' \
       --data '
  {
      "id":"6df58880-c4c9-484a-8fc4-7f7668fe9522",
      "type": "RESTAKING",
      "validatorsCount": 1,
      "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
      "feeRecipientAddress":"0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",    
      "controllerAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
      "nodesOptions":{
         "location": "any",
         "relaysSet": null
      }
  }
  '
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/create", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
    body: JSON.stringify({
        "id": "6df58880-c4c9-484a-8fc4-7f7668fe9522",
        "type": "RESTAKING",
        "validatorsCount": 1,
        "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
        "feeRecipientAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
        "controllerAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
        "nodesOptions": {
            "location": "any",
            "relaysSet": null
        }
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/create",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
      json={
              "id": "6df58880-c4c9-484a-8fc4-7f7668fe9522",
              "type": "RESTAKING",
              "validatorsCount": 1,
              "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
              "feeRecipientAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
              "controllerAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
              "nodesOptions": {
                      "location": "any",
                      "relaysSet": None
              }
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"id": "6df58880-c4c9-484a-8fc4-7f7668fe9522",
  		"type": "RESTAKING",
  		"validatorsCount": 1,
  		"eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
  		"feeRecipientAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
  		"controllerAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
  		"nodesOptions": map[string]interface{}{"location": "any", "relaysSet": nil},
  	}
  	body, _ := json.Marshal(payload)
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/create", bytes.NewBuffer(body))
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `id` — arbitrary UUID. You can later use that UUID to check the status of the set-up operation.

* `type` — staking operation type:

  * `RESTAKING` — value for initiating a restaking operation.
  * `REGULAR` — default value used for native staking transactions.

* `validatorsCount` — number of validators. One validator is equal to 32 ETH.

* `feeRecipientAddress` — fee recipient address.

* `eigenPodOwnerAddress` — owner of the EigenPod address, created in the [previous step](/docs/restaking-eth#1-create-eigenpod-address).

* `controllerAddress` — <Tooltip tip="On Ethereum, we introduced the controller address entity to provide greater flexibility and maintain high-level security during the withdrawal flow. When the user requests the validator withdrawal, only authorized addresses can initiate this request by calling our withdrawal smart contract. The authorized addresses are the withdrawal address and the controller address. Since many users prefer not to use the withdrawal address to interact with smart contracts, a second authorized address can be specified as controller address in the new staking request.">controller address</Tooltip> for the validators.

* `nodesOptions`:

* * `location` — node location. Currently, only `any` is supported.
  * `relaysSet` — Miner Extractable Value (<Tooltip tip="Miner Extractable Value Relay Selection is a process of selecting a validator to participate in the next Ethereum block based on the value that they can extract from transactions in that block.">MEV</Tooltip>) relay selection.

Example response:

<CodeGroup>
  ```json theme={null}
  {
      "result": true
    }
  ```
</CodeGroup>

## 3. Check request status

Check the status of the node set-up operation by sending a GET request to [`/api/v1/eth/staking/direct/nodes-request/status/\{id}`](/reference/eth-nodes-request-status).

Example request:

<CodeGroup>
  ```bash curl theme={null}
  curl --request GET \
       --url https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/status/6df58880-c4c9-484a-8fc4-7f7668fe9522 \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>'
       --header 'content-type: application/json'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/status/6df58880-c4c9-484a-8fc4-7f7668fe9522", {
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/status/6df58880-c4c9-484a-8fc4-7f7668fe9522",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	req, _ := http.NewRequest("GET", "https://api.p2p.org/api/v1/eth/staking/direct/nodes-request/status/6df58880-c4c9-484a-8fc4-7f7668fe9522", nil)
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `id` — UUID that was specified in the node set-up request.

Example response:

<CodeGroup>
  ```json theme={null}
  {
      "result": {
        "id": "6df58880-c4c9-484a-8fc4-7f7668fe9522",
        "status": "ready",
        "type": "RESTAKING",
        "validatorsCount": 1,
        "withdrawalAddress": null,
        "eigenPodAddress": "0x1433F808a4867aDEeEb3AE0Df58691C252269A2C",
        "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
        "controllerAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
        "feeRecipientAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
        "depositData": [
          {
            "pubkey": "0xaed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13",
            "signature": "0x91b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf5",
            "depositDataRoot": "0xd0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89",
            "withdrawalCredentials": "0100000000000000000000001433f808a4867adeeeb3ae0df58691c252269a2c",
            "amount": 32000000000,
            "depositMessageRoot": "04f641c39de982aee68cc7c78bd23bcafffed91fd1c455282b651e0c8d6c4e20",
            "forkVersion": "01017000",
            "eth2NetworkName": "hoodi",
            "depositCliVersion": "2.7.0"
          }
        ],
        "createdAt": "2025-01-29T15:07:08.399Z"
      }
    }
  ```
</CodeGroup>

* `id` — UUID that was specified in the node set-up request.

* `status` — current status of the node request:

  * `init` — node request is created.
  * `processing` — node request is in progress.
  * `ready` — backend has the deposit data for the node request.
  * `cancel` — something went wrong and the deposit data was not created.

* `validatorsCount` — number of validators. One validator is equal to 32 ETH.

* `withdrawalAddress` — withdrawal address for the validators that is set to `null` by default; corresponds to the EigenPod address.

* `eigenPodAddress` — EigenPod address also used as the validator withdrawal address.

* `eigenPodOwnerAddress` — owner of the EigenPod address.

* `controllerAddress` — <Tooltip tip="On Ethereum, we introduced the controller address entity to provide greater flexibility and maintain high-level security during the withdrawal flow. When the user requests the validator withdrawal, only authorized addresses can initiate this request by calling our withdrawal smart contract. The authorized addresses are the withdrawal address and the controller address. Since many users prefer not to use the withdrawal address to interact with smart contracts, a second authorized address can be specified as controller address in the new staking request.">controller address</Tooltip> for the validators.

* `feeRecipientAddress` — fee recipient address.

* `depositData`:

  * `pubkey` — validator public key.
  * `signature` — validator signature.
  * `depositDataRoot` — SHA-256 hash of the SSZ-encoded DepositData object; used as a protection against malformed input.
  * `withdrawalCredentials`— withdrawal address credentials, passed in the expected format by the Ethereum deposit smart contract.
  * `amount` — amount of ETH, denominated in Gwei, that is being deposited.
  * `depositMessageRoot` — cryptographic hash of the Merkle tree’s root, ensuring the integrity and authenticity of the deposit data.
  * `forkVersion` — version of the network fork that the deposit is intended for. It helps in aligning the deposit with a specific version of the protocol.
  * `eth2NetworkName` — name of the Ethereum 2.0 network where the deposit is made.
  * `depositCliVersion` — version of the deposit command-line interface (CLI) tool that was used to generate the deposit data.

* `createdAt` — timestamp of the transaction in the ISO 8601 format.

## 4. Prepare staking transaction

There are two flow to make a deposit:

| Workflow                  | Best For    | Logic                                                                             |
| ------------------------- | ----------- | --------------------------------------------------------------------------------- |
| Simplified Smart Contract | Most Users  | Uses P2P proxy contract to handle registration and deposit in one flow.           |
| Direct Interaction        | Power Users | Manually interacting with the Ethereum Deposit Contract for fine-grained control. |

### 4.1 [P2P Proxy deposit](/docs/direct-staking#p2p-direct-staking-v1-eth2-depositor--message-sender-flow)

Create a serialized transaction for depositing the stake amount and send it as a POST request to [/api/v1/eth/staking/direct/tx/deposit](/reference/eth-staking-deposit).

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/eth/staking/direct/tx/deposit \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>' \
       --header 'content-type: application/json' \
       --data '
   {
     "withdrawalAddress": "0x1433F808a4867aDEeEb3AE0Df58691C252269A2C",
     "depositData": [
       {
         "pubkey": "0xaed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13",
         "signature": "0x91b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf5",
         "depositDataRoot": "0xd0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89"
       }
     ]
   }
  '
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/direct/tx/deposit", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
    body: JSON.stringify({
        "withdrawalAddress": "0x1433F808a4867aDEeEb3AE0Df58691C252269A2C",
        "depositData": [
            {
                "pubkey": "0xaed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13",
                "signature": "0x91b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf5",
                "depositDataRoot": "0xd0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89"
            }
        ]
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/eth/staking/direct/tx/deposit",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
      json={
              "withdrawalAddress": "0x1433F808a4867aDEeEb3AE0Df58691C252269A2C",
              "depositData": [
                      {
                              "pubkey": "0xaed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13",
                              "signature": "0x91b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf5",
                              "depositDataRoot": "0xd0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89"
                      }
              ]
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"withdrawalAddress": "0x1433F808a4867aDEeEb3AE0Df58691C252269A2C",
  		"depositData": []interface{}{map[string]interface{}{"pubkey": "0xaed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13", "signature": "0x91b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf5", "depositDataRoot": "0xd0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89"}},
  	}
  	body, _ := json.Marshal(payload)
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/eth/staking/direct/tx/deposit", bytes.NewBuffer(body))
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `withdrawalAddress` — withdrawal address for the validators. For the `RESTAKING` operation type, this corresponds to the `eigenPodAddress` in the step 3 [Check Request Status](/docs/restaking-eth#3-check-request-status).

* `depositData`:

  * `pubkey` — validator public key.
  * `signature` — validator signature.
  * `depositDataRoot` — hash of the deposit data.
  * `withdrawalCredentials`— withdrawal address credentials, passed in the expected format by the Ethereum deposit smart contract.
  * `amount` — amount of ETH, denominated in Gwei, that is being deposited.
  * `depositMessageRoot` — cryptographic hash of the Merkle tree’s root, ensuring the integrity and authenticity of the deposit data.
  * `forkVersion` — version of the network fork that the deposit is intended for. It helps in aligning the deposit with a specific version of the protocol.
  * `eth2NetworkName` — name of the Ethereum 2.0 network where the deposit is made.
  * `depositCliVersion` — version of the deposit command-line interface (CLI) tool that was used to generate the deposit data.

Example response:

<CodeGroup>
  ```json theme={null}
  {
      "error": null,
      "result": {
        "serializeTx": "0x02f902d305808205508205c8830186a094681a1b3441c6bfb12f91651efd9f02c83c0702938901bc16d674ec800000b902a44f498c730000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030aed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000001433f808a4867adeeeb3ae0df58691c252269a2c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006091b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf50000000000000000000000000000000000000000000000000000000000000001d0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89c0",
        "to": "0xAD91441aB557b5eC5d9f29DB64522Eb918B4f32b",
        "gasLimit": "100000",
        "data": "0x4f498c730000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030aed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000001433f808a4867adeeeb3ae0df58691c252269a2c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006091b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf50000000000000000000000000000000000000000000000000000000000000001d0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89",
        "value": "32000000000000000000",
        "chainId": 17000,
        "type": 2,
        "maxFeePerGas": "1000030",
        "maxPriorityFeePerGas": "1000000"
      }
    }
  ```
</CodeGroup>

Example response is the same as in the [Create EigenPod Address](/docs/restaking-eth#1-create-eigenpod-address) step.

Use `serializeTx` to [sign and send](/docs/signing-transaction-eth) the signed transaction to the Ethereum network.

By broadcasting this transaction, you are depositing the required stake amount in the Ethereum deposit smart contract by using the [P2P smart contract](/docs/direct-staking#p2p-direct-staking-v1-eth2-depositor--message-sender-flow) as a proxy.

### 4.2 Ethereum direct deposit

Use this if you prefer to interact with the official Ethereum contract without a proxy.

1. Take the pubkey, signature, and depositDataRoot from the deposit-data response.
2. Go to the [Official Ethereum Deposit Contract](https://etherscan.io/address/0x00000000219ab540356cBB839Cbe05303d7705Fa)
3. Manually execute the `deposit` function with your 32 ETH and the provided data.

## 5. Verify withdrawal credentials

Before starting, ensure your validator has reached the `active_ongoing` status. The API identifies your associated EigenPod and ownership via the EigenPod Owner and signer of your request.

<Warning>
  Time taken for validator activation depends on the state of the chain. Verify status by sending a POST request to [/api/v1/eth/staking/direct/validator/status](/reference/eth-validator-status). Proceed only once the status is `active_ongoing`.
</Warning>

1. Verify withdrawal credentials by sending a POST request to [/api/v1/eth/staking/eigenlayer/tx/verify-withdrawal-credentials](/reference/eth-eigen-verify-withdrawal-credentials). This links your validator's principal withdrawal path to your EigenPod.

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/verify-withdrawal-credentials \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>' \
       --header 'content-type: application/json' \
       --data '
  {
      "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
      "pubkey": "0xffC08FcD7cFeF5c70fB2b0e1f2A8EaA690AaE2bDFfa5dBEc4dEef31DcC0B19eB1f9Cebe3E2fe9eefBD9a1BDF6FD89b39"
  }
  '
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/verify-withdrawal-credentials", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
    body: JSON.stringify({
        "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
        "pubkey": "0xffC08FcD7cFeF5c70fB2b0e1f2A8EaA690AaE2bDFfa5dBEc4dEef31DcC0B19eB1f9Cebe3E2fe9eefBD9a1BDF6FD89b39"
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/verify-withdrawal-credentials",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
      json={
              "eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
              "pubkey": "0xffC08FcD7cFeF5c70fB2b0e1f2A8EaA690AaE2bDFfa5dBEc4dEef31DcC0B19eB1f9Cebe3E2fe9eefBD9a1BDF6FD89b39"
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"eigenPodOwnerAddress": "0x27AABeE07E0dbC8b0de20f42b1a1980871314Ef5",
  		"pubkey": "0xffC08FcD7cFeF5c70fB2b0e1f2A8EaA690AaE2bDFfa5dBEc4dEef31DcC0B19eB1f9Cebe3E2fe9eefBD9a1BDF6FD89b39",
  	}
  	body, _ := json.Marshal(payload)
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/verify-withdrawal-credentials", bytes.NewBuffer(body))
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `eigenPodOwnerAddress` — owner of the EigenPod address.
* `pubkey` — validator public key.

Example response:

<CodeGroup>
  ```json theme={null}
  {
      "error": null,
      "result": {
        "list": [
          {
            "serializeTx": "0x02f902d305808205508205c8830186a094681a1b3441c6bfb12f91651efd9f02c83c0702938901bc16d674ec800000b902a44f498c730000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030aed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000001433f808a4867adeeeb3ae0df58691c252269a2c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006091b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf50000000000000000000000000000000000000000000000000000000000000001d0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89c0",
            "to": "0xAD91441aB557b5eC5d9f29DB64522Eb918B4f32b",
            "gasLimit": "10000000",
            "data": "0x4f498c730000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030aed7226d86d884dd44bc45c2b57f7634e72abf247713163388b1c34d89a1322d7228ca023dbaf2465b822e35ba00da13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000001433f808a4867adeeeb3ae0df58691c252269a2c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006091b710f0e3affe704e76ada81b095afbedf4b760f3160760e8fa0298cc4858e0f325c2652dc698ec63c59db65562551114ab7fcafe1d675eaaf186fa7758800f0157bd0b51cd3a131fac562d6933658ddbf182aab8d20a9483b1392085e54cf50000000000000000000000000000000000000000000000000000000000000001d0d00dce54b4ec8a7803783fc786a859459ead1d35b856c525cb289aba4b0f89",
            "value": "0",
            "chainId": 17000,
            "type": 2,
            "maxFeePerGas": "1000032",
            "maxPriorityFeePerGas": "1000000"
          }
        ],
      }
    }
  ```
</CodeGroup>

2. Use `serializeTx` to [sign and send](/docs/signing-transaction-eth) the signed transaction to the Ethereum network.

<Warning>
  **Time Sensitive Transaction**

  You must sign and broadcast this transaction within **8192 slots (approx. 27 hours)** of generation. If this window expires, the transaction will be rejected by the network and you must generate a new one, [contact](/docs/contacts) us for support.
</Warning>

By broadcasting this transaction, you are verifying the validator withdrawal credentials on-chain. You can proceed to delegate your restake amount to an EigenLayer node operator.

## 6. Delegate restake to operator

Once withdrawal credentials are verified, you can delegate your ETH restaking power to a Node Operator.

### 6.1 Get list of operators

Retrieve the list of available EigenLayer node operators by sending a GET request to [/api/v1/eth/staking/eigenlayer/operator](/reference/eth-eigen-operator-list).

<CodeGroup>
  ```bash curl theme={null}
  curl --request GET \
       --url https://api.p2p.org/api/v1/eth/staking/eigenlayer/operator \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/eigenlayer/operator", {
    headers: {
      "authorization": "Bearer <token>",
    },
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.p2p.org/api/v1/eth/staking/eigenlayer/operator",
      headers={
          "authorization": "Bearer <token>",
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	req, _ := http.NewRequest("GET", "https://api.p2p.org/api/v1/eth/staking/eigenlayer/operator", nil)
  	req.Header.Set("authorization", "Bearer <token>")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

Example response:

<CodeGroup>
  ```json theme={null}
  {
        "error": null,
        "result": {
            "list": [
                {
                    "id": "6df58880-c4c9-484a-8fc4-7f7668fe9522",
                    "name": "P2P",
                    "address": "0xdbed88d83176316fc46797b43adee927dc2ff2f5",
                }
            ],
          "limit": 10,
          "offset": 0,
          "totalCount": 1
        }
    }
  ```
</CodeGroup>

* `list`:

  * `id` — UUID that was specified in the node set-up request.
  * `name` — name of provider.
  * `address` — EigenLayer node operator address.

* `limit` — number of resources that a single response page contains.

* `offset` — number of resources to exclude from a response.

* `totalCount` — total number of validators relevant to the current request, based on filters applied.

### 6.2 Prepare delegation transaction

Create a serialized transaction for delegating the restaked amount to the node operator by sending a POST request to [/api/v1/eth/staking/eigenlayer/tx/delegate-to](/reference/eth-eigen-delegate-to). The Eigen Pod delegated is associated to the signer of the request.

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/delegate-to \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>' \
       --header 'content-type: application/json' \
       --data '
  {
    "operatorAddress": "0xdbed88d83176316fc46797b43adee927dc2ff2f5"
  }
  '
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/delegate-to", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
    body: JSON.stringify({
        "operatorAddress": "0xdbed88d83176316fc46797b43adee927dc2ff2f5"
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/delegate-to",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
      json={
              "operatorAddress": "0xdbed88d83176316fc46797b43adee927dc2ff2f5"
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"operatorAddress": "0xdbed88d83176316fc46797b43adee927dc2ff2f5",
  	}
  	body, _ := json.Marshal(payload)
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/eth/staking/eigenlayer/tx/delegate-to", bytes.NewBuffer(body))
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `operatorAddress` — address of the EigenLayer node operator retrieved from the previous step, to delegate the restaked assets.

Example response:

<CodeGroup>
  ```json theme={null}
  {
        "error": null,
        "result": {
            "serializeTx": "0x02f8ef8242688084030825768486442318830186a094a44151489861fe9e3055d95adc98fbd462b948e780b8c4eea9064b00000000000000000000000037d5077434723d0ec21d894a52567cbe6fb2c3d800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0",
            "to": "0xA44151489861Fe9e3055d95adC98FbD462B948e7",
            "gasLimit": "0.0000000000001",
            "data": "0xeea9064b00000000000000000000000037d5077434723d0ec21d894a52567cbe6fb2c3d800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "value": "0.0",
            "chainId": 17000,
            "type": 2,
            "maxFeePerGas": "0.0000000000034557",
            "maxPriorityFeePerGas": "1000000"
        }
    }
  ```
</CodeGroup>

Use `serializeTx` from the previous step to [sign and send](/docs/signing-transaction-eth) the signed transaction to the Ethereum network.

By broadcasting this transaction, you are delegating your restake to the EigenLayer node operator.


## Related topics

- [Withdrawal](/docs/withdrawal-restaking.md)
- [Restaking API reference](/reference/eth-eigen-create-pod.md)
