# Exits

* [Via Intent](#via-intent)
  * [How voluntary exiting works ](#how-voluntary-exiting-works)
  * [Request Luganodes to submit exits](#request-luganodes-to-submit-exits)
  * [Generate an exit message](#generate-exit-message)
* [Via Wtihdrawal Address](#via-wtihdrawal-address)
  * [Parital Exit Request](#partial-exit-request)
    * [Sample Request](#sample-request-1)
    * [Types](#types-1)
      * [Parital Exit Response Object](#partial-exit-response-object)

### Via Intent

### How voluntary exiting works

To initiate unstaking, validators are required to perform a `SignedVoluntaryExit` transaction, where the transaction is signed using Luganodes' validator keys.&#x20;

Exiting validators must submit a signed challenge with relevant validator information. Thereafter, the `createAndSignChallenge` function generates the necessary signature for the exit API request, relying on validator indexes (found in the Get Delegation object response) and the withdrawal address.

We have created a script to perform the aforementioned operations with ease.

#### Script to create a Signed Challenge

{% hint style="info" %}
**Note:** `controllerAddress` can be used alternatively to the `withdrawalAddress` in the script below
{% endhint %}

```javascript
// Install ethers package using a package manager (eg. NPM, YARN)
import {
  BaseWallet,
  SigningKey,
  hashMessage,
  hexlify,
  toUtf8Bytes,
} from 'ethers';

const createAndSignChallenge = async (
  validatorIndexes,
  privateKeyOfWithdrawalAdd,
  withdrawalAddress,
) => {
  const wallet = new BaseWallet(new SigningKey(privateKeyOfWithdrawalAdd));

  // challenge that needs to be signed
  const challenge = JSON.stringify(
    {
      intentToExit:
        'I am signing this message and requesting that Luganodes exit the following validators from the network',
      validatorIndexes, // REQUIRED: list of validator indexes
      date: Date.now().toString(), // optional, timestamp this was signed
      address: withdrawalAddress, // REQUIRED: the signing address
    },
    null,
    2,
  );
  const sign = wallet.signMessageSync(hashMessage(challenge));

  console.log('signature: ', sign);

  // packedChallenge
  const packedChallenge = hexlify(
    toUtf8Bytes(
      '\u0019Ethereum Signed Message:\n' +
        challenge.length.toString() +
        challenge,
    ),
  );
  console.log('packed_challenge', packedChallenge);
};

  
await createAndSignChallenge(
    validatorIndexes, //[0, 2]
    privateKeyOfWithdrawalAdd, 
    withdrawalAddress, 
  );
```

## Request Luganodes to submit exits

<mark style="color:green;">`POST`</mark> `/api/exit`

Request Luganodes to exit a set of validators for a given withdrawal address. The list of validators comes from a challenge that must be signed with the withdrawal address. See the above code snippet for constructing the body for this method.

**NOTE:** If the challenge and signature check out, this submits the voluntary exits and will initiate the process for exiting validators. This method does not return the voluntary exits.

#### Headers

| Name                                      | Type   | Description                   |
| ----------------------------------------- | ------ | ----------------------------- |
| api-key<mark style="color:red;">\*</mark> | String | API Key provided by Luganodes |

#### Query Parameters

| Name                                  | Type   | Description                                                            |
| ------------------------------------- | ------ | ---------------------------------------------------------------------- |
| key<mark style="color:red;">\*</mark> | String | The public address of the withdrawal key or the controller key to exit |

#### Request Body

| Name                                        | Type   | Description                                     |
| ------------------------------------------- | ------ | ----------------------------------------------- |
| challenge<mark style="color:red;">\*</mark> | String | The packed challenge formed using above snippet |
| signature<mark style="color:red;">\*</mark> | String | The packed signature formed using above snippet |

{% tabs %}
{% tab title="200: OK Success" %}

```json
{
  "message": "exit request is under processing for these validators",
  "validators": [
    {
      "pubKey": "0xa8b4286511612eccb9f5834f278300fd389d5490d2c53c7674826959a1e2113e8dad87cdc357da16f9461473d82bff73",
      "validatorIndex": 1123,
      "provisionId": "a62c7c43-faf7-4fd8-908e-1791c6d8c257"
    }
  ]
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```json
{
    "success": false,
    "status": 400,
    "message": "validators are already in one of the exit states"
}
```

{% endtab %}
{% endtabs %}

```json
// Example request body

{
    "signature":"0xba56185cea6b6f1bd9fc7bda51656a2136e19958d79718ff13c99cec82d36a9f5280784717a0579c5a7294a3778e7d0a00039b5a51d4e85cae25ebc14130dd691c",
    "challenge":"0x19457468657265756d205369676e6564204d6573736167653a0a3234347b0a202022696e74656e74546f45786974223a20224920616d207369676e696e672074686973206d65737361676520616e642072657175657374696e672074686174205374616b656420657869742074686520666f6c6c6f77696e672076616c696461746f72732066726f6d20746865206e6574776f726b222c0a20202276616c696461746f72496e6465786573223a205b0a20202020300a20205d2c0a20202264617465223a202231363838373137333039383136222c0a20202261646472657373223a2022307861303863364339653364304532384530453945663137634536373839396538453036353031644432220a7d"
}
```

## Generate Exit Message&#x20;

<mark style="color:green;">`POST`</mark> `/api/exit/message`&#x20;

Request Luganodes to generate an exit message for a set of validators for a given withdrawal address. This message can be broadcasted over the network through an RPC call. The list of validators comes from a challenge that must be signed with the withdrawal address.&#x20;

**NOTE:**  This method requires the exit message to be broadcasted through an RPC call. If RPC response is "null", then the exit message has been successfully broadcasted.&#x20;

#### Headers

| Name                                      | Type   | Description                   |
| ----------------------------------------- | ------ | ----------------------------- |
| api-key<mark style="color:red;">\*</mark> | String | API Key provided by Luganodes |

#### Query Parameters

| Name                                  | Type   | Description                                                            |
| ------------------------------------- | ------ | ---------------------------------------------------------------------- |
| key<mark style="color:red;">\*</mark> | String | The public address of the withdrawal key or the controller key to exit |

#### Request Body

| Name                                        | Type   | Description                                     |
| ------------------------------------------- | ------ | ----------------------------------------------- |
| challenge<mark style="color:red;">\*</mark> | String | The packed challenge formed using above snippet |
| signature<mark style="color:red;">\*</mark> | String | The packed signature formed using above snippet |

{% tabs %}
{% tab title="200: OK Success" %}

```json
{
    "message": "Exit message(s) created",
    "result": {
        "validatorIndexes": [
            1792413
        ],
        "exitMessages": [
            {
                "message": {
                    "epoch": 0,
                    "validator_index": 1792413
                },
                "signature": "0x90415852edac40501f8c233149cf2c92d1604124c9cbb9b91b4beac0fac5a0d8376b75f0a3a6b7faede07af0dce1edf705bcdf3f9d1d8a124ca73d089ec777a3c15a033c4c8c13ffd9390da0cb1c511f881f0753e6afc724b922d33a76de2d6b"
            }
        ]
    },
    "page": 1,
    "per_page": 100,
    "total": 1,
    "pages": 1
}
```

{% endtab %}
{% endtabs %}

```json
// Example request body

{
    "signature":"0xba56185cea6b6f1bd9fc7bda51656a2136e19958d79718ff13c99cec82d36a9f5280784717a0579c5a7294a3778e7d0a00039b5a51d4e85cae25ebc14130dd691c",
    "challenge":"0x19457468657265756d205369676e6564204d6573736167653a0a3234347b0a202022696e74656e74546f45786974223a20224920616d207369676e696e672074686973206d65737361676520616e642072657175657374696e672074686174205374616b656420657869742074686520666f6c6c6f77696e672076616c696461746f72732066726f6d20746865206e6574776f726b222c0a20202276616c696461746f72496e6465786573223a205b0a20202020300a20205d2c0a20202264617465223a202231363838373137333039383136222c0a20202261646472657373223a2022307861303863364339653364304532384530453945663137634536373839396538453036353031644432220a7d"
}
```

### Via Withdrawal Address

## Partial Exit Request&#x20;

<mark style="color:green;">`POST`</mark> `/api/exit/partial`&#x20;

Client can call this API to generate an unsigned transaction to perform partial withdrawals. This unsigned transaction needs to be signed by the validator withdrawal address and broadcasted to the network.

#### Headers

| Name                                      | Type   | Description                   |
| ----------------------------------------- | ------ | ----------------------------- |
| api-key<mark style="color:red;">\*</mark> | String | API Key provided by Luganodes |

#### Query Parameters

| Name                                  | Type   | Description                                                            |
| ------------------------------------- | ------ | ---------------------------------------------------------------------- |
| key<mark style="color:red;">\*</mark> | String | The public address of the withdrawal key or the controller key to exit |

#### Request Body

| Name                                               | Type   | Description                     |
| -------------------------------------------------- | ------ | ------------------------------- |
| validatorPubKey<mark style="color:red;">\*</mark>  | String | Public address of validator     |
| amountToWithdraw<mark style="color:red;">\*</mark> | Number | Amount of stake to be withdrawn |

{% tabs %}
{% tab title="200: OK Partial Exit Response" %}

```json

    "message": "Partial exit transaction created",
    "result": {
        "validatorPubKey": "0x8e44dac3019bc8128a86b16c5e7012a4dc763718dc9a31e3b2df6c18bb72b7cf5a08cabd03fea42c9f1aa9d2f234c1f8",
        "amountToWithdraw": "1",
        "withdrawalAddress": "0x8C24B68141552e0844354B0b638031918CAAFaeB",
        "unsignedTx": "0x02f85083088bb0368403b0be13848360bf63830186a08001b8388e44dac3019bc8128a86b16c5e7012a4dc763718dc9a31e3b2df6c18bb72b7cf5a08cabd03fea42c9f1aa9d2f234c1f8000000003b9aca00c0",
        "partialExitRequestTrx": {
            "data": "0x8e44dac3019bc8128a86b16c5e7012a4dc763718dc9a31e3b2df6c18bb72b7cf5a08cabd03fea42c9f1aa9d2f234c1f8000000003b9aca00",
            "value": 1,
            "nonce": 54,
            "gasLimit": 100000,
            "maxFeePerGas": "2204155747",
            "maxPriorityFeePerGas": "61914643",
            "type": 2,
            "chainId": "560048"
        }
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Partial exit operations can be performed for one validator at a time. If you want to perform batch operations, you can use our [CLI](/tools/ethereum/pectra-cli.md).
{% endhint %}

```json
// Example request body

{
    "validatorPubKey": "0x8e44dac3019bc8128a86b16c5e7012a4dc763718dc9a31e3b2df6c18bb72b7cf5a08cabd03fea42c9f1aa9d2f234c1f8",
    "amountToWithdraw": "1"
}
```

### Types

### Partial Exit Response Object

<table><thead><tr><th width="216.13020833333331">Property</th><th width="469">Description</th><th>Type</th></tr></thead><tbody><tr><td>message</td><td>Transaction generation status</td><td>String</td></tr><tr><td>result</td><td>Result Object</td><td>Object</td></tr></tbody></table>

### Result Object

<table><thead><tr><th width="216.13020833333331">Property</th><th width="469">Description</th><th>Type</th></tr></thead><tbody><tr><td>validatorPubKey</td><td>Public address of validator</td><td>String</td></tr><tr><td>amountToWithdraw</td><td>Amount of stake to be withdrawn<br><br>NOTE: Amount resulting in the validator's balance below 32 ETH is not allowed.</td><td>Object</td></tr><tr><td>unsignedTx</td><td>Unsigned transaction object which needs to be signed wiith the validator withdrawal address</td><td>String</td></tr><tr><td>withdrawalAddress</td><td>Withdrawal Address of validator</td><td>String</td></tr><tr><td>partialRequestTrx</td><td>Transaction Object</td><td>Object</td></tr></tbody></table>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.luganodes.com/apis/ethereum/exits.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
