Skip to content

Commit 5506c95

Browse files
authoredMar 26, 2024··
Merge pull request #117 from lidofinance/feature/si-1215-add-wwt
[Feature] SI-1183 add-to-sdk-as-method-by-api

File tree

11 files changed

+303
-3
lines changed

11 files changed

+303
-3
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ console.log(balanceETH.toString(), 'ETH balance');
114114

115115
## Migration
116116

117-
For breaking changes between versions see [MIGRATION.md](MIGRATION.md)
117+
For breaking changes between versions see [MIGRATION.md](packages/sdk/MIGRATION.md)
118118

119119
## Documentation
120120

‎packages/sdk/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
### Added
66

77
- `Sepolia` testnet
8+
- New method `getWithdrawalWaitingTimeByAmount` for fetching withdrawal waiting time for amount of eth
9+
- New method `getWithdrawalWaitingTimeByRequestIds` for fetching withdrawal waiting time for earlier created requests by their ids
810

911
## Playground
1012

1113
- Support for `Sepolia` testnet
14+
- Added blocks with new methods `getWithdrawalWaitingTimeByAmount` and `getWithdrawalWaitingTimeByRequestIds`
1215

1316
# 3.1.0
1417

‎packages/sdk/README.md

+51-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ For breaking changes between versions see [MIGRATION.md](MIGRATION.md)
6666
- [Views](#views)
6767
- [Constants](#constants)
6868
- [Requests info](#requests-info)
69+
- [Waiting time](#waiting-time)
70+
- [Get time by amount](#get-time-by-amount)
71+
- [Get time by request ids](#get-time-by-request-ids)
6972
- [(w)stETH](#wsteth)
7073
- [unstETH NFT](#unsteth-nft)
7174
- [Shares](#shares)
@@ -654,7 +657,7 @@ try {
654657
console.log(
655658
'transaction hash, transaction receipt, confirmations',
656659
requestResult,
657-
'array of requests(nfts) created with ids, amounts,creator, owner'
660+
'array of requests(nfts) created with ids, amounts,creator, owner',
658661
request.results.requests,
659662
);
660663
} catch (error) {
@@ -1010,6 +1013,53 @@ try {
10101013
- `pendingRequests` (Type: Array[RequestStatusWithId]): A list of requests pending finalization.
10111014
- `pendingAmountStETH` (Type: bigint): The amount of ETH pending claiming.
10121015

1016+
### Waiting time
1017+
1018+
#### Methods
1019+
1020+
##### Get time by amount
1021+
1022+
###### `getWithdrawalWaitingTimeByAmount`
1023+
1024+
###### Input Parameters:
1025+
1026+
- `props: { amount?: bigint }`
1027+
- `amount?` (Type: bigint **optional**): The amount of withdrawable eth. In case when it is not passed, it is calculated as default information about queue.
1028+
1029+
##### Output Parameters:
1030+
1031+
- Type: Object
1032+
- Structure:
1033+
- `requestInfo` (Type: Object): Information about withdrawal request
1034+
- `finalizationIn` (Type: number): The time needed for withdrawal in milliseconds.
1035+
- `finalizationAt` (Type: string): The time when request finalized for withdrawal.
1036+
- `type` (Type: WaitingTimeCalculationType): Type of final source of eth for withdrawal.
1037+
- `status` (Type: WaitingTimeStatus): Status of withdrawal request.
1038+
- `nextCalculationAt` (Type: string): Time when next calculation can be changed.
1039+
1040+
##### Get time by request ids
1041+
1042+
###### `getWithdrawalWaitingTimeByRequestIds`
1043+
1044+
###### Input Parameters:
1045+
1046+
- `props: { ids: bigint[] }`
1047+
- `ids` (ids: Array[bigint]): The ids of withdrawal requests.
1048+
1049+
##### Output Parameters:
1050+
1051+
- Type: Array of WithdrawalWaitingTimeRequestInfo objects
1052+
- Structure of each object:
1053+
- `requestInfo` (Type: RequestByIdInfoDto): Information about withdrawal request.
1054+
- `finalizationIn` (Type: number): The time needed for withdrawal in milliseconds.
1055+
- `finalizationAt` (Type: string): The time when request finalized for withdrawal.
1056+
- `requestId` (Type: string): The request id.
1057+
- `requestedAt` (Type: string): The time when withdrawal requested.
1058+
- `type` (Type: WaitingTimeCalculationType): Type of final source of eth for withdrawal.
1059+
- `status` (Type: WaitingTimeStatus): Status of withdrawal request.
1060+
- `nextCalculationAt` (Type: string): Time when next calculation can be changed.
1061+
1062+
10131063
## (w)stETH
10141064

10151065
stETH and wstETH tokens functionality is presented trough modules with same ERC20 interface that exposes balances, allowances, transfers and ERC2612 permits signing.

‎packages/sdk/src/common/constants.ts

+7
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,10 @@ export const VIEM_CHAINS: { [key in CHAINS]: Chain } = {
111111
[CHAINS.Holesky]: holesky,
112112
[CHAINS.Sepolia]: sepolia,
113113
};
114+
115+
export const WQ_API_URLS: { [key in CHAINS]: string | null } = {
116+
[CHAINS.Mainnet]: 'https://wq-api.lido.fi',
117+
[CHAINS.Goerli]: 'https://wq-api.testnet.fi',
118+
[CHAINS.Holesky]: 'https://wq-api-holesky.testnet.fi',
119+
[CHAINS.Sepolia]: null,
120+
};

‎packages/sdk/src/common/decorators/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ConsoleCss: Record<HeadMessage, string> = {
1515
'Events:': 'color: salmon',
1616
'Statistic:': 'color: purple',
1717
'Rewards:': 'color: greenyellow',
18+
'API:': 'color: mediumpurple',
1819
'Init:':
1920
'color: #33F3FF;text-shadow: 0px 0px 0 #899CD5, 1px 1px 0 #8194CD, 2px 2px 0 #788BC4, 3px 3px 0 #6F82BB, 4px 4px 0 #677AB3, 5px 5px 0 #5E71AA, 6px 6px 0 #5568A1, 7px 7px 0 #4C5F98, 8px 8px 0 #445790, 9px 9px 0 #3B4E87, 10px 10px 0 #32457E, 11px 11px 0 #2A3D76, 12px 12px 0 #21346D, 13px 13px 0 #182B64, 14px 14px 0 #0F225B, 15px 15px 0 #071A53, 16px 16px 0 #02114A, 17px 17px 0 #0B0841, 18px 18px 0 #130039, 19px 19px 0 #1C0930, 20px 20px 0 #251227, 21px 21px 20px rgba(0,0,0,1), 21px 21px 1px rgba(0,0,0,0.5), 0px 0px 20px rgba(0,0,0,.2);font-size: 50px;',
2021
};

‎packages/sdk/src/common/decorators/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export type HeadMessage =
1313
| 'Events:'
1414
| 'Statistic:'
1515
| 'Rewards:'
16-
| 'Deprecation:';
16+
| 'Deprecation:'
17+
| 'API:';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { expect, describe, test } from '@jest/globals';
2+
import { useWithdraw } from '../../../tests/utils/fixtures/use-withdraw.js';
3+
import { WithdrawalWaitingTimeByRequestIdsParams } from '../types.js';
4+
5+
describe('withdraw waiting time', () => {
6+
const withdraw = useWithdraw();
7+
const { waitingTime } = withdraw;
8+
9+
test('can get withdrawal waiting time by amount', async () => {
10+
const amount = 110n;
11+
const requestInfos = await waitingTime.getWithdrawalWaitingTimeByAmount({
12+
amount,
13+
});
14+
expect(typeof requestInfos.status).toEqual('string');
15+
});
16+
17+
test('can get withdrawal waiting time by request ids', async () => {
18+
const requestsIds = [1234n, 1235n];
19+
20+
const requestInfos = await waitingTime.getWithdrawalWaitingTimeByRequestIds(
21+
{
22+
ids: requestsIds,
23+
} as WithdrawalWaitingTimeByRequestIdsParams,
24+
);
25+
26+
expect(Array.isArray(requestInfos)).toEqual(true);
27+
expect(requestInfos.length).toEqual(requestsIds.length);
28+
});
29+
});

‎packages/sdk/src/withdraw/bus.ts

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
LidoSDKWithdrawApprove,
88
} from './request/index.js';
99
import { LidoSDKModule } from '../common/class-primitives/sdk-module.js';
10+
import { LidoSDKWithdrawWaitingTime } from './withdraw-waiting-time.js';
1011

1112
export class Bus extends LidoSDKModule {
1213
private version: string | undefined;
@@ -17,6 +18,7 @@ export class Bus extends LidoSDKModule {
1718
private approvalInstance: LidoSDKWithdrawApprove | undefined;
1819
private claimInstance: LidoSDKWithdrawClaim | undefined;
1920
private requestInstance: LidoSDKWithdrawRequest | undefined;
21+
private waitingTimeInstance: LidoSDKWithdrawWaitingTime | undefined;
2022

2123
// Contract
2224

@@ -89,4 +91,16 @@ export class Bus extends LidoSDKModule {
8991
}
9092
return this.requestInstance;
9193
}
94+
95+
// Waiting Time
96+
97+
get waitingTime(): LidoSDKWithdrawWaitingTime {
98+
if (!this.waitingTimeInstance) {
99+
this.waitingTimeInstance = new LidoSDKWithdrawWaitingTime({
100+
bus: this,
101+
version: this.version,
102+
});
103+
}
104+
return this.waitingTimeInstance;
105+
}
92106
}

‎packages/sdk/src/withdraw/types.ts

+60
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Address } from 'viem';
22
import type { Bus } from './bus.js';
33
import type { AccountValue } from '../index.js';
4+
import { CHAINS } from '../index.js';
45

56
export type LidoSDKWithdrawModuleProps = { bus: Bus; version?: string };
67

@@ -51,3 +52,62 @@ export type GetWithdrawalRequestsInfoReturnType = {
5152
pendingInfo: GetPendingRequestsInfoReturnType;
5253
claimableETH: GetClaimableRequestsETHByAccountReturnType;
5354
};
55+
56+
export type WqApiCustomUrlGetter = (
57+
defaultUrl: string | null,
58+
chainId: CHAINS,
59+
) => string;
60+
61+
export type WithdrawalWaitingTimeByAmountParams = {
62+
amount?: bigint;
63+
getCustomApiUrl?: WqApiCustomUrlGetter;
64+
};
65+
66+
export type RequestInfo = {
67+
finalizationIn: number;
68+
finalizationAt: string;
69+
type: WaitingTimeCalculationType;
70+
};
71+
72+
export type WithdrawalWaitingTimeByAmountResponse = {
73+
requestInfo: RequestInfo;
74+
status: WaitingTimeStatus;
75+
nextCalculationAt: string;
76+
};
77+
78+
export type WithdrawalWaitingTimeByRequestIdsParams = {
79+
ids: readonly bigint[];
80+
requestDelay?: number;
81+
getCustomApiUrl?: WqApiCustomUrlGetter;
82+
};
83+
84+
export type RequestByIdInfo = {
85+
finalizationIn: number;
86+
finalizationAt: string;
87+
requestId?: string;
88+
requestedAt?: string;
89+
type: WaitingTimeCalculationType;
90+
};
91+
92+
export type WithdrawalWaitingTimeRequestInfo = {
93+
requestInfo: RequestByIdInfo;
94+
status: WaitingTimeStatus;
95+
nextCalculationAt: string;
96+
};
97+
98+
export enum WaitingTimeStatus {
99+
initializing = 'initializing',
100+
calculating = 'calculating',
101+
finalized = 'finalized',
102+
calculated = 'calculated',
103+
}
104+
105+
export enum WaitingTimeCalculationType {
106+
buffer = 'buffer',
107+
bunker = 'bunker',
108+
vaultsBalance = 'vaultsBalance',
109+
rewardsOnly = 'rewardsOnly',
110+
validatorBalances = 'validatorBalances',
111+
requestTimestampMargin = 'requestTimestampMargin',
112+
exitValidators = 'exitValidators',
113+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { Logger, ErrorHandler } from '../common/decorators/index.js';
2+
3+
import { BusModule } from './bus-module.js';
4+
import type {
5+
WithdrawalWaitingTimeByAmountResponse,
6+
WithdrawalWaitingTimeRequestInfo,
7+
WithdrawalWaitingTimeByAmountParams,
8+
WithdrawalWaitingTimeByRequestIdsParams,
9+
WqApiCustomUrlGetter,
10+
} from './types.js';
11+
import { ERROR_CODE, WQ_API_URLS } from '../common/index.js';
12+
import { formatEther } from 'viem';
13+
14+
const endpoints = {
15+
calculateByAmount: '/v2/request-time/calculate',
16+
calculateByRequestId: '/v2/request-time',
17+
};
18+
19+
export class LidoSDKWithdrawWaitingTime extends BusModule {
20+
// API call integrations
21+
@Logger('API:')
22+
@ErrorHandler()
23+
public async getWithdrawalWaitingTimeByAmount(
24+
props: WithdrawalWaitingTimeByAmountParams,
25+
): Promise<WithdrawalWaitingTimeByAmountResponse> {
26+
const getCustomApiUrl = props?.getCustomApiUrl;
27+
28+
const query = new URLSearchParams();
29+
if (props.amount) {
30+
query.set('amount', formatEther(props.amount));
31+
}
32+
33+
const baseUrl = this.getBaseUrl(getCustomApiUrl);
34+
const url = `${baseUrl}${endpoints.calculateByAmount}?${query.toString()}`;
35+
36+
const response = await fetch(url, {
37+
headers: {
38+
'WQ-Request-Source': 'sdk',
39+
},
40+
});
41+
42+
return response.json();
43+
}
44+
45+
@Logger('API:')
46+
@ErrorHandler()
47+
public async getWithdrawalWaitingTimeByRequestIds(
48+
props: WithdrawalWaitingTimeByRequestIdsParams,
49+
): Promise<readonly WithdrawalWaitingTimeRequestInfo[]> {
50+
const requestDelay = props?.requestDelay ?? 1000;
51+
const getCustomApiUrl = props?.getCustomApiUrl;
52+
53+
if (!Array.isArray(props.ids) || props.ids.length === 0) {
54+
throw this.bus.core.error({
55+
code: ERROR_CODE.INVALID_ARGUMENT,
56+
message: 'expected not empty array ids',
57+
});
58+
}
59+
60+
const idsPages = [];
61+
const pageSize = 20;
62+
const baseUrl = this.getBaseUrl(getCustomApiUrl);
63+
const path = `${baseUrl}${endpoints.calculateByRequestId}`;
64+
65+
for (let i = 0; i < props.ids.length; i += pageSize) {
66+
idsPages.push(props.ids.slice(i, i + pageSize));
67+
}
68+
69+
const result = [];
70+
71+
for (const page of idsPages) {
72+
const query = new URLSearchParams();
73+
query.set('ids', page.toString());
74+
75+
const url = `${path}?${query.toString()}`;
76+
77+
const response = await fetch(url, {
78+
headers: {
79+
'WQ-Request-Source': 'sdk',
80+
},
81+
});
82+
83+
const requests = await response.json();
84+
result.push(...requests);
85+
86+
if (idsPages.length > 1) {
87+
// avoid backend spam
88+
await new Promise((resolve) => setTimeout(resolve, requestDelay));
89+
}
90+
}
91+
92+
return result;
93+
}
94+
95+
getBaseUrl(getCustomApiUrl?: WqApiCustomUrlGetter) {
96+
const defaultUrl = WQ_API_URLS[this.bus.core.chainId];
97+
98+
const baseUrl =
99+
getCustomApiUrl && typeof getCustomApiUrl === 'function'
100+
? getCustomApiUrl(defaultUrl, this.bus.core.chainId)
101+
: defaultUrl;
102+
103+
if (!baseUrl) {
104+
throw this.bus.core.error({
105+
code: ERROR_CODE.INVALID_ARGUMENT,
106+
message: `wq-api URL is not found for chain ${this.bus.core.chainId}, use getCustomApiUrl prop to setup custom URL`,
107+
});
108+
}
109+
110+
return baseUrl;
111+
}
112+
}

‎playground/demo/withdrawals/request.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,29 @@ export const WithdrawalsRequestDemo = () => {
180180
})
181181
}
182182
/>
183+
184+
<Action
185+
title={`Withdrawal Waiting Time By Amount`}
186+
walletAction
187+
action={() =>
188+
withdraw.waitingTime.getWithdrawalWaitingTimeByAmount({
189+
amount,
190+
})
191+
}
192+
/>
193+
194+
<Action
195+
title={`Withdrawal Waiting Time For Account Requests`}
196+
walletAction
197+
action={async () => {
198+
const ids = await withdraw.views.getWithdrawalRequestsIds({
199+
account,
200+
});
201+
return withdraw.waitingTime.getWithdrawalWaitingTimeByRequestIds({
202+
ids,
203+
});
204+
}}
205+
/>
183206
</Accordion>
184207
);
185208
};

0 commit comments

Comments
 (0)
Please sign in to comment.