@lombard.finance/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/index.js +12574 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/btcSdk/utils/getOutputScript.ts +54 -0
- package/src/common/const.ts +3 -0
- package/src/common/types/internalTypes.ts +8 -0
- package/src/common/types/types.ts +13 -0
- package/src/common/utils/convertSatoshi.ts +21 -0
- package/src/common/utils/getErrorMessage.ts +35 -0
- package/src/common/utils/isValidChain.ts +5 -0
- package/src/index.ts +5 -0
- package/src/provider/Provider.ts +174 -0
- package/src/provider/ReadProvider.ts +120 -0
- package/src/provider/index.ts +2 -0
- package/src/provider/rpcUrlConfig.ts +8 -0
- package/src/provider/types.ts +58 -0
- package/src/provider/utils/getMaxPriorityFeePerGas.ts +25 -0
- package/src/sdk/apiConfig.ts +20 -0
- package/src/sdk/generateDepositBtcAddress/generateDepositBtcAddress.stories.tsx +52 -0
- package/src/sdk/generateDepositBtcAddress/generateDepositBtcAddress.ts +64 -0
- package/src/sdk/generateDepositBtcAddress/index.ts +1 -0
- package/src/sdk/getDepositBtcAddress/getDepositBtcAddress.stories.tsx +53 -0
- package/src/sdk/getDepositBtcAddress/getDepositBtcAddress.ts +101 -0
- package/src/sdk/getDepositBtcAddress/index.ts +1 -0
- package/src/sdk/getDepositsByAddress/getDepositsByAddress.stories.tsx +49 -0
- package/src/sdk/getDepositsByAddress/getDepositsByAddress.ts +146 -0
- package/src/sdk/getDepositsByAddress/index.ts +1 -0
- package/src/sdk/index.ts +3 -0
- package/src/sdk/internalTypes.ts +5 -0
- package/src/sdk/utils/getCainIdByName.ts +21 -0
- package/src/sdk/utils/getChainNameById.ts +17 -0
- package/src/stories/components/Button/Button.tsx +43 -0
- package/src/stories/components/Button/index.ts +1 -0
- package/src/stories/components/CodeBlock/CodeBlock.tsx +24 -0
- package/src/stories/components/CodeBlock/CodeBlockStyles.css +3 -0
- package/src/stories/components/CodeBlock/index.ts +1 -0
- package/src/stories/components/Spinner/Spinner.tsx +25 -0
- package/src/stories/components/Spinner/index.ts +1 -0
- package/src/stories/const.ts +1 -0
- package/src/stories/hooks/useConnect.ts +47 -0
- package/src/stories/hooks/useQuery.ts +56 -0
- package/src/stories/utils/connectInjectedWallet.ts +12 -0
- package/src/stories/utils/fromCamelCase.ts +16 -0
- package/src/stories/utils/getMetaTitle.ts +7 -0
- package/src/stories/utils/getWalletInfo.ts +31 -0
- package/src/vite-env.d.ts +1 -0
- package/src/web3Sdk/abi/IERC20.json +222 -0
- package/src/web3Sdk/abi/LBTC.json +1400 -0
- package/src/web3Sdk/abi/index.ts +4 -0
- package/src/web3Sdk/approveLBTC/approveLBTC.stories.tsx +77 -0
- package/src/web3Sdk/approveLBTC/approveLBTC.ts +48 -0
- package/src/web3Sdk/approveLBTC/index.ts +1 -0
- package/src/web3Sdk/claimLBTC/claimLBTC.stories.tsx +77 -0
- package/src/web3Sdk/claimLBTC/claimLBTC.ts +62 -0
- package/src/web3Sdk/claimLBTC/index.ts +1 -0
- package/src/web3Sdk/index.ts +4 -0
- package/src/web3Sdk/internalTypes.ts +19 -0
- package/src/web3Sdk/lbtcAddressConfig.ts +16 -0
- package/src/web3Sdk/signLbtcDestionationAddr/index.ts +1 -0
- package/src/web3Sdk/signLbtcDestionationAddr/signLbtcDestionationAddr.stories.tsx +97 -0
- package/src/web3Sdk/signLbtcDestionationAddr/signLbtcDestionationAddr.ts +25 -0
- package/src/web3Sdk/unstakeLBTC/index.ts +1 -0
- package/src/web3Sdk/unstakeLBTC/unstakeLBTC.stories.tsx +77 -0
- package/src/web3Sdk/unstakeLBTC/unstakeLBTC.ts +51 -0
- package/src/web3Sdk/utils/getGasMultiplier.ts +19 -0
- package/src/web3Sdk/utils/getLbtcTokenContract.ts +28 -0
- package/src/web3Sdk/utils/getTokenABI.ts +12 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { IEnvParam } from '../../common/types/internalTypes';
|
|
3
|
+
import { TChainId } from '../../common/types/types';
|
|
4
|
+
import { getApiConfig } from '../apiConfig';
|
|
5
|
+
import { getChainNameById } from '../utils/getChainNameById';
|
|
6
|
+
|
|
7
|
+
const ADDRESS_URL = 'api/v1/address';
|
|
8
|
+
|
|
9
|
+
interface IGenerateNewAddressResponse {
|
|
10
|
+
address: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface IGenerateDepositBtcAddressParams extends IEnvParam {
|
|
14
|
+
/**
|
|
15
|
+
* The destination EVM user address where LBTC will be claimed.
|
|
16
|
+
*/
|
|
17
|
+
address: string;
|
|
18
|
+
/**
|
|
19
|
+
* The destination chain ID where LBTC will be claimed.
|
|
20
|
+
*/
|
|
21
|
+
chainId: TChainId;
|
|
22
|
+
/**
|
|
23
|
+
* The signature of the address. The signature is generated by signing the address using EVM wallet.
|
|
24
|
+
*/
|
|
25
|
+
signature: string;
|
|
26
|
+
/**
|
|
27
|
+
* The referral ID.
|
|
28
|
+
*/
|
|
29
|
+
referralId?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generates a BTC deposit address.
|
|
34
|
+
* @param {IGenerateDepositBtcAddressParams} params - The parameters for generating the deposit address.
|
|
35
|
+
* @returns {Promise<string>} The generated deposit address.
|
|
36
|
+
*/
|
|
37
|
+
export async function generateDepositBtcAddress({
|
|
38
|
+
address,
|
|
39
|
+
chainId,
|
|
40
|
+
signature,
|
|
41
|
+
referralId,
|
|
42
|
+
env,
|
|
43
|
+
}: IGenerateDepositBtcAddressParams): Promise<string> {
|
|
44
|
+
const { depositAddrApiUrl } = getApiConfig(env);
|
|
45
|
+
const toChain = getChainNameById(chainId);
|
|
46
|
+
|
|
47
|
+
const requestParams = {
|
|
48
|
+
to_address: address,
|
|
49
|
+
to_address_signature: signature,
|
|
50
|
+
to_chain: toChain,
|
|
51
|
+
referral_id: referralId,
|
|
52
|
+
nonce: 0,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const { data } = await axios.post<IGenerateNewAddressResponse>(
|
|
56
|
+
ADDRESS_URL,
|
|
57
|
+
requestParams,
|
|
58
|
+
{
|
|
59
|
+
baseURL: depositAddrApiUrl,
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return data.address;
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './generateDepositBtcAddress';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { defaultEnv } from '../../common/const';
|
|
3
|
+
import { OChainId } from '../../common/types/types';
|
|
4
|
+
import { Button } from '../../stories/components/Button';
|
|
5
|
+
import { CodeBlock } from '../../stories/components/CodeBlock';
|
|
6
|
+
import { exampleEvmAddress } from '../../stories/const';
|
|
7
|
+
import useQuery from '../../stories/hooks/useQuery';
|
|
8
|
+
import { fromCamelCase } from '../../stories/utils/fromCamelCase';
|
|
9
|
+
import {
|
|
10
|
+
getDepositBtcAddress,
|
|
11
|
+
IGetDepositBtcAddressParams,
|
|
12
|
+
} from './getDepositBtcAddress';
|
|
13
|
+
|
|
14
|
+
const { name } = getDepositBtcAddress;
|
|
15
|
+
const nameWithWhitespaces = fromCamelCase(name);
|
|
16
|
+
|
|
17
|
+
const meta = {
|
|
18
|
+
title: 'SDK/getDepositBtcAddress',
|
|
19
|
+
component: StoryView,
|
|
20
|
+
tags: ['autodocs'],
|
|
21
|
+
} satisfies Meta<typeof StoryView>;
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof meta>;
|
|
26
|
+
|
|
27
|
+
export const WithParams: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
address: exampleEvmAddress,
|
|
30
|
+
chainId: OChainId.ethereum,
|
|
31
|
+
env: defaultEnv,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export function StoryView(props: IGetDepositBtcAddressParams) {
|
|
36
|
+
const { data, error, isLoading, refetch } = useQuery(
|
|
37
|
+
() => getDepositBtcAddress(props),
|
|
38
|
+
[props],
|
|
39
|
+
false,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const test = true;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<Button onClick={refetch} disabled={isLoading} isLoading={isLoading}>
|
|
47
|
+
{nameWithWhitespaces}
|
|
48
|
+
</Button>
|
|
49
|
+
|
|
50
|
+
<CodeBlock text={error || data} />
|
|
51
|
+
</>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { IEnvParam } from '../../common/types/internalTypes';
|
|
3
|
+
import { TChainId } from '../../common/types/types';
|
|
4
|
+
import { getApiConfig } from '../apiConfig';
|
|
5
|
+
import { TChainName } from '../internalTypes';
|
|
6
|
+
import { getChainNameById } from '../utils/getChainNameById';
|
|
7
|
+
|
|
8
|
+
// todo: implement case when the address is sanctioned
|
|
9
|
+
/**
|
|
10
|
+
* The address wich will be returned if the provided BTC address is sanctioned.
|
|
11
|
+
*
|
|
12
|
+
* @remarks not implemented yet
|
|
13
|
+
*/
|
|
14
|
+
export const SANCTIONED_ADDRESS = 'sanctioned_address';
|
|
15
|
+
|
|
16
|
+
const ADDRESS_URL = 'api/v1/address';
|
|
17
|
+
|
|
18
|
+
interface IDepositAddress {
|
|
19
|
+
btc_address: string;
|
|
20
|
+
created_at: string;
|
|
21
|
+
deprecated?: boolean;
|
|
22
|
+
type: string;
|
|
23
|
+
used?: boolean;
|
|
24
|
+
deposit_metadata: {
|
|
25
|
+
to_address: string;
|
|
26
|
+
to_blockchain: TChainName;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface IDepositAddressesResponse {
|
|
31
|
+
addresses: IDepositAddress[];
|
|
32
|
+
has_more?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface IGetDepositBtcAddressParams extends IEnvParam {
|
|
36
|
+
/**
|
|
37
|
+
* The destination EVM user address where LBTC will be claimed.
|
|
38
|
+
*/
|
|
39
|
+
address: string;
|
|
40
|
+
/**
|
|
41
|
+
* The destination chain ID where LBTC will be claimed.
|
|
42
|
+
*/
|
|
43
|
+
chainId: TChainId;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns the address for depositing BTC.
|
|
48
|
+
*
|
|
49
|
+
* @param {IGetDepositBtcAddressParams} params - function parameters
|
|
50
|
+
*
|
|
51
|
+
* @returns {Promise<string>} the address for depositing BTC
|
|
52
|
+
*/
|
|
53
|
+
export async function getDepositBtcAddress({
|
|
54
|
+
address,
|
|
55
|
+
chainId,
|
|
56
|
+
env,
|
|
57
|
+
}: IGetDepositBtcAddressParams): Promise<string> {
|
|
58
|
+
const toBlockchain = getChainNameById(chainId);
|
|
59
|
+
const addresses = await getDepositBtcAddresses({ address, chainId, env });
|
|
60
|
+
|
|
61
|
+
const addressData = addresses.find(
|
|
62
|
+
addressData => addressData.deposit_metadata.to_blockchain === toBlockchain,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (!addressData) {
|
|
66
|
+
throw new Error('No address');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return addressData.btc_address;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Returns the addresses for depositing BTC.
|
|
74
|
+
*
|
|
75
|
+
* @param {IGetDepositBtcAddressParams} params - function parameters
|
|
76
|
+
*
|
|
77
|
+
* @returns {Promise<IDepositAddress[]>} the deposit addresses
|
|
78
|
+
*/
|
|
79
|
+
export async function getDepositBtcAddresses({
|
|
80
|
+
address,
|
|
81
|
+
chainId,
|
|
82
|
+
env,
|
|
83
|
+
}: IGetDepositBtcAddressParams): Promise<IDepositAddress[]> {
|
|
84
|
+
const { depositAddrApiUrl } = getApiConfig(env);
|
|
85
|
+
const toBlockchain = getChainNameById(chainId);
|
|
86
|
+
|
|
87
|
+
const requestrParams = {
|
|
88
|
+
to_address: address,
|
|
89
|
+
to_blockchain: toBlockchain,
|
|
90
|
+
limit: 1,
|
|
91
|
+
offset: 0,
|
|
92
|
+
asc: false,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const { data } = await axios.get<IDepositAddressesResponse>(ADDRESS_URL, {
|
|
96
|
+
baseURL: depositAddrApiUrl,
|
|
97
|
+
params: requestrParams,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return data?.addresses || [];
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getDepositBtcAddress';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { defaultEnv } from '../../common/const';
|
|
3
|
+
import { Button } from '../../stories/components/Button';
|
|
4
|
+
import { CodeBlock } from '../../stories/components/CodeBlock';
|
|
5
|
+
import { exampleEvmAddress } from '../../stories/const';
|
|
6
|
+
import useQuery from '../../stories/hooks/useQuery';
|
|
7
|
+
import { fromCamelCase } from '../../stories/utils/fromCamelCase';
|
|
8
|
+
import {
|
|
9
|
+
getDepositsByAddress,
|
|
10
|
+
IGetDepositsByAddressParams,
|
|
11
|
+
} from './getDepositsByAddress';
|
|
12
|
+
|
|
13
|
+
const { name } = getDepositsByAddress;
|
|
14
|
+
const nameWithWhitespaces = fromCamelCase(name);
|
|
15
|
+
|
|
16
|
+
const meta = {
|
|
17
|
+
title: 'SDK/getDepositsByAddress',
|
|
18
|
+
component: StoryView,
|
|
19
|
+
tags: ['autodocs'],
|
|
20
|
+
} satisfies Meta<typeof StoryView>;
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
|
|
24
|
+
type Story = StoryObj<typeof meta>;
|
|
25
|
+
|
|
26
|
+
export const WithParams: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
address: exampleEvmAddress,
|
|
29
|
+
env: defaultEnv,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function StoryView(props: IGetDepositsByAddressParams) {
|
|
34
|
+
const { data, error, isLoading, refetch } = useQuery(
|
|
35
|
+
() => getDepositsByAddress(props),
|
|
36
|
+
[props],
|
|
37
|
+
false,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<Button onClick={refetch} disabled={isLoading} isLoading={isLoading}>
|
|
43
|
+
{nameWithWhitespaces}
|
|
44
|
+
</Button>
|
|
45
|
+
|
|
46
|
+
<CodeBlock text={error || data} />
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { IEnvParam } from '../../common/types/internalTypes';
|
|
3
|
+
import { OChainId, TChainId, TEnv } from '../../common/types/types';
|
|
4
|
+
import { fromSatoshi } from '../../common/utils/convertSatoshi';
|
|
5
|
+
import { getApiConfig } from '../apiConfig';
|
|
6
|
+
import { getCainIdByName } from '../utils/getCainIdByName';
|
|
7
|
+
|
|
8
|
+
type Address = string;
|
|
9
|
+
|
|
10
|
+
interface IDepositResponse {
|
|
11
|
+
txid: string;
|
|
12
|
+
index?: number;
|
|
13
|
+
block_height?: string;
|
|
14
|
+
block_time?: string;
|
|
15
|
+
value: number;
|
|
16
|
+
address: Address;
|
|
17
|
+
to_chain: string;
|
|
18
|
+
claim_tx?: string;
|
|
19
|
+
raw_payload: string;
|
|
20
|
+
payload: string;
|
|
21
|
+
signature: string;
|
|
22
|
+
sanctioned?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface IDepositsByAddressResponse {
|
|
26
|
+
outputs: IDepositResponse[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface IDeposit {
|
|
30
|
+
txid: string;
|
|
31
|
+
index?: number;
|
|
32
|
+
blockHeight?: number;
|
|
33
|
+
blockTime?: number;
|
|
34
|
+
value: number;
|
|
35
|
+
address: Address;
|
|
36
|
+
chainId: TChainId;
|
|
37
|
+
isClaimed: boolean;
|
|
38
|
+
rawPayload?: string;
|
|
39
|
+
signature?: string;
|
|
40
|
+
isRestricted?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface IGetDepositsByAddressParams extends IEnvParam {
|
|
44
|
+
/**
|
|
45
|
+
* The EVM address to get deposits for
|
|
46
|
+
*/
|
|
47
|
+
address: Address;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns all deposits for a given address
|
|
52
|
+
*
|
|
53
|
+
* @param {IGetDepositsByAddressParams} params - the parameters for getting deposits
|
|
54
|
+
*
|
|
55
|
+
* @returns {Promise<IDeposit[]>} a list of deposits
|
|
56
|
+
*/
|
|
57
|
+
export async function getDepositsByAddress({
|
|
58
|
+
address,
|
|
59
|
+
env,
|
|
60
|
+
}: IGetDepositsByAddressParams): Promise<IDeposit[]> {
|
|
61
|
+
const { baseApiUrl } = getApiConfig(env);
|
|
62
|
+
const url = `${baseApiUrl}/api/v1/address/outputs/${address}`;
|
|
63
|
+
|
|
64
|
+
const { data } = await axios.get<IDepositsByAddressResponse | undefined>(url);
|
|
65
|
+
|
|
66
|
+
const outputs = data?.outputs ?? [];
|
|
67
|
+
|
|
68
|
+
return outputs.map(mapResponse(env));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function mapResponse(env?: TEnv) {
|
|
72
|
+
return (data: IDepositResponse): IDeposit => ({
|
|
73
|
+
txid: data.txid,
|
|
74
|
+
index: data.index ?? 0,
|
|
75
|
+
blockHeight: data.block_height ? Number(data.block_height) : undefined,
|
|
76
|
+
blockTime: data.block_time ? Number(data.block_time) : undefined,
|
|
77
|
+
value: fromSatoshi(data.value),
|
|
78
|
+
address: data.address,
|
|
79
|
+
chainId: getCainIdByName(data.to_chain, env),
|
|
80
|
+
// todo: return claiming tx from the API when it's available
|
|
81
|
+
isClaimed: !!data.claim_tx,
|
|
82
|
+
rawPayload: data.raw_payload,
|
|
83
|
+
signature: data.signature,
|
|
84
|
+
isRestricted: !!data.sanctioned,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const demoDepositsByAddress: IDeposit[] = [
|
|
89
|
+
{
|
|
90
|
+
txid: 'txid0',
|
|
91
|
+
index: 0,
|
|
92
|
+
blockHeight: 100,
|
|
93
|
+
blockTime: 1715964690,
|
|
94
|
+
value: 0.2,
|
|
95
|
+
address: 'address0',
|
|
96
|
+
chainId: OChainId.holesky,
|
|
97
|
+
isClaimed: false,
|
|
98
|
+
rawPayload: 'rawPayload0',
|
|
99
|
+
signature: 'signature0',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
txid: 'dasjmnkosdfjnkdsgjnk',
|
|
103
|
+
index: 0,
|
|
104
|
+
blockHeight: 110,
|
|
105
|
+
blockTime: 1715964690,
|
|
106
|
+
value: 0.3,
|
|
107
|
+
address: 'adslhjnkbsfdahbk',
|
|
108
|
+
chainId: OChainId.holesky,
|
|
109
|
+
isClaimed: false,
|
|
110
|
+
rawPayload: 'rawPayload0',
|
|
111
|
+
signature: 'signature0',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
txid: '0xfsmkfdskm',
|
|
115
|
+
index: 0,
|
|
116
|
+
blockHeight: 102,
|
|
117
|
+
blockTime: 1715964690,
|
|
118
|
+
value: 0.55,
|
|
119
|
+
address: 'dgfgfasd',
|
|
120
|
+
chainId: OChainId.holesky,
|
|
121
|
+
isClaimed: false,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
txid: 'kmgnjkofejnadwnjdasljmnkjgsdklmn',
|
|
125
|
+
index: 0,
|
|
126
|
+
blockHeight: 102,
|
|
127
|
+
blockTime: 1715964691,
|
|
128
|
+
value: 0.77,
|
|
129
|
+
address: 'hgjhyewadwss',
|
|
130
|
+
chainId: OChainId.holesky,
|
|
131
|
+
isClaimed: false,
|
|
132
|
+
isRestricted: true,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
txid: 'f6b6d0e1e77df21e406bd730c32b05c3fae8296491a1d946925eff07d02d5825',
|
|
136
|
+
index: 1,
|
|
137
|
+
blockHeight: 100,
|
|
138
|
+
blockTime: 1715789138,
|
|
139
|
+
value: 0.2,
|
|
140
|
+
address: 'address1',
|
|
141
|
+
chainId: OChainId.holesky,
|
|
142
|
+
isClaimed: true,
|
|
143
|
+
rawPayload: 'rawPayload1',
|
|
144
|
+
signature: 'signature1',
|
|
145
|
+
},
|
|
146
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getDepositsByAddress';
|
package/src/sdk/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defaultEnv } from '../../common/const';
|
|
2
|
+
import { OChainId, OEnv, TChainId, TEnv } from '../../common/types/types';
|
|
3
|
+
import { TChainName } from '../internalTypes';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param chainId the chain ID
|
|
7
|
+
*
|
|
8
|
+
* @returns the chain name
|
|
9
|
+
*/
|
|
10
|
+
export function getCainIdByName(
|
|
11
|
+
chain: string,
|
|
12
|
+
env: TEnv = defaultEnv,
|
|
13
|
+
): TChainId {
|
|
14
|
+
switch (chain as TChainName) {
|
|
15
|
+
case 'DESTINATION_BLOCKCHAIN_ETHEREUM':
|
|
16
|
+
return env === OEnv.prod ? OChainId.ethereum : OChainId.holesky;
|
|
17
|
+
|
|
18
|
+
default:
|
|
19
|
+
return OChainId.ethereum;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OChainId, TChainId } from '../../common/types/types';
|
|
2
|
+
import { OChainName, TChainName } from '../internalTypes';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param chainId the chain ID
|
|
6
|
+
*
|
|
7
|
+
* @returns the chain name
|
|
8
|
+
*/
|
|
9
|
+
export function getChainNameById(chainId: TChainId): TChainName {
|
|
10
|
+
switch (chainId) {
|
|
11
|
+
case OChainId.holesky:
|
|
12
|
+
case OChainId.ethereum:
|
|
13
|
+
return OChainName.eth;
|
|
14
|
+
default:
|
|
15
|
+
throw new Error(`Unknown chain ID: ${chainId}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Spinner } from '../Spinner';
|
|
3
|
+
|
|
4
|
+
export interface ButtonProps {
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
primary?: boolean;
|
|
8
|
+
size?: 'small' | 'medium' | 'large';
|
|
9
|
+
isLoading?: boolean;
|
|
10
|
+
onClick?: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Primary UI component for user interaction
|
|
15
|
+
*/
|
|
16
|
+
export const Button = ({
|
|
17
|
+
primary = true,
|
|
18
|
+
size = 'medium',
|
|
19
|
+
children,
|
|
20
|
+
isLoading,
|
|
21
|
+
...props
|
|
22
|
+
}: ButtonProps) => {
|
|
23
|
+
const mode = primary
|
|
24
|
+
? 'storybook-button--primary'
|
|
25
|
+
: 'storybook-button--secondary';
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
className={[
|
|
31
|
+
'btn',
|
|
32
|
+
size === 'small' ? 'btn-sm' : '',
|
|
33
|
+
size === 'large' ? 'btn-lg' : '',
|
|
34
|
+
primary ? 'btn-primary' : 'btn-secondary',
|
|
35
|
+
].join(' ')}
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
{children}
|
|
39
|
+
|
|
40
|
+
{isLoading && <Spinner color="text-light" className="ms-2" />}
|
|
41
|
+
</button>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Button';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import './CodeBlockStyles.css';
|
|
2
|
+
|
|
3
|
+
interface ICodeBlockProps {
|
|
4
|
+
text?: any;
|
|
5
|
+
withFormatting?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function CodeBlock({
|
|
9
|
+
text,
|
|
10
|
+
withFormatting = true,
|
|
11
|
+
}: ICodeBlockProps): JSX.Element | null {
|
|
12
|
+
const formattedCode =
|
|
13
|
+
text && withFormatting ? JSON.stringify(text, null, 2) : text;
|
|
14
|
+
|
|
15
|
+
if (!text) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<pre className="card my-3 code-block--max-height">
|
|
21
|
+
<code className="card-body">{formattedCode}</code>
|
|
22
|
+
</pre>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CodeBlock';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface ISpinnerProps {
|
|
2
|
+
color?: 'text-primary' | 'text-light';
|
|
3
|
+
size?: 'sm' | 'md';
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Spinner({
|
|
8
|
+
color = 'text-primary',
|
|
9
|
+
size = 'sm',
|
|
10
|
+
className,
|
|
11
|
+
}: ISpinnerProps): JSX.Element {
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
className={[
|
|
15
|
+
'spinner-border',
|
|
16
|
+
color,
|
|
17
|
+
size === 'sm' ? 'spinner-border-sm' : '',
|
|
18
|
+
className || '',
|
|
19
|
+
].join(' ')}
|
|
20
|
+
role="status"
|
|
21
|
+
>
|
|
22
|
+
<span className="visually-hidden">Loading...</span>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Spinner';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const exampleEvmAddress = '0x659579f1460c38c3ce3288b47b074646cef855fc';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Web3 from 'web3';
|
|
2
|
+
import { TChainId } from '../../common/types/types';
|
|
3
|
+
import { isValidChain } from '../../common/utils/isValidChain';
|
|
4
|
+
import { connectInjectedWallet } from '../utils/connectInjectedWallet';
|
|
5
|
+
import { getWalletInfo } from '../utils/getWalletInfo';
|
|
6
|
+
import useQuery from './useQuery';
|
|
7
|
+
|
|
8
|
+
interface IRequestConnect {
|
|
9
|
+
web3: Web3;
|
|
10
|
+
account: string;
|
|
11
|
+
chainId: TChainId;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface IUseConnect {
|
|
15
|
+
data: IRequestConnect | null;
|
|
16
|
+
error: string | null;
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
connect: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function useConnect(): IUseConnect {
|
|
22
|
+
const {
|
|
23
|
+
data,
|
|
24
|
+
error,
|
|
25
|
+
isLoading,
|
|
26
|
+
refetch: connect,
|
|
27
|
+
} = useQuery(requestConnect, [], false);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
data,
|
|
31
|
+
error,
|
|
32
|
+
isLoading,
|
|
33
|
+
connect,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function requestConnect(): Promise<IRequestConnect> {
|
|
38
|
+
const provider = await connectInjectedWallet();
|
|
39
|
+
const web3 = new Web3(provider);
|
|
40
|
+
const { account, chainId } = await getWalletInfo(web3);
|
|
41
|
+
|
|
42
|
+
if (!isValidChain(chainId)) {
|
|
43
|
+
throw new Error('Invalid chain');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return { web3, account, chainId };
|
|
47
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { getErrorMessage } from '../../common/utils/getErrorMessage';
|
|
3
|
+
|
|
4
|
+
type QueryFn<T> = () => Promise<T>;
|
|
5
|
+
|
|
6
|
+
interface UseQueryResult<T> {
|
|
7
|
+
data: T | null;
|
|
8
|
+
error: string | null;
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
refetch: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Custom hook for making a query and managing the query state.
|
|
15
|
+
*
|
|
16
|
+
* @template T - The type of data returned by the query.
|
|
17
|
+
* @param queryFn The function that performs the query.
|
|
18
|
+
* @param dependencies The dependencies that trigger a re-fetch of the query.
|
|
19
|
+
* @param shouldFetch Determines whether the query should be fetched initially. Defaults to true.
|
|
20
|
+
* @returns The query result object containing the data, error, loading state, and a refetch function.
|
|
21
|
+
*/
|
|
22
|
+
export function useQuery<T>(
|
|
23
|
+
queryFn: QueryFn<T>,
|
|
24
|
+
dependencies: any[] = [],
|
|
25
|
+
shouldFetch = true,
|
|
26
|
+
): UseQueryResult<T> {
|
|
27
|
+
const [data, setData] = useState<T | null>(null);
|
|
28
|
+
const [error, setError] = useState<string | null>(null);
|
|
29
|
+
const [isLoading, setLoading] = useState<boolean>(false);
|
|
30
|
+
|
|
31
|
+
const fetchData = useCallback(async () => {
|
|
32
|
+
setLoading(true);
|
|
33
|
+
setError(null);
|
|
34
|
+
setData(null);
|
|
35
|
+
try {
|
|
36
|
+
const result = await queryFn();
|
|
37
|
+
setData(result);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error(err);
|
|
40
|
+
const errorMsg = getErrorMessage(err);
|
|
41
|
+
setError(errorMsg);
|
|
42
|
+
} finally {
|
|
43
|
+
setLoading(false);
|
|
44
|
+
}
|
|
45
|
+
}, [queryFn, ...dependencies]);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (shouldFetch) {
|
|
49
|
+
fetchData();
|
|
50
|
+
}
|
|
51
|
+
}, [shouldFetch, fetchData, ...dependencies]);
|
|
52
|
+
|
|
53
|
+
return { data, error, isLoading, refetch: fetchData };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default useQuery;
|