Voluntary Exits

To stop staking, validators need to submit a SignedVoluntaryExit transaction. This is signed with the validator keys that Staked holds. Request a voluntary exit and submit it or hold it offline for submission at a later date.

Voluntary exits are only valid for the chain version/fork for which they were created and the following fork, e.g. an exit signed during Altair is only valid to be submitted during Altair and Bellatrix. Staked signs new exits each fork so if you are holding them offline re-request them after a fork.

To exit validators either submit a signed challenge containing the validators to exit or request the encrypted exits, decrypt them on your end, and then submit.

const challenge = JSON.stringify({
    intentToExit: "I am signing this message and requesting that Staked exit the following validators from the network",
    validatorIndexes: [1234, 1235, 1236], // REQUIRED: list of validator indexes
    date: Date.now().toString(), // optional, timestamp this was signed
    address: withdrawal_address, // REQUIRED: the signing address
}, null, 2)
const signature = await web3.eth.personal.sign(challenge, withdrawal_address);
const packed_challenge = web3.utils.toHex('\u0019Ethereum Signed Message:\n' + challenge.length.toString() + challenge);

Staked supports EOA and EIP-1271 compliant signatures when requesting voluntary exits.

Request Staked to submit exits

POST https://mainnet.staked.cloud/api/delegations/eth2/delegator/:key/exit/submit

Request Staked 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. If you need the voluntary exits you must request the encrypted exits.

Query Parameters

NameTypeDescription

key*

String

The withdrawal key to exit

Request Body

NameTypeDescription

signature*

String

The signature by the withdrawal key to

challenge*

String

The packed message to be signed (see above). This specifies which validators to exit.

All exits submitted successfully.

Voluntary exits are encrypted with the validator's withdrawal credential's public key. The public key address must have at least one outgoing transaction to be discoverable for encryption. You also have the option of providing your own ecies pubkey to staked to override this default encryption key. Example of using ecies to create a pubkey is below, please contact our support desk if you need to use this override pubkey.

Exit messages are stored and delivered encrypted so that only the staker can initiate voluntary exits. The voluntary exit for every validator with a shared withdrawal credential public key is encrypted in one batch to reduce the burden of decrypting, however multiple batches may be returned (though n<=5).

import json, base64
from ecies import encrypt, decrypt

# how Staked encrypts
data = base64.b64encode(json.dumps(signed_voluntary_exits_arr).encode())
encrypted_exits = base64.b64encode(encrypt(withdrawal_public_key, data)).decode()

# to decrypt you just invert the process:
decrypted_exits = json.loads(
    base64.b64decode(
        decrypt(
            withdrawal_private_key,
            base64.b64decode(
                encrypted_exits.encode()
            )
        )
    ).decode()
)
# signed_voluntary_exits = [
#     {
#         "message": {
#             "epoch": "1234",
#             "validator_index": "1234"
#         },
#         "signature": "0x1234..."
#     },
#     ... 
# ]
assert(decrypted_exits == encrypted_exits)

# To create new ecies pubkeys to provide as encryption keys:
from ecies.utils import generate_eth_key
eth_k = generate_eth_key()
pubkey_hex = eth_k.public_key.to_hex()
secretkey_hex = eth_k.to_hex()

Request voluntary exits for a type-0x01 withdrawal address

GET https://mainnet.staked.cloud/api/delegations/ETH2/delegator/:withdrawal_address/exit

Returns all SignedVoluntaryExits for validators using the given withdrawal credential.

signed_exits contents are encrypted with the same withdrawal key and will need to be decrypted before submission, but may contain more than one encrypted blob of SignedVoluntaryExits.

NOTE: this does not submit these exits, it just returns the encrypted exits for storage or decryption by the API consumer.

Path Parameters

NameTypeDescription

withdrawal_address*

String

Return exits for the set of validators using this ETH address as the basis for their 0x01 withdrawal credentials

Query Parameters

NameTypeDescription

api_key*

String

Your Staked API key

{
    "withdrawal_key": "0x123...abc",
    "validator_pubkeys": ["1234...", "1235...", "1236...", ...],
    "signed_exits": ["encrypted_exits", ...]
}

Exiting is separate from withdrawing. After successfully submitting an exit, validators will continue to stake until out of the exit queue and completely exited. Once finalized, the withdrawal process will take additional time to return all funds to the withdrawal address.

NOTE: if an exit is submitted before the validator has a type-0x01 ETH withdrawal credential funds will not be returned until a SignedBLSToExecutionChange has been submitted.

Submit voluntary exits for a type-0x01 withdrawal address

PUT https://mainnet.staked.cloud/api/delegations/ETH2/delegator/:withdrawal_address/exit

Submit a list of (decrypted) SignedVoluntaryExits to submit to the beacon chain.

Path Parameters

NameTypeDescription

withdrawal_address*

String

Return exits for the set of validators using this ETH address as the basis for their 0x01 withdrawal credentials

Query Parameters

NameTypeDescription

api_key*

String

Your Staked API key

Request Body

NameTypeDescription

exits*

Array

List of SignedVoluntaryExits to submit

All exits submitted successfully.

Last updated