@lidofinance/lido-ethereum-sdk
v4.0.1
Published
<div style="display: flex;" align="center"> <h1 align="center">Lido Ethereum SDK</h1> </div>
Downloads
1,207
Readme
Lido Ethereum SDK is a package that provides convenient tools for interacting with Lido contracts on the Ethereum network through a software development kit (SDK). This SDK simplifies working with Lido contracts and accessing their functionality.
⚒️ Work In Progress ⚒️
The project is currently under active development and may experience breaking changes in the future.
Changelog
For changes between versions see CHANGELOG.MD
Migration
For breaking changes between versions see MIGRATION.md
Table of contents
- Installation
- Modules
- Usage
- Basic Examples
- Error Codes
- Lido contract addresses
- Stake
- Wrap
- Withdraw
- (w)stETH
- unstETH NFT
- Shares
- Lido statistics
- Lido events
- Rewards
Installation
You can install the Lido Ethereum SDK using npm or yarn:
yarn:
yarn add @lidofinance/lido-ethereum-sdk
npm:
npm install @lidofinance/lido-ethereum-sdk
Modules
The Lido Ethereum SDK consists of several modules:
- Core - provides access to the SDK core functionality
- Stake - provides access to the Lido staking functionality
- Withdraw - provides access to the Lido withdrawals functionality
- Wrap - provides access to the Lido wrap functionality
- (w)stETH - provides access to the stETH and wstETH tokens functionality
- unstETH NFT - provides access to the unstETH NFT functionality
- Shares - provides access to the underlying share token
- Statistics - provides access to the Lido stats, mainly APR
- Rewards - provides access to historical data on stETH rewards
Usage
Import
To get started with the Lido Ethereum SDK, you need to import the necessary modules. You can use CJS or ES6+ imports. Import from root package or each module separately to improve on bundle size.
// CSJ
const { LidoSDK } = require('@lidofinance/lido-ethereum-sdk');
// or
const { LidoSDKStake } = require('@lidofinance/lido-ethereum-sdk/stake');
// or
// ES6+, all other modules are available from root
import { LidoSDK, LidoSDKStake } from '@lidofinance/lido-ethereum-sdk';
// Full list of separate imports
import { LidoSDKCore } from '@lidofinance/lido-ethereum-sdk/core';
import { LidoSDKStake } from '@lidofinance/lido-ethereum-sdk/stake';
import { LidoSDKWithdraw } from '@lidofinance/lido-ethereum-sdk/withdraw';
import { LidoSDKWrap } from '@lidofinance/lido-ethereum-sdk/wrap';
import {
LidoSDKstETH,
LidoSDKwstETH,
} from '@lidofinance/lido-ethereum-sdk/erc20';
import { LidoSDKUnstETH } from '@lidofinance/lido-ethereum-sdk/unsteth';
import { LidoSDKShares } from '@lidofinance/lido-ethereum-sdk/shares';
import { LidoSDKStatistics } from '@lidofinance/lido-ethereum-sdk/statistics';
import { LidoSDKRewards } from '@lidofinance/lido-ethereum-sdk/rewards';
Initialization
Before using the SDK, you need to create an instance of the LidoSDK class:
Pass your own viem PublicClient:
import { LidoSDK } from '@lidofinance/lido-ethereum-sdk';
import { createPublicClient, http } from 'viem';
import { goerli } from 'viem/chains';
const rpcProvider = createPublicClient({
chain: goerli,
transport: http(),
});
const sdk = new LidoSDK({
chainId: 5,
rpcProvider,
web3Provider: provider, // optional
});
Or just rpc urls so it can be created under the hood:
const sdk = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
web3Provider: provider, // optional
});
Replace "https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}" with the address of your Ethereum provider.
With web3Provider
In order to access transaction signing functionality you need to provide viem WalletClient instance. Accessing web3 methods without web3Provider will result in error.
We support account hoisting as per Viem WalletClient
, so passing account is not required for transactions and related functions.
Some functions don't usually require web3provider to be present like simulate...
or populate..
but not passing an account to them will result in request to web3provider and an error if it is missing.
import { LidoSDK, LidoSDKCore } from '@lidofinance/lido-ethereum-sdk';
import { createWalletClient, custom } from 'viem';
import { goerli } from 'viem/chains';
let web3Provider = createWalletClient({
chain: goerli,
transport: custom(window.ethereum),
});
// or use our helper to pass any eip-1193 provider
let web3Provider = LidoSDKCore.createWeb3Provider(5, window.ethereum);
const sdk = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
web3Provider,
});
Separate modules
Every SDK module needs LidoSDKCore
to function. You can pass same arguments as to LidoSDKCore
constructor to create it under the hood or pass existing instance. This allows you to build up your SDK only out of parts you need.
import { LidoSDKStake } from '@lidofinance/lido-ethereum-sdk/stake';
import { LidoSDKWrap } from '@lidofinance/lido-ethereum-sdk/stake';
import { LidoSDKCore } from '@lidofinance/lido-ethereum-sdk/core';
const params = {
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
};
// core is created under the hood
const stake = new LidoSDKStake(params);
const core = new LidoSDKCore(params);
const wrap = new LidoSDKWrap({ core });
Basic Examples
Core example
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
});
// Views
const balanceETH = await lidoSDK.core.balanceETH(address);
console.log(balanceETH.toString(), 'ETH balance');
Stake example
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
web3provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
// Contracts
const addressStETH = await lidoSDK.stake.contractAddressStETH();
const contractStETH = await lidoSDK.stake.getContractStETH();
// Calls
const stakeTx = await lidoSDK.stake.stakeEth({
value,
callback,
referralAddress,
});
console.log(addressStETH, 'stETH contract address');
console.log(contractStETH, 'stETH contract');
console.log(stakeTx, 'stake tx result');
Withdraw example
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
web3provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
// Contracts
const addressWithdrawalQueue =
await lidoSDK.withdraw.contract.contractAddressWithdrawalQueue();
const contractWithdrawalQueue =
await lidoSDK.withdraw.contract.getContractWithdrawalQueue();
// Calls
const requestTx = await lidoSDK.withdraw.request.requestWithdrawalWithPermit({
amount: 10000000n, // `10000000` string is accepted as well
token: 'stETH',
// account will be requested from provider
});
console.log(addressWithdrawalQueue, 'Withdrawal Queue contract address');
console.log(contractWithdrawalQueue, 'Withdrawal Queue contract');
console.log(requestTx.result.requests, 'array of created requests');
Wrap example
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
web3provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
// Contracts
const addressWstETH = await lidoSDK.wrap.contractAddressWstETH();
const contractWstETH = await lidoSDK.withdraw.getContractWstETH();
// Calls
const wrapTx = await lidoSDK.wrap.wrapEth({
value,
account,
});
const { stethWrapped, wstethReceived } = wrapTx.result;
console.log(addressWstETH, 'wstETH contract address');
console.log(contractWstETH, 'wstETH contract');
console.log({ stethWrapped, wstethReceived }, 'wrap result');
Error Codes
- INVALID_ARGUMENT: arguments passed to SDK method are not valid
- NOT_SUPPORTED: behavior or feature though possible is not currently supported by SDK
- PROVIDER_ERROR: error with RPC or Web3 Provider
- READ_ERROR: error while accessing Blockchain or External Resource for read
- UNKNOWN_ERROR error was not recognized by SDK and is not directly thrown by it's code
Lido contract addresses
import { LidoSDK, LIDO_CONTRACT_NAMES } from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
});
const stethAddress = await lidoSDK.core.getContractAddress(
LIDO_CONTRACT_NAMES.lido,
);
const wsteth = await lidoSDK.core.getContractAddress(
LIDO_CONTRACT_NAMES.wsteth,
);
Stake
Call
Arguments:
value
: string | bigint - amount of ETH to stake (in wei)callback
: StageCallback - callback function that will be on each stage of the transactionreferralAddress
: string - referral address (optional)
Callback stages:
sign
- waiting for the user to sign the transactionreceipt
= waiting for the transaction to be included in the blockconfirmation
- transaction is confirmed by the networkdone
- transaction is successfulmultisig_done
- transaction with multisig is successfulerror
- transaction is failed
import {
LidoSDK,
LidoSDKCore,
StakeStageCallback,
TransactionCallbackStage,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const callback: StakeStageCallback = ({ stage, payload }) => {
switch (stage) {
case TransactionCallbackStage.SIGN:
console.log('wait for sign');
break;
case TransactionCallbackStage.RECEIPT:
console.log('wait for receipt');
console.log(payload, 'transaction hash');
break;
case TransactionCallbackStage.CONFIRMATION:
console.log('wait for confirmation');
console.log(payload, 'transaction receipt');
break;
case TransactionCallbackStage.DONE:
console.log('done');
console.log(payload, 'transaction confirmations');
break;
case TransactionCallbackStage.ERROR:
console.log('error');
console.log(payload, 'error object with code and message');
break;
default:
}
};
try {
const stakeTx = await lidoSDK.stake.stakeEth({
value,
callback,
referralAddress,
account,
});
console.log(
stakeTx,
'transaction hash, transaction receipt, confirmations, stake result',
stakeTx.result.stethReceived,
stakeTx.result.sharesReceived,
);
} catch (error) {
console.log((error as SDKError).errorMessage, (error as SDKError).code);
}
Populate transaction
import { LidoSDK } from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
});
const populateResult = await lidoSDK.stake.stakeEthPopulateTx({
value,
callback,
referralAddress,
account,
});
console.log(populateResult, 'to, from, value, data');
Simulate transaction
import { LidoSDK } from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
});
const simulateResult = await lidoSDK.staking.stakeEthSimulateTx({
value,
callback,
referralAddress,
account,
});
Wrap
Calls
Wrap ETH
Arguments:
value
: string | bigint - amount of ETH to wrap to wstETH (staking ETH and then wrapping stETH to wstETH in a single tx)callback
: StageCallback - callback function that will be on each stage of the transaction
import {
LidoSDK,
TransactionCallback,
TransactionCallbackStage,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const callback: TransactionCallback = ({ stage, payload }) => {
switch (stage) {
case TransactionCallbackStage.SIGN:
console.log('wait for sign');
break;
case TransactionCallbackStage.RECEIPT:
console.log('wait for receipt');
console.log(payload, 'transaction hash');
break;
case TransactionCallbackStage.CONFIRMATION:
console.log('wait for confirmation');
console.log(payload, 'transaction receipt');
break;
case TransactionCallbackStage.DONE:
console.log('done');
console.log(payload, 'transaction confirmations');
break;
case TransactionCallbackStage.ERROR:
console.log('error');
console.log(payload, 'error object with code and message');
break;
default:
}
};
try {
const wrapTx = await lidoSDK.staking.wrapETH({
value,
callback,
account,
});
console.log(
wrapTx,
'transaction hash, transaction receipt, confirmations, wrap result',
wrapTx.result.stethWrapped,
wrapTx.result.wstethReceived,
);
} catch (error) {
console.log((error as SDKError).errorMessage, (error as SDKError).code);
}
Wrap stETH
To wrap stETH you first need to approve stETH to wrap contract:
import {
LidoSDK,
TransactionCallback,
TransactionCallbackStage,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
// get existing allowance
const allowance = await lidoSDK.wrap.getStethForWrapAllowance(account);
// if value is more than allowance perform approve
const approveResult = await lidoSDK.wrap.approveStethForWrap({
value,
callback,
});
// wrap stETH
const wrapResult = await lidoSDK.wrap.wrapSteth({ value, callback });
Unwrap
// unwrap wstETH to receive stETH
const unwrapTx = await lidoSDK.wrap.unwrap({
value: unwrapAmount,
callback,
});
console.log(unwrapTx.result.stethReceived, unwrapTx.result.wstethUnwrapped);
Wrap utilities
For all transaction methods helper methods are available similar to stake
module:
...populateTX
: returns ready to sign transaction object with all data encoded...simulateTX
: performs dry-ran of the transaction to see if it will execute on the network
For wrapEth
only wrapEthEstimateGas
is available instead of simulateTx
but you can use it all the same for checking transaction validity.
Withdraw
Call
Send request withdrawal with Permit
Signing Permit is only supported for EOA
Arguments:
requests
: (Type: bigint[] ) - array of requests ids oramount
: (Type: String | BigInt ) - amount of token to withdraw, will be split into minimum amount of requeststoken
: (Type: 'stETH' | 'wstETH') - token namepermit
: (Type: SignedPermit optional) - presigned permit, will be requested if not presentcallback
: (Type: TransactionCallback optional) - callback function that will be on each stage of the transactionaccount
(Type: Address | Account optional): The account address.
import {
LidoSDK,
TransactionCallback,
TransactionCallbackStage,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const callback: TransactionCallback = ({ stage, payload }) => {
switch (stage) {
case TransactionCallbackStage.PERMIT:
console.log('wait for permit');
break;
case TransactionCallbackStage.GAS_LIMIT:
console.log('wait for gas limit');
break;
case TransactionCallbackStage.SIGN:
console.log('wait for sign');
break;
case TransactionCallbackStage.RECEIPT:
console.log('wait for receipt');
console.log(payload, 'transaction hash');
break;
case TransactionCallbackStage.CONFIRMATION:
console.log('wait for confirmation');
console.log(payload, 'transaction receipt');
break;
case TransactionCallbackStage.DONE:
console.log('done');
console.log(payload, 'transaction confirmations');
break;
case TransactionCallbackStage.MULTISIG_DONE:
console.log('multisig_done');
console.log(payload, 'transaction confirmations');
break;
case TransactionCallbackStage.ERROR:
console.log('error');
console.log(payload, 'error object with code and message');
break;
default:
}
};
try {
const requestTx = await lidoSDK.withdrawals.request.requestWithPermit({
requests,
token, // 'stETH' | 'wstETH'
callback,
account,
});
console.log(
'transaction hash, transaction receipt, confirmations',
requestResult,
'array of requests(nfts) created with ids, amounts,creator, owner',
request.results.requests,
);
} catch (error) {
console.log((error as SDKError).errorMessage, (error as SDKError).code);
}
Send request withdrawal with preallocated allowance
Supports EOA and Multisig
Arguments:
requests
: (Type: bigint[] ) - array of requests ids oramount
: (Type: String | BigInt ) - amount of token to withdraw, will be split into minimum amount of requeststoken
: (Type: string) - token name ('stETH' | 'wstETH')callback
: (Type: TransactionCallback optional) - callback function that will be on each stage of the transactionaccount
(Type: Address | Account optional): The account address.
import {
LidoSDK,
TransactionCallback,
TransactionCallbackStage,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const callback: TransactionCallback = ({ stage, payload }) => {
switch (stage) {
case TransactionCallbackStage.GAS_LIMIT:
console.log('wait for gas limit');
break;
case TransactionCallbackStage.SIGN:
console.log('wait for sign');
break;
case TransactionCallbackStage.RECEIPT:
console.log('wait for receipt');
console.log(payload, 'transaction hash');
break;
case TransactionCallbackStage.CONFIRMATION:
console.log('wait for confirmation');
console.log(payload, 'transaction receipt');
break;
case TransactionCallbackStage.DONE:
console.log('done');
console.log(payload, 'transaction confirmations');
break;
case TransactionCallbackStage.ERROR:
console.log('error');
console.log(payload, 'error object with code and message');
break;
default:
}
};
try {
const requestResult = await lidoSDK.withdrawals.request.requestWithdrawal({
amount,
token, // 'stETH' | 'wstETH'
callback,
});
console.log(
requestResult,
'transaction hash, transaction receipt, confirmations',
);
} catch (error) {
console.log((error as SDKError).errorMessage, (error as SDKError).code);
}
Request
helpers
populate
andsimulate
helpers are availablesplitAmountToRequests({amount, token})
splits token amount into minimal possible array of withdrawal requests
Claim requests
Arguments:
requestsIds
: (Type: bigint[]): An array of request ids.hints
(Type: bigint[] optional): An array of hints per each request, will be calculated if not provided.account
: (Type: Address optional): The account address.callback
: (Type: TransactionCallback optional): callback function that will be on each stage of the transaction
import {
LidoSDK,
TransactionCallback,
TransactionCallbackStage,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const callback: TransactionCallback = ({ stage, payload }) => {
switch (stage) {
case TransactionCallbackStage.GAS_LIMIT:
console.log('wait for gas limit');
break;
case TransactionCallbackStage.SIGN:
console.log('wait for sign');
break;
case TransactionCallbackStage.RECEIPT:
console.log('wait for receipt');
console.log(payload, 'transaction hash');
break;
case TransactionCallbackStage.CONFIRMATION:
console.log('wait for confirmation');
console.log(payload, 'transaction receipt');
break;
case TransactionCallbackStage.DONE:
console.log('done');
console.log(payload, 'transaction confirmations');
break;
case TransactionCallbackStage.ERROR:
console.log('error');
console.log(payload, 'error object with code and message');
break;
default:
}
};
try {
const claimTx = await lidoSDK.withdrawals.claim.claimRequests({
requestsIds,
callback,
});
console.log(
claimTx,
'transaction hash, transaction receipt, confirmations',
claim.result.requests,
'array of claimed requests, with amounts of ETH claimed',
);
} catch (error) {
console.log((error as SDKError).errorMessage, (error as SDKError).code);
}
Claim
helpers
populate
and simulate
helpers are available
Withdraw utilities
Set allowance of WithdrawalQueue contract
Supports EOA and Multisig
import {
LidoSDK,
ApproveCallbackStages,
ApproveStageCallback,
SDKError,
} from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const callback: ApproveStageCallback = ({ stage, payload }) => {
switch (stage) {
case ApproveCallbackStages.GAS_LIMIT:
console.log('wait for gas limit');
break;
case ApproveCallbackStages.SIGN:
console.log('wait for sign');
break;
case ApproveCallbackStages.RECEIPT:
console.log('wait for receipt');
console.log(payload, 'transaction hash');
break;
case ApproveCallbackStages.CONFIRMATION:
console.log('wait for confirmation');
console.log(payload, 'transaction receipt');
break;
case ApproveCallbackStages.DONE:
console.log('done');
console.log(payload, 'transaction confirmations');
break;
case ApproveCallbackStages.ERROR:
console.log('error');
console.log(payload, 'error object with code and message');
break;
default:
}
};
try {
const approveResult = await lidoSDK.withdrawals.approval.approve({
amount,
token, // 'stETH' | 'wstETH'
callback,
account,
});
console.log(
approveResult,
'transaction hash, transaction receipt, confirmations',
);
} catch (error) {
console.log((error as SDKError).errorMessage, (error as SDKError).code);
}
Allowance
other methods
Views
populate
andsimulate
helpers are availablegetAllowance
returns current allowance for tokencheckAllowance
return current allowance and compares with amount to check if you need to approve
Views
- getWithdrawalRequestsIds
- getLastCheckpointIndex
- getWithdrawalStatus
- findCheckpointHints
- getClaimableEther
- getUnfinalizedStETH
Constants
- minStethWithdrawalAmount
- maxStethWithdrawalAmount
- minWStethWithdrawalAmount
- maxWStethWithdrawalAmount
- isPaused
- isBunkerModeActive
- isTurboModeActive
Requests info
getWithdrawalRequestsInfo
Input Parameters:
props: { account: Address | Account }
account
(Type: Address | Account): The account address.
Output Parameters:
Type: Object
Structure:
claimableInfo
(Type: Object): Information about withdrawal requests that can be claimed.claimableRequests
(Type: Array[RequestStatusWithId]): A list of requests with their statuses and identifiers.claimableAmountStETH
(Type: bigint): The amount of ETH available for claiming.
pendingInfo
(Type: Object): Information about pending withdrawal requests.pendingRequests
(Type: Array[RequestStatusWithId]): A list of requests with their statuses and identifiers.pendingAmountStETH
(Type: bigint): The amount of ETH pending for withdrawal.
claimableETH
(Type: bigint): The amount of ETH available for claiming.
getWithdrawalRequestsStatus
Input Parameters:
props: { account: Address }
account
(Type: Address | Account): The account address.
Output Parameters:
Type: Array of RequestStatusWithId objects
Structure of each object:
id
(Type: bigint): The request identifier.isFinalized
(Type: boolean): A flag indicating whether the request has been finalized.isClaimed
(Type: boolean): A flag indicating whether the request has already been claimed.amountOfStETH
(Type: bigint): The amount of stETH to be withdrawn.amountOfShares
(Type: bigint): The amount of shares to be burned.owner
(Type: Address): The account address that initiated the request.timestamp
(Type: bigint): The timestamp of the request.stringId
(Type: string): The request identifier in string format.
getClaimableRequestsInfo
Input Parameters:
props: { account: Address }
account
(Type: Address | Account): The account address.
Output Parameters:
Type: Object
Structure:
claimableRequests
(Type: Array[RequestStatusWithId]): A list of requests that can be claimed.claimableAmountStETH
(Type: bigint): The amount of ETH available for claiming.
getClaimableRequestsETHByIds
Input Parameters:
props: { claimableRequestsIds: (bigint | RequestStatusWithId)[] }
claimableRequestsIds
(Type: Array): An array of request identifiers for which information is needed.
Output Parameters:
Type: Object
Structure:
ethByRequests
(Type: Array of bigint): A list of ETH amounts for each request.ethSum
(Type: bigint): The sum of all ETH amounts in the list.hints
(Type: Array of bigint): A list of hints for each request.
getClaimableRequestsETHByAccount
Input Parameters:
props: { account: Address }
account
(Type: Address | Account): The account address.
Output Parameters:
Type: Object
Structure:
ethByRequests
(Type: Array of bigint): A list of ETH amounts for each request.ethSum
(Type: bigint): The sum of all ETH amounts in the list.hints
(Type: Array of bigint): A list of hints for each request.requests
(Type: Array of RequestStatusWithId): A list of requests with their statuses and identifiers.sortedIds
(Type: Array of bigint): A list of request identifiers sorted by id.
getPendingRequestsInfo
Input Parameters:
props: { account: Address | Account }
account
(Type: Address | Account): The account address.
Output Parameters:
Type: Object
Structure:
pendingRequests
(Type: Array[RequestStatusWithId]): A list of requests pending finalization.pendingAmountStETH
(Type: bigint): The amount of ETH pending claiming.
Waiting time
Methods
Get time by amount
getWithdrawalWaitingTimeByAmount
Input Parameters:
props: { amount?: bigint }
amount?
(Type: bigint optional): The amount of withdrawable eth. In case when it is not passed, it is calculated as default information about queue.
Output Parameters:
- Type: Object
- Structure:
requestInfo
(Type: Object): Information about withdrawal requestfinalizationIn
(Type: number): The time needed for withdrawal in milliseconds.finalizationAt
(Type: string): The time when request finalized for withdrawal.type
(Type: WaitingTimeCalculationType): Type of final source of eth for withdrawal.
status
(Type: WaitingTimeStatus): Status of withdrawal request.nextCalculationAt
(Type: string): Time when next calculation can be changed.
Get time by request ids
getWithdrawalWaitingTimeByRequestIds
Input Parameters:
props: { ids: bigint[] }
ids
(ids: Array[bigint]): The ids of withdrawal requests.
Output Parameters:
- Type: Array of WithdrawalWaitingTimeRequestInfo objects
- Structure of each object:
requestInfo
(Type: RequestByIdInfoDto): Information about withdrawal request.finalizationIn
(Type: number): The time needed for withdrawal in milliseconds.finalizationAt
(Type: string): The time when request finalized for withdrawal.requestId
(Type: string): The request id.requestedAt
(Type: string): The time when withdrawal requested.type
(Type: WaitingTimeCalculationType): Type of final source of eth for withdrawal.
status
(Type: WaitingTimeStatus): Status of withdrawal request.nextCalculationAt
(Type: string): Time when next calculation can be changed.
(w)stETH
stETH and wstETH tokens functionality is presented trough modules with same ERC20 interface that exposes balances, allowances, transfers and ERC2612 permits signing.
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
// Views
const balanceStETH = await lidoSDK.steth.balance(address);
const balanceWStETH = await lidoSDK.wsteth.balance(address);
// Contracts
const contractStETH = await lidoSDK.steth.getContract();
const addressStETH = await lidoSDK.steth.contractAddress();
const contractWStETH = await lidoSDK.wsteth.getContract();
const addressWStETH = await lidoSDK.wsteth.contractAddress();
// Calls
const transfer = await lidoSDK.steth.transfer({
amount,
to,
});
Transfer
const transferTx = await lidoSDK.steth.transfer({
amount,
to,
from, // pass from to call transferFrom method
account,
callback,
});
Allowance
const approveTx = await lidoSDK.steth.approve({
amount,
to,
account,
callback,
});
const allowance = await lidoSDK.steth.allowance({ to, account });
// bigint representing how much stETH is `to` address allowed to spend from `account` address
console.log(allowance);
Permit
// initiate permit signing for stETH
const permit = await lidoSDK.steth.signPermit({
amount,
spender,
account,
deadline, // optional, leave empty for infinite deadline
});
Token Metadata
Other helpful functions are exposed
erc20Metadata
returns token name, symbol, decimals and ERC2612 Domain separator.nonces
returns current permit nonce for accounttotalSupply
returns total supply of the token, for (w)stETH tokens this is a variable that changes over timeerc721Domain
return unhashed ERC2612 domain, used for signing permits
Utility methods
For all transaction methods helper methods are available similar to stake
module:
...populate
: returns ready to sign transaction object with all data encoded...simulate
: performs dry-ran of the transaction to see if it will execute on the network
For permit signing ...populate
helpers requests and fills out all needed data for signTypedData
RPC call
Custom token (experimental)
Both token classes inherit from the same abstract class AbstractLidoSDKErc20
which is exposed from erc20
SDK module.
If you want to use this with other token extend from this abstract class and implementingcontractAddress
method that returns address of the token contract on current chain from this.core
. Consult with source code of this sdk module to get started. Use at your own risk, be aware that this is experimental feature and ABI used may not fit your custom token fully or correctly.
unstETH NFT
This modules exposes NFT functionality of Lido Withdrawal Request NFT.
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
});
// Contracts
const addressUnstETH = await lidoSDK.unsteth.contractAddress();
const contractUnstETH = await lidoSDK.unsteth.getContract();
// views
const nfts = await lidoSDK.unsteth.getNFTsByAccount(account);
const owner = await lidoSDK.unsteth.getAccountByNFT(tokenId);
// Calls
const transfer = await lidoSDK.unsteth.transfer({
id,
to,
from, // optional to call transferFrom
account,
callback,
});
Shares
This module exposes methods of Lido(stETH) contract that allow interaction with underlying shares mechanism with interface similar to ERC20. You can query balance, transfer and convert values between shares and stETH. It's best used for tracking balances and performing operations in values unchanged by rebases.
Example
import { LidoSDK } from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
web3Provider: LidoSDKCore.createWeb3Provider(5, window.ethereum),
});
const balanceShares = await lidoSDK.shares.balance(address);
// transferring shares is equivalent to transferring corresponding amount of stETH
const transferTx = await lidoSDK.shares.transfer({ account, amount, to });
// converting stETH amount to shares trough on-chain call based on actual share rate
const shares = await lidoSDK.convertToShares(1000n);
// reverse
const steth = await lidoSDK.convertToSteth(1000n);
// total supply of shares and ether in protocol
const { totalEther, totalShares } = await lidoSDK.getTotalSupply();
// get current share rate from protocol
const shareRate = await lidoSDK.getShareRate();
Lido statistics
APR
Methods
getLastApr
Output Parameters:
- Type: number
getSmaApr
Input Parameters:
props: { days }
days
(Type: number): The number of days back to return sma apr.
Output Parameters:
- Type: number
Examples
import { LidoSDK } from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
});
const lastApr = await lidoSDK.statistics.apr.getLastApr();
const smaApr = await lidoSDK.statistics.apr.getSmaApr({ days: 7 });
console.log(lastApr, 'last apr');
console.log(smaApr, 'sma apr by 7 days');
Lido events
Rebase
Methods
getLastRebaseEvent
Output Parameters:
- Type: RebaseEvent
getFirstRebaseEvent
Input Parameters:
props: { days, fromBlockNumber }
days
(Type: number): The number of days ago from which to start searching for the first rebase event.fromBlockNumber
(Type: number | undefined): Block number from which to start the search.
Output Parameters:
- Type: RebaseEvent
getRebaseEvents
Input Parameters:
Warning: specifying timestamp/seconds/days will result in binary search for fitting block number which will negatively affect rpc request count and execution time
Sub types:
blockType
object that contains one of possible fields:block
block number(Type: BigInt) or Block Tag(excludingpending
)timestamp
timestamp in seconds(type:BigInt) since epoch time
backType
object that contains one of possible fields:seconds
(Type: BigInt): seconds backdays
(Type: BigInt): days backblocks
(Type: BigInt): block back
Props:
to
(Type: blockType optional) defaults to{block:"latests"}
upper bound for events parsingmaxCount
(Type: number optional) maximum count of events to return, if omitted will return all events in rangestepBlock
: (Type: number optional) defaults to 50000, maximum block range per 1 requestfrom
(Type: blockType) lower bound for events parsing orback
(Type: backType) alternative way to define lower bound relative toto
Output Parameters:
- Type: Array of RebaseEvent objects
getLastRebaseEvents
Input Parameters:
props: { count, stepBlock? }
count
(Type: number): how many last rebase events to returnstepBlock
: (Type: number optional) defaults to 50000, maximum block range per 1 request
Output Parameters:
- Type: Array of RebaseEvent objects
Examples
import { LidoSDK } from '@lidofinance/lido-ethereum-sdk';
const lidoSDK = new LidoSDK({
rpcUrls: ['https://rpc-url'],
chainId: 5,
});
const lastRebaseEvent = await lidoSDK.events.stethEvents.getLastRebaseEvent();
const firstRebaseEvent = await lidoSDK.events.stethEvents.getFirstRebaseEvent({
days: 3,
});
const lastRebaseEventsByCount =
await lidoSDK.events.stethEvents.getLastRebaseEvents({ count: 7 });
const lastRebaseEventsByDays =
await lidoSDK.events.stethEvents.getRebaseEventsByDays({ days: 7 });
console.log(lastRebaseEvent, 'last rebase event');
console.log(firstRebaseEvent, 'first rebase event');
console.log(lastRebaseEventsByCount, 'last rebase events by count');
console.log(lastRebaseEventsByDays, 'last rebase events by days');
Rewards
This module allows you to query historical rewards data for given address via chain events or subgraph.
Common Options
address - (Type: Address) address of an account you want to query rewards for
to (Type:
blockType
) defaults to{block: "latest"}
, upper bound for queryfrom (Type:
blockType
) lower bound for query orback (Type:
backType
) alternative way to define lower bound relative toto
includeZeroRebases [default:
false
] - include rebase events when users had no rewards(because of empty balance)includeOnlyRewards [default:
false
] - include only rebase events
Common Return
type RewardsResult = {
// pre query states
baseBalance: bigint;
baseBalanceShares: bigint;
baseShareRate: number;
// commutative rewards in stETH
totalRewards: bigint;
// computed block numbers
fromBlock: bigint;
toBlock: bigint;
// query result in block/logIndex ascending order
rewards: {
type: 'submit' | 'withdrawal' | 'rebase' | 'transfer_in' | 'transfer_out';
change: bigint; // negative or positive change in stETH
changeShares: bigint; // same in shares
balance: bigint; // post event balance in stETH
balanceShares: bigint; // same in shares
shareRate: number; // apx share rate at a time of event
apr?: number; // apr for rebase events
originalEvent: RewardsChainEvents | RewardsSubgraphEvents ; // original event from chain/subgraph, contains extra info
}[]
};
Get Rewards from chain
This method heavily utilizes RPC fetching chain event logs. It's better suited for smaller,recent queries. Beware that this might cause rate limit issues on free RPC endpoints.
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
});
const rewardsQuery = await lidoSDK.rewards.getRewardsFromChain({
address: rewardsAddress,
stepBlock: 10000, // defaults to 50000, max block range per 1 query
back: {
days: 10n,
},
});
console.log(rewardsQuery.rewards);
Get Rewards from subgraph
This method requires you to provide API URL to send subgraph requests to. It's better suited for larger, more historical queries.
Important notes
- to is capped by last indexed block in subgraph. Block number is available in result object by
lastIndexedBlock
. - getSubgraphUrl can also return object of type
{url:string,requestHeaders?: Record<string,string> }
that is passed tographql-request
for extra configurability
const lidoSDK = new LidoSDK({
chainId: 5,
rpcUrls: ['https://eth-goerli.alchemyapi.io/v2/{ALCHEMY_API_KEY}'],
});
const rewardsQuery = await lidoSDK.rewards.getRewardsFromSubgraph({
address: rewardsAddress,
blocksBack: 10000,
stepEntities: 500, // defaults to 1000, max entities per one request to endpoint
getSubgraphUrl(graphId, chainId) {
return `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/${id}`;
},
});
console.log(rewardsQuery.rewards);