Skip to main content

Pre-signed Exit Transactions

Exiting a validator on Ethereum requires submission of a pre-signed exit transaction to the network, which requires a signature by the validator's private key (held only by Figment to reduce slashing risk).

Pre-signed exit transactions provide a safe way to ensure you can exit your Ethereum validators with minimal future dependence on your staking provider.

Figment can provide Pre-signed exit transactions for a validator between 14-16 hours after a deposit transaction has been made.

Once the pre-signed exit transaction is generated, anyone with access can broadcast it to exit the validator, which is why Figment requires an encryption key, so only you have access to them.

Since pre-signed exit transactions expire after two network hard forks, Figment re-generates them daily at 6:30am UTC. It is up to you to decide how often to update them in your system.

Creating a Keypair

Figment currently supports both GPG and RSA keys for encrypting pre-signed exit transactions.

Please contact your Figment Customer Success Representative to provide or update your encryption key(s).

GPG

Figment requires a GPG key size of at least 2048 bits.

  • We recommend using the following command to generate your key: gpg --full-generate-key.
  • To export your public key (which you will provide to Figment): gpg --output public_key.gpg --armor --export colton@figment.io

RSA

  • To generate your private key: openssl genrsa -out private_key.pem 4096
    • Note that we require an RSA key size of 4096 bits
  • To generate the public key (which you will provide to Figment): openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem
    • Note that the public key should be in PKCS8 format, i.e. starting with: ----BEGIN PUBLIC KEY-----

After providing your key to Figment

You can expect your public key to be saved within 24 business hours of providing it to Figment. Once the public key has been saved, an up-to-date version of the encrypted pre-signed exit transaction for all of your active validators will be generated daily at 6:30am UTC.

Retrieving Encrypted Exit Transactions

  1. Once you have completed Figment’s Liability Disclaimer and provided your PGP public key with Figment, you will have easy access to pre-signed validator exit transactions (technically named SignedVoluntaryExit) for all of your active validators. Note that a validator is not eligible for exit until 2^8 epochs (~27.3 hours) have passed since entering the active set.

  2. To retrieve your pre-signed transactions you can use Figment’s Validator API. There are three available endpoints where you’ll be able to retrieve the encrypted exit transaction file from the presigned_exit_transaction field, which resides in each validator’s attributes:

  1. The contents of the file are encrypted using the encryption key you provided to Figment.
  • Below is the format of the file for GPG encrypted exit transactions:
-----BEGIN PGP MESSAGE-----
Version: Date Created (Epoch Created)
Comment: Validator Public Key

wV4DhAgK6qzUbbYSAQdAcGntg7DvCl+4Sjz3sw8MGBfZo/Yv3ih/G3PNrzd2bUsw
jwAX1EqYjC3PB35YCyPuVh0YC5Cp7x7QQvW5js0pSB+kiUTN6/jjmE0o5goreVj5
0sB8AQTVG9R+g2Bs3eXaQSbVk/3ji6klJg9ReccQpkuTmAKI61YZmZ5YXhD20KDU
7wj6PXxcI50ol2Y4OUYSdZr/W2NM42jhMWUEbBl1/T6DjWfRbwd+MDwUwtq790Zy
d8lFBwy9zdYcGAU2EHEq4rvn08v/xdt5EHVUAsHOCTg9jbzw7QbEThL/BCpBt4t0
+umtF3E9EYec3yR651brdTWo3rDLqsU0FW3o2VrrT9emQo7or6NDFSz0Hv70YX+U
Qrq7dxDCUKdHmxQadje5PePaKbLiGaGnN8x81bDSsvKBXXLeTRNyZae5HPmFGNRP
uSXM/Z54VsqBM0CZeoMjrcdHyr26G7Ar/geoKvIAyNwKTGmoVtZz5CfllpKgrPSH
b9X5UsHtPrF4s5pfuK0dcHNQYnxazG4OlRaEhJ3j1g==
=cLUy
-----END PGP MESSAGE-----
  • Below is the format of the file for RSA encrypted exit transactions:
aGV3bl7MuFX5q+gGBBDPkE1PHhZSPJP/ENRuFAptNYU43qQky9XRXbBJlwbL4bjxSfbX3FVlBJIE7eZZsi6iBGcucFBJGIMZ8B9/r9KnGrpGxhLDFZR5Atl4Nm81CgqZQ493CD4S4hAP+5eHxUUfnF/E1pEASk2BeBWslif2k1KY/B7EdQegXRghWwQVPQVkiOu7vhCJOGTj2VE0adybq3fiRvAO4EcZlYHYzeaAHPznq/oI7x3pzhK2dog5X8jtyfC8eloBQOKSn7mR76FJH+0yI2W3PURicqrzR61FRP1hzShxGByi1mf13NnrmdBubrnkJKnjScaIhTtnxky4dhstJz/jPlBf2iBJn+HFcL2H/C/RuI1iNs+G519Sovqv+gIjGEgtwv5FGuIfnHf3ZRCDGVnsvdR0DXVOsXNgtBpG6gjF+DS0Vyv6WXYP1CidNo4bZA3q35SoVznX8gfWQZG9tfvcLiKLCHA9bDFJmuTBUVxB60YuPMuNogO5+30/CBpRkTouXF8I3KJNuJN1ysPfKR9JCgmEJpxeCq4jqkesHGavayvPuMBwfmzboWrJzqq7m+hw7vtHHcb9EdxF8jbWW46k/oJn+ZiFlNO7zl7PETZi1T7SiZuem3o218pshi6ad+jdPj3elCuBN8+32qFFiQuU5KMeVSCIQ8NxtHo=
  1. Below we have provided boilerplate JavaScript code for downloading your pre-signed exit transactions via API
const fs = require("fs");
const os = require("os");

const queryParams = {
presigned_exit_transaction: "true",
status: "active_ongoing",
withdrawal_address: "MY_WITHDRAWAL_ADDRESS",
};

const queryString = Object.keys(queryParams)
.map((key) => key + "=" + queryParams[key])
.join("&");
const directoryName = `${os.homedir}/figment/ethereum/exit-transactions`;
const apikey = "VALIDATOR_API_KEY";

fetch(
`https://hubble.figment.io/api/v1/prime/eth2_staking/validators?${queryString}`,
{
method: "GET",
headers: {
Authorization: `Bearer ${apikey}`,
"Content-Type": "application/json",
},
}
)
.then((resp) => resp.json())
.then((body) => {
for (let i = 0; i < body.data.length; i++) {
if (body.data[i].attributes.presigned_exit_transaction != undefined) {
let presigned_exit_transaction =
body.data[i].attributes.presigned_exit_transaction;
let validator_pubkey = body.data[i].attributes.pubkey;

fs.writeFile(
`${directoryName}/${validator_pubkey}-exit-transaction.enc`,
presigned_exit_transaction,
(err) => {
if (err) console.log(err);
else {
console.log("The file was saved!");
console.log("Content:");
console.log(
fs.readFileSync(
`${directoryName}/${validator_pubkey}-exit-transaction.enc`,
"utf8"
)
);
}
}
);
}
}
})
.catch((err) => console.log("Error: " + err));

Decrypting Encrypted Exit Transactions

note

In the examples below, we pipe the output to jq to format it for readability, however this is not a requirement for decryption.

  1. If you’re using GPG:
gpg -d exit-transaction.enc | jq
  1. If you’re using RSA:
base64 -d < exit-transaction.enc | openssl pkeyutl -decrypt -inkey private_key.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | jq
  1. Expected output:
  • epoch : Epoch when the pre-signed exit transaction was generated by Figment
  • validator_index : Index of the exiting validator
  • signature : BLS signature of message by the validator signing key
{
"message": {
"epoch": "156529",
"validator_index": "356323"
},
"signature": "0xa9bbed5545c6278a8f208c0ce60cf62d4a1b5110c9782b0ed1bdfc11547d036acebcbff23a6d6b312918e0f249474c180e62dfe09db1c7cc0136e6dd8c5fb7cbed73f88a592522cc716b71ac8f72da71d26d4f7825042939d24b35cf326c567c"
}

Broadcasting Exit Transactions

There are three ways you can broadcast your pre-signed exit transactions once you are able to decrypt them.

  1. Using Figment’s Staking API: The Staking API will track the exit transaction for you and deliver updates via webhook as the validator moves through the exit queue and withdrawal process.
  1. Using your own Beacon Node: This solution is best for stakers who want to minimize any dependencies on third parties.
  1. Using the beaconcha.in tool: beaconcha.in has recently released a public tool for broadcasting pre-signed exit transactions.