@lombard.finance/sdk 3.1.0 → 3.2.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.
Files changed (72) hide show
  1. package/README.md +59 -1
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +73 -62
  4. package/dist/index2.cjs +62 -52
  5. package/dist/index2.cjs.map +1 -1
  6. package/dist/index2.js +8680 -12363
  7. package/dist/index2.js.map +1 -1
  8. package/package.json +6 -6
  9. package/src/api-functions/generateDepositBtcAddress/generateDepositBtcAddress.ts +4 -4
  10. package/src/api-functions/getDepositBtcAddress/getDepositBtcAddress.stories.tsx +8 -0
  11. package/src/api-functions/getDepositBtcAddress/getDepositBtcAddress.ts +3 -3
  12. package/src/api-functions/getDepositsByAddress/getDepositsByAddress.ts +7 -7
  13. package/src/api-functions/getUnstakesByAddress/getUnstakesByAddress.ts +5 -5
  14. package/src/api-functions/getUserStakeAndBakeSignature/getUserStakeAndBakeSignature.stories.tsx +8 -0
  15. package/src/bridge/abi/CCIP_BRIDGE_ADAPTER_ABI.json +704 -0
  16. package/src/bridge/abi/OFT_BRIDGE_ADAPTER_ABI.json +912 -0
  17. package/src/bridge/index.ts +11 -0
  18. package/src/bridge/lib/bridge.stories.tsx +89 -0
  19. package/src/bridge/lib/bridge.ts +101 -0
  20. package/src/bridge/lib/ccip-bridge.stories.tsx +90 -0
  21. package/src/bridge/lib/ccip-bridge.ts +163 -0
  22. package/src/bridge/lib/config.ts +338 -0
  23. package/src/bridge/lib/oft-bridge.stories.tsx +89 -0
  24. package/src/bridge/lib/oft-bridge.ts +212 -0
  25. package/src/common/api-config.ts +8 -2
  26. package/src/common/blockchain-identifier.ts +32 -5
  27. package/src/common/chains.ts +13 -1
  28. package/src/common/contract-info.ts +8 -0
  29. package/src/contract-functions/approveLBTC/approveLBTC.stories.tsx +1 -1
  30. package/src/contract-functions/approveLBTC/approveLBTC.ts +3 -2
  31. package/src/contract-functions/claimLBTC/claimLBTC.ts +3 -2
  32. package/src/contract-functions/getBasculeDepositStatus/getBasculeDepositStatus.ts +10 -4
  33. package/src/contract-functions/getLBTCMintingFee/getLBTCMintingFee.tsx +14 -11
  34. package/src/contract-functions/getLBTCTotalSupply/getLBTCTotalSupply.ts +13 -9
  35. package/src/contract-functions/getPermitNonce/getPermitNonce.ts +16 -10
  36. package/src/contract-functions/getShareValue/getShareValue.stories.tsx +1 -1
  37. package/src/contract-functions/getShareValue/getShareValue.ts +1 -1
  38. package/src/contract-functions/getSharesByAddress/getSharesByAddress.stories.tsx +1 -1
  39. package/src/contract-functions/getSharesByAddress/getSharesByAddress.ts +1 -1
  40. package/src/contract-functions/getStakeAndBakeFee/getStakeAndBakeFee.stories.tsx +14 -1
  41. package/src/contract-functions/getStakeAndBakeFee/getStakeAndBakeFee.tsx +5 -1
  42. package/src/contract-functions/signNetworkFee/signNetworkFee.ts +3 -2
  43. package/src/contract-functions/signStakeAndBake/signStakeAndBake.stories.tsx +2 -1
  44. package/src/contract-functions/signStakeAndBake/signStakeAndBake.ts +8 -3
  45. package/src/contract-functions/unstakeLBTC/unstakeLBTC.ts +3 -2
  46. package/src/index.ts +26 -28
  47. package/src/metrics/get-lbtc-stats.stories.tsx +51 -0
  48. package/src/metrics/get-lbtc-stats.ts +38 -0
  49. package/src/tokens/abi/LBTC_ABI.json +1760 -1760
  50. package/src/tokens/abi/LBTC_ABI.ts +1761 -0
  51. package/src/tokens/lbtc-addresses.ts +1 -0
  52. package/src/tokens/token-addresses.ts +32 -0
  53. package/src/tokens/tokens.ts +59 -50
  54. package/src/utils/numbers.ts +3 -0
  55. package/src/vaults/index.ts +35 -176
  56. package/src/vaults/lib/config.ts +196 -0
  57. package/src/vaults/lib/metrics/get-vault-apy.stories.tsx +57 -0
  58. package/src/vaults/lib/metrics/get-vault-apy.ts +132 -0
  59. package/src/vaults/lib/{get-vault-points.stories.tsx → metrics/get-vault-points.stories.tsx} +8 -8
  60. package/src/vaults/lib/{get-vault-points.ts → metrics/get-vault-points.ts} +1 -1
  61. package/src/vaults/lib/metrics/get-vault-tvl.stories.tsx +57 -0
  62. package/src/vaults/lib/metrics/get-vault-tvl.ts +119 -0
  63. package/src/vaults/lib/{cancel-withdraw.stories.tsx → ops/cancel-withdraw.stories.tsx} +9 -9
  64. package/src/vaults/lib/{deposit.stories.tsx → ops/deposit.stories.tsx} +9 -9
  65. package/src/vaults/lib/{deposit.ts → ops/deposit.ts} +10 -10
  66. package/src/vaults/lib/{get-vault-deposits.stories.tsx → ops/get-vault-deposits.stories.tsx} +9 -9
  67. package/src/vaults/lib/{get-vault-deposits.ts → ops/get-vault-deposits.ts} +5 -5
  68. package/src/vaults/lib/{get-vault-withdrawals.stories.tsx → ops/get-vault-withdrawals.stories.tsx} +9 -9
  69. package/src/vaults/lib/{get-vault-withdrawals.ts → ops/get-vault-withdrawals.ts} +5 -5
  70. package/src/vaults/lib/{withdraw.stories.tsx → ops/withdraw.stories.tsx} +9 -9
  71. package/src/vaults/lib/{withdraw.ts → ops/withdraw.ts} +12 -12
  72. package/src/tokens/lbtc-contract.ts +0 -89
