Recipes
Recipes
Stake ETH From Fireblocks
Creates new validator keys and returns a staking transaction to deposit ETH to those validators. Then the staking transaction gets signed w Fireblocks API.
In this Recipe
- Provision validators
- Submit for Fireblocks signature
- Wait for Fireblocks signature
🔥Open Recipe
JavaScript
async function createValidators() {
const url = '<https://api.figment.io/ethereum/validators>';
const data = {
network: 'hoodi',
validators_count: 1,
withdrawal_address: '0x8C025F5EdaBE788A7f14Db861420aaE12CDf979f',
funding_address: '0x8C025F5EdaBE788A7f14Db861420aaE12CDf979f',
fee_recipient_address: '0x8C025F5EdaBE788A7f14Db861420aaE12CDf979f',
region: 'ca-central-1'
};
try {
const response = await axios.post(url, data, {
headers: {
'accept': 'application/json',
'content-type': 'application/json',
'x-api-key': process.env.FIGMENT_API_KEY
}
});
if (response.data && response.data.meta && response.data.meta.staking_transaction && response.data.meta.staking_transaction.contract_call_data) {
return response.data.meta.staking_transaction.contract_call_data;
} else {
console.log('Contract Call Data not found in the response.');
return null;
}
} catch (error) {
console.error('Error:', error.response ? error.response.data : error);
return null;
}
}
async function signWithFireblocks(contractAddress, contractCallData) {
console.log("Contract Call Data:", contractCallData);
return fireblocksApiClient.createTransaction({
operation: TransactionOperation.CONTRACT_CALL,
assetId: process.env.FIREBLOCKS_ASSET_ID,
source: {
type: PeerType.VAULT_ACCOUNT,
id: "1"
},
destination: {
type: PeerType.ONE_TIME_ADDRESS,
oneTimeAddress: {
address: contractAddress
}
},
note: "Contract Call Transaction",
amount: "32",
extraParameters: {
contractCallData
}
}).then(res => {
console.log(`✔ Submitted to Fireblocks for approval & signature. ID: ${res.id}`);
return res;
}).catch(e => {
console.error(`Fireblocks API Error: ${e.message}`);
});
}
async function waitForTxCompletion(fbTx) {
let tx = fbTx;
while (tx.status !== TransactionStatus.COMPLETED) {
if ([TransactionStatus.BLOCKED, TransactionStatus.FAILED, TransactionStatus.REJECTED, TransactionStatus.CANCELLED].includes(tx.status)) {
throw new Error(`Exiting the operation due to error. Transaction status: ${tx.status}`);
}
console.log("Transaction's status:", (await fireblocksApiClient.getTransactionById(fbTx.id)).status);
await new Promise(resolve => setTimeout(resolve, 4000));
tx = await fireblocksApiClient.getTransactionById(fbTx.id);
}
return (await fireblocksApiClient.getTransactionById(fbTx.id));
}
async function processValidators() {
const contractCallData = await createValidators();
if (contractCallData) {
const fbTx = await signWithFireblocks('0xA627f94a8F94E4713d38F52aC3a6377B0a111d47', contractCallData); // Use the actual contract address
if (fbTx) {
const fbRes = await waitForTxCompletion(fbTx);
console.log(fbRes);
}
}
}
// Execute the combined function
processValidators();