Skip To Content

Blockdaemon Documentation

Ethereum API Usage Example

In this section you will find a TypeScript example showing how to send an Ethereum transaction using the Ethereum Staking Integration API.

The transaction is signed and sent with the web3.js Ethereum API. For RPC access, Ubiquity Native Access API is used. However, you can choose other tools and methods for these purposes.

In the example we provide, the following steps are taken to send a transaction:

Step 1. A stake intent is created with POST Create a New Stake Intent (V1). The unsigned_transaction field returns a base64 string.

Step 2. The signTransaction() web3.js method is used to sign the transaction. The unsigned_transaction string is passed to the data property of the transaction object to be signed.

Step 3. The sendSignedTransaction() web3.js method is used to send the signed transaction.

Creating a Stake Intent and Sending a Transaction in Ethereum Prater

import Web3 from 'web3';
import { TransactionConfig, TransactionReceipt } from 'web3-core';

const batchDepositContractAddress = {
  prater: '0x6D144323aED2326255e9cE36a429ad737a1ccE37',
};

const gwei = 10n ** 9n;

async function example() {
  const network: 'mainnet' | 'prater' = 'prater';

  const { ethereumSenderAddress, rpcUrl, bossApiKey } =
    getEnvironmentVariables();

  const response = await createStakeIntent(bossApiKey, {
    stakes: [
      {
        amount: '32000000000',
        withdrawal_credentials:
          '0x0000000000000000000000000000000000000000000000000000000000000000',
      },
    ],
  });

  const { unsigned_transaction, stakes } = response.ethereum;
  const totalDepositAmount =
    stakes.reduce((sum, next) => sum + BigInt(next.amount), 0n) * gwei;

  const web3 = new Web3(rpcUrl);

  const txReceipt = await sendTx(web3, {
    from: ethereumSenderAddress,
    to: batchDepositContractAddress[network],
    value: totalDepositAmount.toString(10),
    data: unsigned_transaction,
  });

  console.log(txReceipt);
}

function getEnvironmentVariables() {
  if (!process.env.ETHEREUM_SENDER_ADDRESS) {
    throw new Error('Please set the ETHEREUM_SENDER_ADDRESS env variable.');
  }

  if (!process.env.ETH_RPC_URL && !process.env.UBIQUITY_API_KEY) {
    throw new Error(
      'Please set either ETH_RPC_URL or UBIQUITY_API_KEY env variables.',
    );
  }

  if (!process.env.BOSS_API_KEY) {
    throw new Error('Please set the BOSS_API_KEY env variable.');
  }

  return {
    ethereumSenderAddress: process.env.ETHEREUM_SENDER_ADDRESS,
    rpcUrl:
      process.env.ETH_RPC_URL ??
      getUbiquityNativeWeb3Url(process.env.UBIQUITY_API_KEY!),
    bossApiKey: process.env.BOSS_API_KEY,
  };
}

function getUbiquityNativeWeb3Url(
  apiKey: string,
  network: 'mainnet' | 'prater' = 'prater',
) {
  return `https://svc.blockdaemon.com/ethereum/${network}/native?apiKey=${apiKey}`;
}

export type CreateStakeIntentRequest = {
  stakes: {
    withdrawal_credentials: string;
    amount: string;
  }[];
};

export type CreateStakeIntentResponse = {
  stake_intent_id: string;
  ethereum: {
    stakes: {
      stake_id: string;
      amount: string;
      validator_public_key: string;
      withdrawal_credentials: string;
    }[];
    contract_address: string;
    unsigned_transaction: string;
  };
};

function createStakeIntent(
  bossApiKey: string,
  request: CreateStakeIntentRequest,
): Promise {
  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-API-Key': bossApiKey,
    },
    body: JSON.stringify(request),
  };

  return fetch(
    'https://svc.blockdaemon.com/boss/v1/ethereum/prater/stake-intents',
    requestOptions,
  ).then(response => response.json() as Promise);
}

export async function sendTx(
  web3: Web3,
  txConfig_: Pick<TransactionConfig, 'from' | 'to' | 'data' | 'value'>,
): Promise {
  const txConfig: TransactionConfig = txConfig_;
  txConfig.nonce = await web3.eth.getTransactionCount(txConfig.from as string);
  txConfig.gas = await web3.eth.estimateGas(txConfig);

  const { baseFeePerGas } = await web3.eth.getBlock('latest');
  if (!baseFeePerGas) {
    throw new Error('Could not get block base fee');
  }
  txConfig.maxFeePerGas = (BigInt(baseFeePerGas) + 2n * gwei).toString();

  const signedTx = (await web3.eth.signTransaction(
    txConfig,
  )) as unknown as string;

  return await web3.eth.sendSignedTransaction(signedTx);
}

example()
  .then(() => process.exit(0))
  .catch(err => {
    console.error(err);
    process.exit(1);
  });

Authentication Using API Key as an X-API-Key

When signing up for a staking account, you are provided with an API key.

To authenticate a Staking API request, pass your API key in the X-API-Key header:


curl -X POST \
'https://svc.blockdaemon.com/boss/v1/ethereum/prater/stake-intents' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"stakes": [{"amount": "32000000000", "withdrawal_credentials": "0x0092c20062cee70389f1cb4fa566a2be5e2319ff43965db26dbaa3ce90b9df99", "quantity": 1}]}'

We don't support Internet Explorer

Please use Chrome, Safari, Firefox, or Edge to view this site.