@@ -0,0 +1,11 @@
1
+ /** Generic bridge func */
2
+ export { bridge, type BridgeParameters } from './lib/bridge';
3
+
4
+ /** CCIP bridge func */
5
+ export { bridgeCCIP, type BridgeCCIPParameters } from './lib/ccip-bridge';
6
+
7
+ /** OFT bridge func */
8
+ export { bridgeOFT, type BridgeOFTParameters } from './lib/oft-bridge';
9
+
10
+ /** Utils */
11
+ export { getBridgeInfo } from './lib/config';
@@ -0,0 +1,89 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Button } from '../../stories/components/Button';
3
+ import { CodeBlock } from '../../stories/components/CodeBlock';
4
+ import {
5
+ canPerformAction,
6
+ useConnection,
7
+ } from '../../stories/hooks/useConnection';
8
+ import useQuery from '../../stories/hooks/useQuery';
9
+ import { ConnectButton } from '../../stories/components/ConnectButton';
10
+ import {
11
+ functionType,
12
+ wagmiDecorator,
13
+ } from '../../stories/components/decorators';
14
+ import { ErrorBlock } from '../../stories/components/error-block';
15
+ import { ChainId } from '../../common/chains';
16
+ import { BRIDGE_CHAINS, OFT_BRIDGE_CHAINS } from './config';
17
+ import { bridge, BridgeParameters } from './bridge';
18
+
19
+ const meta = {
20
+ title: 'bridge/bridge',
21
+ component: StoryView,
22
+ tags: ['autodocs'],
23
+ decorators: [wagmiDecorator, functionType('write')],
24
+ } satisfies Meta<typeof StoryView>;
25
+
26
+ export default meta;
27
+
28
+ type Story = StoryObj<typeof meta>;
29
+
30
+ export const WithParams: Story = {
31
+ args: {
32
+ to: ChainId.sonic,
33
+ amount: '0.0001',
34
+ approve: true,
35
+ env: 'prod',
36
+ },
37
+ argTypes: {
38
+ to: {
39
+ mapping: ChainId,
40
+ options: BRIDGE_CHAINS.map(
41
+ ch => Object.entries(ChainId).find(([k, v]) => v === ch)?.[0],
42
+ ),
43
+ control: { type: 'select' },
44
+ },
45
+ },
46
+ };
47
+
48
+ type Props = Omit<BridgeParameters, 'account' | 'chainId' | 'provider'>;
49
+
50
+ export function StoryView(props: Props) {
51
+ const connection = useConnection();
52
+
53
+ const request = async () => {
54
+ if (!canPerformAction(connection)) {
55
+ return;
56
+ }
57
+
58
+ return bridge({
59
+ ...props,
60
+
61
+ account: connection.account.address,
62
+ chainId: connection.account.chainId,
63
+ provider: connection.provider,
64
+ });
65
+ };
66
+
67
+ const { data, error, isLoading, refetch } = useQuery(request, [], false);
68
+
69
+ return (
70
+ <>
71
+ <p>This method bridges funds between chains.</p>
72
+
73
+ <div className="mb-4">
74
+ <ConnectButton />
75
+ </div>
76
+
77
+ <Button
78
+ onClick={refetch}
79
+ disabled={isLoading || !canPerformAction(connection)}
80
+ isLoading={isLoading}
81
+ actionName={bridge.name}
82
+ />
83
+
84
+ <ErrorBlock>{error}</ErrorBlock>
85
+
86
+ <CodeBlock text={data} />
87
+ </>
88
+ );
89
+ }
@@ -0,0 +1,101 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { bridgeCCIP } from './ccip-bridge';
3
+ import {
4
+ BRIDGE_CHAINS,
5
+ BRIDGE_EXPLORER_URL_MAP,
6
+ BridgeChain,
7
+ BridgeType,
8
+ CCIPBridgeChain,
9
+ getBridgeInfo,
10
+ OFTBridgeChain,
11
+ } from './config';
12
+ import { bridgeOFT } from './oft-bridge';
13
+ import { Address } from 'viem';
14
+ import { CommonWriteParameters } from '../../common/parameters';
15
+
16
+ export type BridgeParameters = {
17
+ /** The destination chain id. */
18
+ to: BridgeChain;
19
+ /** The LBTC amount. */
20
+ amount: BigNumber.Value;
21
+ /**
22
+ * A flag determining whether the amount should be approved within
23
+ * the execution of this function. If set to `false` it will
24
+ * throw an error when the deposit amount exceeds allowance.
25
+ */
26
+ approve?: boolean;
27
+ /** The destination address. If omitted the same as the account address. */
28
+ recipient?: Address;
29
+ } & CommonWriteParameters;
30
+
31
+ /**
32
+ * Bridges funds (`amount`) from the connected chain (`chainId`) to the provided
33
+ * destination chain (`to`)
34
+ */
35
+ export async function bridge({
36
+ to,
37
+ amount,
38
+ approve,
39
+ account,
40
+ chainId,
41
+ provider,
42
+ recipient,
43
+ rpcUrl,
44
+ env,
45
+ }: BridgeParameters) {
46
+ const bridgeInfo = getBridgeInfo(chainId as BridgeChain, to);
47
+
48
+ if (!bridgeInfo) {
49
+ throw new Error(
50
+ `Unsupported bridge from ${chainId} to ${to}. Please switch to the supported chains: ${BRIDGE_CHAINS.join(', ')}`,
51
+ );
52
+ }
53
+
54
+ switch (bridgeInfo.type) {
55
+ case BridgeType.CCIP: {
56
+ const txHash = await bridgeCCIP({
57
+ to: to as CCIPBridgeChain,
58
+ amount,
59
+ approve,
60
+ recipient,
61
+ account,
62
+ chainId,
63
+ provider,
64
+ env,
65
+ rpcUrl,
66
+ });
67
+
68
+ return {
69
+ txHash,
70
+ explorerUrl: BRIDGE_EXPLORER_URL_MAP[BridgeType.CCIP].replace(
71
+ '{txHash}',
72
+ txHash,
73
+ ),
74
+ type: BridgeType.CCIP,
75
+ };
76
+ }
77
+
78
+ case BridgeType.OFT: {
79
+ const txHash = await bridgeOFT({
80
+ to: to as OFTBridgeChain,
81
+ amount,
82
+ approve,
83
+ recipient,
84
+ account,
85
+ chainId,
86
+ provider,
87
+ env,
88
+ rpcUrl,
89
+ });
90
+
91
+ return {
92
+ txHash,
93
+ explorerUrl: BRIDGE_EXPLORER_URL_MAP[BridgeType.OFT].replace(
94
+ '{txHash}',
95
+ txHash,
96
+ ),
97
+ type: BridgeType.OFT,
98
+ };
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,90 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Button } from '../../stories/components/Button';
3
+ import { CodeBlock } from '../../stories/components/CodeBlock';
4
+ import {
5
+ canPerformAction,
6
+ useConnection,
7
+ } from '../../stories/hooks/useConnection';
8
+ import useQuery from '../../stories/hooks/useQuery';
9
+ import { ConnectButton } from '../../stories/components/ConnectButton';
10
+ import {
11
+ functionType,
12
+ wagmiDecorator,
13
+ } from '../../stories/components/decorators';
14
+ import { ErrorBlock } from '../../stories/components/error-block';
15
+ import { bridgeCCIP, BridgeCCIPParameters } from './ccip-bridge';
16
+ import { ChainId } from '../../common/chains';
17
+ import { CCIP_BRIDGE_CHAINS } from './config';
18
+
19
+ const meta = {
20
+ title: 'bridge/bridgeCCIP',
21
+ component: StoryView,
22
+ tags: ['autodocs'],
23
+ decorators: [wagmiDecorator, functionType('write')],
24
+ } satisfies Meta<typeof StoryView>;
25
+
26
+ export default meta;
27
+
28
+ type Story = StoryObj<typeof meta>;
29
+
30
+ export const WithParams: Story = {
31
+ args: {
32
+ to: ChainId.holesky,
33
+ amount: '0.0001',
34
+ approve: true,
35
+ env: 'stage',
36
+ },
37
+ argTypes: {
38
+ to: {
39
+ mapping: ChainId,
40
+ options: CCIP_BRIDGE_CHAINS.map(
41
+ ch => Object.entries(ChainId).find(([k, v]) => v === ch)?.[0],
42
+ ),
43
+ defaultValue: 'holesky',
44
+ control: { type: 'select' },
45
+ },
46
+ },
47
+ };
48
+
49
+ type Props = Omit<BridgeCCIPParameters, 'account' | 'chainId' | 'provider'>;
50
+
51
+ export function StoryView(props: Props) {
52
+ const connection = useConnection();
53
+
54
+ const request = async () => {
55
+ if (!canPerformAction(connection)) {
56
+ return;
57
+ }
58
+
59
+ return bridgeCCIP({
60
+ ...props,
61
+
62
+ account: connection.account.address,
63
+ chainId: connection.account.chainId,
64
+ provider: connection.provider,
65
+ });
66
+ };
67
+
68
+ const { data, error, isLoading, refetch } = useQuery(request, [], false);
69
+
70
+ return (
71
+ <>
72
+ <p>This method bridges funds between chains.</p>
73
+
74
+ <div className="mb-4">
75
+ <ConnectButton />
76
+ </div>
77
+
78
+ <Button
79
+ onClick={refetch}
80
+ disabled={isLoading || !canPerformAction(connection)}
81
+ isLoading={isLoading}
82
+ actionName={bridgeCCIP.name}
83
+ />
84
+
85
+ <ErrorBlock>{error}</ErrorBlock>
86
+
87
+ <CodeBlock text={data} />
88
+ </>
89
+ );
90
+ }
@@ -0,0 +1,163 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { CommonWriteParameters } from '../../common/parameters';
3
+ import {
4
+ BridgeType,
5
+ CCIP_BRIDGE_CHAINS,
6
+ CCIPBridgeChain,
7
+ getBridgeInfo,
8
+ MIN_BRIDGE_AMOUNT,
9
+ } from './config';
10
+ import { makePublicClient } from '../../clients/public-client';
11
+ import { makeWalletClient } from '../../clients/wallet-client';
12
+ import {
13
+ fromBaseDenomination,
14
+ getTokenInfo,
15
+ toBaseDenomination,
16
+ } from '../../tokens/tokens';
17
+ import { getErrorMessage } from '../../utils/err';
18
+ import toBigInt from '../../utils/numbers';
19
+ import { Address, pad, parseEther, toBytes, toHex } from 'viem';
20
+ import { approveLBTC } from '../../contract-functions';
21
+ import { Token } from '../../tokens/token-addresses';
22
+
23
+ export type BridgeCCIPParameters = {
24
+ /** The destination chain id. */
25
+ to: CCIPBridgeChain;
26
+ /** The LBTC amount. */
27
+ amount: BigNumber.Value;
28
+ /**
29
+ * A flag determining whether the amount should be approved within
30
+ * the execution of this function. If set to `false` it will
31
+ * throw an error when the deposit amount exceeds allowance.
32
+ */
33
+ approve?: boolean;
34
+ /** The destination address. If omitted the same as the account address. */
35
+ recipient?: Address;
36
+ } & CommonWriteParameters;
37
+ export async function bridgeCCIP({
38
+ to,
39
+ amount: amountRaw,
40
+ approve,
41
+ recipient: optionalRecipient,
42
+ account,
43
+ chainId: from,
44
+ provider,
45
+ env,
46
+ rpcUrl,
47
+ }: BridgeCCIPParameters) {
48
+ const amount = BigNumber(amountRaw);
49
+ const recipient = optionalRecipient || account;
50
+
51
+ const bridgeInfo = getBridgeInfo(from as CCIPBridgeChain, to);
52
+ if (!bridgeInfo || bridgeInfo.type !== BridgeType.CCIP) {
53
+ throw new Error(
54
+ `Unsupported bridge from ${from} to ${to}. Please switch to the supported chains: ${CCIP_BRIDGE_CHAINS.join(', ')}`,
55
+ );
56
+ }
57
+
58
+ const bridgeContract = bridgeInfo.contract;
59
+
60
+ const lbtcContract = await getTokenInfo(Token.LBTC, from, env, rpcUrl);
61
+ if (!lbtcContract) {
62
+ throw new Error('Could not retrieve LBTC contract info.');
63
+ }
64
+
65
+ const publicClient = makePublicClient({ chainId: from, rpcUrl });
66
+ const walletClient = makeWalletClient({ provider, chainId: from });
67
+
68
+ const amountBase = toBigInt(
69
+ toBaseDenomination(amount, lbtcContract.decimals),
70
+ );
71
+
72
+ if (amount.isLessThan(MIN_BRIDGE_AMOUNT)) {
73
+ throw new Error(
74
+ `The amount is smaller than the minimum amount allowed: ${MIN_BRIDGE_AMOUNT.toFixed()}`,
75
+ );
76
+ }
77
+
78
+ const balanceRaw = await publicClient.readContract({
79
+ address: lbtcContract.address,
80
+ abi: lbtcContract.abi,
81
+ functionName: 'balanceOf',
82
+ args: [account],
83
+ });
84
+ const balance = fromBaseDenomination(
85
+ String(balanceRaw),
86
+ lbtcContract.decimals,
87
+ );
88
+
89
+ // check if amount exceeds balance
90
+ if (amount.isGreaterThan(balance)) {
91
+ throw new Error(
92
+ `The amount exceeds the account's balance. \nAmount: ${amount.toFixed()} \nBalance: ${balance.toFixed()}`,
93
+ );
94
+ }
95
+
96
+ const allowanceRaw = await publicClient.readContract({
97
+ address: lbtcContract.address,
98
+ abi: lbtcContract.abi,
99
+ functionName: 'allowance',
100
+ args: [account, bridgeContract.address],
101
+ });
102
+ const allowance = fromBaseDenomination(
103
+ String(allowanceRaw),
104
+ lbtcContract.decimals,
105
+ );
106
+
107
+ // check if amount exceeds allowance
108
+ if (amount.isGreaterThan(allowance)) {
109
+ const exceededMessage = `The amount exceeds allowance. \nAmount: ${amount.toFixed()} \nAllowance: ${allowance.toFixed()}`;
110
+ if (!approve) {
111
+ throw new Error(exceededMessage);
112
+ }
113
+
114
+ // try to approve new amount
115
+ console.info(exceededMessage);
116
+ try {
117
+ const txHash = await approveLBTC({
118
+ account,
119
+ spender: bridgeContract.address,
120
+ amount,
121
+ chainId: from,
122
+ provider,
123
+ rpcUrl,
124
+ env,
125
+ });
126
+ console.info(`Approve tx hash: ${txHash}`);
127
+ console.info(`Approved ${amountBase} for ${bridgeContract.address}`);
128
+ } catch (err) {
129
+ const msg = getErrorMessage(err);
130
+ throw new Error(
131
+ `Could not approve ${amountBase} for ${bridgeContract.address}. \nReason: ${msg}`,
132
+ );
133
+ }
134
+ }
135
+
136
+ const bridgeArgs = [
137
+ /** toChain - bytes32 */
138
+ toHex(to, { size: 32 }),
139
+ /** toAddress - bytes32 */
140
+ pad(recipient),
141
+ /** amount - uint64 */
142
+ amountBase,
143
+ ];
144
+
145
+ const adapterFee = (await publicClient.readContract({
146
+ abi: bridgeContract.abi,
147
+ address: bridgeContract.address,
148
+ functionName: 'getAdapterFee',
149
+ args: bridgeArgs,
150
+ })) as bigint;
151
+
152
+ const { request } = await publicClient.simulateContract({
153
+ abi: bridgeContract.abi,
154
+ address: bridgeContract.address,
155
+ account,
156
+ functionName: 'deposit',
157
+ args: bridgeArgs,
158
+ value: adapterFee,
159
+ });
160
+
161
+ const txHash = await walletClient.writeContract(request);
162
+ return txHash;
163
+ }