@lombard.finance/sdk 2.0.12 → 2.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lombard.finance/sdk",
3
- "version": "2.0.12",
3
+ "version": "2.0.15",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/index.js",
@@ -2,10 +2,11 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { OChainId, OEnv } from '../../common/types/types';
3
3
  import { Button } from '../../stories/components/Button';
4
4
  import { CodeBlock } from '../../stories/components/CodeBlock';
5
+ import { useConnect } from '../../stories/hooks/useConnect';
5
6
  import useQuery from '../../stories/hooks/useQuery';
6
7
  import {
7
- IGetUserStakeAndBakeSignatureParams,
8
- getUserStakeAndBakeSignature,
8
+ IGetUserStakeAndBakeSignatureParams,
9
+ getUserStakeAndBakeSignature,
9
10
  } from './getUserStakeAndBakeSignature';
10
11
 
11
12
  const meta = {
@@ -21,25 +22,41 @@ type Story = StoryObj<typeof meta>;
21
22
  export const WithParams: Story = {
22
23
  args: {
23
24
  env: OEnv.stage,
24
- userDestinationAddress: '0x8C6bF4b04363910443cCc8F3B71B267EC3b96241',
25
25
  },
26
26
  };
27
27
 
28
28
  type GetUserStakeAndBakeSignatureProps = Pick<
29
29
  IGetUserStakeAndBakeSignatureParams,
30
- 'env' | 'userDestinationAddress'
30
+ 'env'
31
31
  >;
32
32
 
33
33
  export function StoryView(props: GetUserStakeAndBakeSignatureProps) {
34
+ const {
35
+ data: connectData,
36
+ error: connectError,
37
+ isLoading: isConnectLoading,
38
+ connect,
39
+ } = useConnect();
40
+
34
41
  const request = async () => {
42
+ if (!connectData?.account) {
43
+ return;
44
+ }
45
+
35
46
  return getUserStakeAndBakeSignature({
36
47
  ...props,
48
+ userDestinationAddress: connectData.account,
37
49
  chainId: OChainId.holesky,
38
50
  });
39
51
  };
40
52
 
41
53
  const { data, error, isLoading, refetch } = useQuery(request, [], false);
42
54
 
55
+ const formattedConnectData = connectData && {
56
+ account: connectData.account,
57
+ chainId: connectData.chainId,
58
+ };
59
+
43
60
  return (
44
61
  <>
45
62
  <p>
@@ -47,6 +64,18 @@ export function StoryView(props: GetUserStakeAndBakeSignatureProps) {
47
64
  signature is used to approve spending of tokens.
48
65
  </p>
49
66
 
67
+ <div className="mb-4">
68
+ <Button
69
+ onClick={connect}
70
+ disabled={isConnectLoading}
71
+ isLoading={isConnectLoading}
72
+ >
73
+ Connect
74
+ </Button>
75
+
76
+ <CodeBlock text={connectError || formattedConnectData} />
77
+ </div>
78
+
50
79
  <Button onClick={refetch} disabled={isLoading} isLoading={isLoading}>
51
80
  Get User Stake and Bake Signature
52
81
  </Button>
@@ -54,4 +83,4 @@ export function StoryView(props: GetUserStakeAndBakeSignatureProps) {
54
83
  <CodeBlock text={error || data} />
55
84
  </>
56
85
  );
57
- }
86
+ }
@@ -21,9 +21,17 @@ export interface IGetUserStakeAndBakeSignatureResponse {
21
21
  */
22
22
  signature: string;
23
23
  /**
24
- * The typed data used to generate the signature
24
+ * The expiration date
25
25
  */
26
- typedData: string;
26
+ expirationDate: string;
27
+ /**
28
+ * The deposit amount
29
+ */
30
+ depositAmount: string;
31
+ /**
32
+ * The chain ID
33
+ */
34
+ chainId: string;
27
35
  }
28
36
 
29
37
  /**
@@ -1,13 +1,23 @@
1
- import { FormControl, InputLabel, MenuItem, Select, TextField } from '@mui/material';
1
+ import {
2
+ FormControl,
3
+ InputLabel,
4
+ MenuItem,
5
+ Select,
6
+ TextField,
7
+ } from '@mui/material';
2
8
  import type { Meta } from '@storybook/react';
3
9
  import { useEffect, useState } from 'react';
4
- import { OChainId } from '../../common/types/types';
10
+ import { OChainId, OEnv } from '../../common/types/types';
5
11
  import { Button } from '../../stories/components/Button';
6
12
  import { CodeBlock } from '../../stories/components/CodeBlock';
7
13
  import { useConnect } from '../../stories/hooks/useConnect';
8
14
  import useQuery from '../../stories/hooks/useQuery';
9
- import { VAULT_CONTRACTS } from '../../web3Sdk/signStakeAndBake/contracts';
15
+ import {
16
+ getStakeAndBakeSpenderContract,
17
+ SUPPORTED_STAKE_AND_BAKE_CHAINS,
18
+ } from '../../web3Sdk/signStakeAndBake/contracts';
10
19
  import { signStakeAndBake } from '../../web3Sdk/signStakeAndBake/signStakeAndBake';
20
+ import { storeStakeAndBakeSignature } from './storeStakeAndBakeSignature';
11
21
 
12
22
  const EXPIRY_OPTIONS = {
13
23
  '10 seconds': 10,
@@ -19,8 +29,6 @@ const EXPIRY_OPTIONS = {
19
29
 
20
30
  type ExpiryOption = keyof typeof EXPIRY_OPTIONS;
21
31
 
22
- const AVAILABLE_CHAINS = Object.keys(VAULT_CONTRACTS).map(Number);
23
-
24
32
  const meta = {
25
33
  title: 'SDK/storeStakeAndBakeSignature',
26
34
  component: StoryView,
@@ -33,11 +41,15 @@ export function StoryView() {
33
41
  const [selectedExpiry, setSelectedExpiry] =
34
42
  useState<ExpiryOption>('10 seconds');
35
43
  const [selectedChain, setSelectedChain] = useState(OChainId.holesky);
36
- const [spender, setSpender] = useState(VAULT_CONTRACTS[OChainId.holesky].SPENDER);
37
- const [verifyingContract, setVerifyingContract] = useState(
38
- VAULT_CONTRACTS[OChainId.holesky].VERIFYING_CONTRACT,
44
+
45
+ const [spender, setSpender] = useState(
46
+ getStakeAndBakeSpenderContract(OChainId.holesky),
39
47
  );
40
48
 
49
+ useEffect(() => {
50
+ setSpender(getStakeAndBakeSpenderContract(selectedChain));
51
+ }, [selectedChain]);
52
+
41
53
  const {
42
54
  data: connectData,
43
55
  error: connectError,
@@ -45,12 +57,6 @@ export function StoryView() {
45
57
  connect,
46
58
  } = useConnect();
47
59
 
48
- useEffect(() => {
49
- const contracts = VAULT_CONTRACTS[selectedChain];
50
- setSpender(contracts.SPENDER);
51
- setVerifyingContract(contracts.VERIFYING_CONTRACT);
52
- }, [selectedChain]);
53
-
54
60
  const request = async () => {
55
61
  if (!connectData || !connectData.provider) {
56
62
  return;
@@ -59,20 +65,32 @@ export function StoryView() {
59
65
  const expiry =
60
66
  Math.floor(Date.now() / 1000) + EXPIRY_OPTIONS[selectedExpiry];
61
67
 
62
- return signStakeAndBake({
68
+ // First sign the authorization
69
+ const { signature, typedData } = await signStakeAndBake({
63
70
  provider: connectData.provider,
64
71
  address: connectData.account,
65
72
  chainId: selectedChain,
66
73
  value: '1999',
67
74
  expiry,
68
75
  spender,
69
- verifyingContract,
70
76
  });
77
+
78
+ // Then store it
79
+ await storeStakeAndBakeSignature({
80
+ signature,
81
+ typedData,
82
+ env: OEnv.stage,
83
+ });
84
+
85
+ return {
86
+ signature,
87
+ typedData,
88
+ };
71
89
  };
72
90
 
73
91
  const { data, error, isLoading, refetch } = useQuery(
74
92
  request,
75
- [selectedExpiry, selectedChain, spender, verifyingContract],
93
+ [selectedExpiry, selectedChain],
76
94
  false,
77
95
  );
78
96
 
@@ -84,8 +102,8 @@ export function StoryView() {
84
102
  return (
85
103
  <>
86
104
  <p>
87
- This method stores the stake and bake signature in the backend. The
88
- signature is used to approve spending of tokens.
105
+ This method signs and stores the stake and bake signature in the
106
+ backend. The signature is used to approve spending of tokens.
89
107
  </p>
90
108
 
91
109
  <div className="mb-4">
@@ -111,7 +129,7 @@ export function StoryView() {
111
129
  setSelectedChain(Number(e.target.value) as typeof selectedChain)
112
130
  }
113
131
  >
114
- {AVAILABLE_CHAINS.map(chainId => (
132
+ {SUPPORTED_STAKE_AND_BAKE_CHAINS.map(chainId => (
115
133
  <MenuItem key={chainId} value={chainId}>
116
134
  {chainId} Holesky
117
135
  </MenuItem>
@@ -120,28 +138,6 @@ export function StoryView() {
120
138
  </FormControl>
121
139
  </div>
122
140
 
123
- <div className="mb-4">
124
- <FormControl fullWidth>
125
- <TextField
126
- label="Spender Address"
127
- value={spender}
128
- onChange={e => setSpender(e.target.value)}
129
- helperText="The address that will be authorized to spend tokens"
130
- />
131
- </FormControl>
132
- </div>
133
-
134
- <div className="mb-4">
135
- <FormControl fullWidth>
136
- <TextField
137
- label="Verifying Contract"
138
- value={verifyingContract}
139
- onChange={e => setVerifyingContract(e.target.value)}
140
- helperText="The contract that will verify the signature"
141
- />
142
- </FormControl>
143
- </div>
144
-
145
141
  <div className="mb-4">
146
142
  <FormControl fullWidth>
147
143
  <InputLabel id="expiry-select-label">Expiry Time</InputLabel>
@@ -160,6 +156,17 @@ export function StoryView() {
160
156
  </FormControl>
161
157
  </div>
162
158
 
159
+ <div className="mb-4">
160
+ <FormControl fullWidth>
161
+ <TextField
162
+ label="Spender Address"
163
+ value={spender}
164
+ onChange={e => setSpender(e.target.value)}
165
+ helperText="The address that will be authorized to spend tokens"
166
+ />
167
+ </FormControl>
168
+ </div>
169
+
163
170
  <Button
164
171
  onClick={refetch}
165
172
  disabled={
@@ -167,7 +174,7 @@ export function StoryView() {
167
174
  }
168
175
  isLoading={isLoading}
169
176
  >
170
- Store Stake and Bake Signature
177
+ Sign and Store Stake and Bake Signature
171
178
  </Button>
172
179
 
173
180
  <CodeBlock
@@ -19,27 +19,23 @@ type Story = StoryObj<typeof meta>;
19
19
  export const Holesky: Story = {
20
20
  args: {
21
21
  chainId: OChainId.holesky,
22
- bakeGasEstimate: 77,
23
22
  },
24
23
  };
25
24
 
26
25
  export const Ethereum: Story = {
27
26
  args: {
28
27
  chainId: OChainId.ethereum,
29
- bakeGasEstimate: 77,
30
28
  },
31
29
  };
32
30
 
33
31
  type GetLBTCMintingFeeProps = {
34
32
  chainId: TChainId;
35
- bakeGasEstimate: number;
36
33
  };
37
34
 
38
35
  export function StoryView(props: GetLBTCMintingFeeProps) {
39
36
  const request = async () => {
40
37
  return getLBTCMintingFee({
41
38
  chainId: props.chainId,
42
- bakeGasEstimate: props.bakeGasEstimate,
43
39
  });
44
40
  };
45
41
 
@@ -57,7 +53,6 @@ export function StoryView(props: GetLBTCMintingFeeProps) {
57
53
  <div className="mt-4 p-4 border rounded">
58
54
  <h3 className="text-lg font-bold mb-2">Fee Details</h3>
59
55
  <p>Minting Fee: {data.toString()} BTC</p>
60
- <p>Bake Gas Estimate: {props.bakeGasEstimate}</p>
61
56
  </div>
62
57
  )}
63
58
  </div>
@@ -11,10 +11,6 @@ export interface IGetLBTCMintingFeeParams {
11
11
  * Chain ID
12
12
  */
13
13
  chainId: TChainId;
14
- /**
15
- * Bake gas estimate
16
- */
17
- bakeGasEstimate?: number;
18
14
  /**
19
15
  * RPC URL
20
16
  */
@@ -25,14 +21,12 @@ export interface IGetLBTCMintingFeeParams {
25
21
  * Get LBTC minting fee.
26
22
  *
27
23
  * @param chainId - Chain ID
28
- * @param bakeGasEstimate - Bake gas estimate
29
- * @param rpcUrl - RPC URL
24
+ * @param rpcUrl - RPC URL (optional)
30
25
  *
31
26
  * @returns LBTC minting fee
32
27
  */
33
28
  export async function getLBTCMintingFee({
34
29
  chainId,
35
- bakeGasEstimate = 0,
36
30
  rpcUrl,
37
31
  }: IGetLBTCMintingFeeParams): Promise<BigNumber> {
38
32
  const rpcUrlConfig = getRpcUrlConfigFromChain(chainId, rpcUrl);
@@ -42,10 +36,6 @@ export async function getLBTCMintingFee({
42
36
 
43
37
  const fee: bigint = await tokenContract.methods.getMintFee().call();
44
38
  const feeBtc = new BigNumber(fromSatoshi(fee.toString(10)));
45
- if (bakeGasEstimate) {
46
- const total = feeBtc.plus(fromSatoshi(bakeGasEstimate));
47
- return total;
48
- }
49
39
 
50
40
  return feeBtc;
51
41
  }
@@ -1,8 +1,8 @@
1
1
  import { TChainId } from '../../common/types/types';
2
- import { VAULT_CONTRACTS } from './contracts';
2
+ import { STAKE_AND_BAKE_SPENDER_CONTRACTS } from './contracts';
3
3
 
4
4
  export const getStakeAndBakeSpenderAddress = (chainId: TChainId): string => {
5
- const address = VAULT_CONTRACTS[chainId]?.SPENDER;
5
+ const address = STAKE_AND_BAKE_SPENDER_CONTRACTS[chainId];
6
6
  if (!address) {
7
7
  throw new Error(`No spender address configured for chain ID ${chainId}`);
8
8
  }
@@ -1,13 +1,13 @@
1
- import { OChainId } from '../../common/types/types';
1
+ import { OChainId, TChainId } from '../../common/types/types';
2
2
 
3
- interface IVaultContracts {
4
- SPENDER: string;
5
- VERIFYING_CONTRACT: string;
6
- }
7
-
8
- export const VAULT_CONTRACTS: Record<number, IVaultContracts> = {
9
- [OChainId.holesky]: {
10
- SPENDER: '0x52BD640617eeD47A00dA0da93351092D49208d1d',
11
- VERIFYING_CONTRACT: '0xED7bfd5C1790576105Af4649817f6d35A75CD818',
12
- },
3
+ export const STAKE_AND_BAKE_SPENDER_CONTRACTS: Record<number, string> = {
4
+ [OChainId.holesky]: '0x52BD640617eeD47A00dA0da93351092D49208d1d',
13
5
  } as const;
6
+
7
+ export const SUPPORTED_STAKE_AND_BAKE_CHAINS = Object.keys(
8
+ STAKE_AND_BAKE_SPENDER_CONTRACTS,
9
+ ).map(Number);
10
+
11
+ export const getStakeAndBakeSpenderContract = (chainId: TChainId): string => {
12
+ return STAKE_AND_BAKE_SPENDER_CONTRACTS[chainId];
13
+ };
@@ -1,2 +1,3 @@
1
+ export * from './contracts';
1
2
  export * from './getTypedData';
2
3
  export * from './signStakeAndBake';
@@ -13,7 +13,10 @@ import { CodeBlock } from '../../stories/components/CodeBlock';
13
13
  import { useConnect } from '../../stories/hooks/useConnect';
14
14
  import useQuery from '../../stories/hooks/useQuery';
15
15
  import { fromCamelCase } from '../../stories/utils/fromCamelCase';
16
- import { VAULT_CONTRACTS } from './contracts';
16
+ import {
17
+ getStakeAndBakeSpenderContract,
18
+ SUPPORTED_STAKE_AND_BAKE_CHAINS,
19
+ } from './contracts';
17
20
  import { signStakeAndBake } from './signStakeAndBake';
18
21
 
19
22
  const { name } = signStakeAndBake;
@@ -29,8 +32,6 @@ const EXPIRY_OPTIONS = {
29
32
 
30
33
  type ExpiryOption = keyof typeof EXPIRY_OPTIONS;
31
34
 
32
- const AVAILABLE_CHAINS = Object.keys(VAULT_CONTRACTS).map(Number);
33
-
34
35
  const meta = {
35
36
  title: 'Web3SDK/signStakeAndBake',
36
37
  component: StoryView,
@@ -44,10 +45,7 @@ export function StoryView() {
44
45
  useState<ExpiryOption>('10 seconds');
45
46
  const [selectedChain, setSelectedChain] = useState(OChainId.holesky);
46
47
  const [spender, setSpender] = useState(
47
- VAULT_CONTRACTS[OChainId.holesky].SPENDER,
48
- );
49
- const [verifyingContract, setVerifyingContract] = useState(
50
- VAULT_CONTRACTS[OChainId.holesky].VERIFYING_CONTRACT,
48
+ getStakeAndBakeSpenderContract(OChainId.holesky),
51
49
  );
52
50
 
53
51
  const {
@@ -58,9 +56,7 @@ export function StoryView() {
58
56
  } = useConnect();
59
57
 
60
58
  useEffect(() => {
61
- const contracts = VAULT_CONTRACTS[selectedChain];
62
- setSpender(contracts.SPENDER);
63
- setVerifyingContract(contracts.VERIFYING_CONTRACT);
59
+ setSpender(getStakeAndBakeSpenderContract(selectedChain));
64
60
  }, [selectedChain]);
65
61
 
66
62
  const request = async () => {
@@ -78,13 +74,12 @@ export function StoryView() {
78
74
  value: '1999',
79
75
  expiry,
80
76
  spender,
81
- verifyingContract,
82
77
  });
83
78
  };
84
79
 
85
80
  const { data, error, isLoading, refetch } = useQuery(
86
81
  request,
87
- [selectedExpiry, selectedChain, spender, verifyingContract],
82
+ [selectedExpiry, selectedChain, spender],
88
83
  false,
89
84
  );
90
85
 
@@ -123,7 +118,7 @@ export function StoryView() {
123
118
  setSelectedChain(Number(e.target.value) as typeof selectedChain)
124
119
  }
125
120
  >
126
- {AVAILABLE_CHAINS.map(chainId => (
121
+ {SUPPORTED_STAKE_AND_BAKE_CHAINS.map(chainId => (
127
122
  <MenuItem key={chainId} value={chainId}>
128
123
  {chainId}
129
124
  </MenuItem>
@@ -143,17 +138,6 @@ export function StoryView() {
143
138
  </FormControl>
144
139
  </div>
145
140
 
146
- <div className="mb-4">
147
- <FormControl fullWidth>
148
- <TextField
149
- label="Verifying Contract"
150
- value={verifyingContract}
151
- onChange={e => setVerifyingContract(e.target.value)}
152
- helperText="The contract that will verify the signature"
153
- />
154
- </FormControl>
155
- </div>
156
-
157
141
  <div className="mb-4">
158
142
  <FormControl fullWidth>
159
143
  <InputLabel id="expiry-select-label">Expiry Time</InputLabel>
@@ -2,6 +2,7 @@ import { TChainId } from '../../common/types/types';
2
2
  import { Provider } from '../../provider';
3
3
  import { IProviderBasedParams } from '../types';
4
4
  import { getStakeAndBakeTypedData } from './getTypedData';
5
+ import { getVerifyingContract } from './utils';
5
6
 
6
7
  const NO_SIGNATURE_ERROR =
7
8
  'Failed to obtain a valid signature. The response is undefined or invalid.';
@@ -32,10 +33,6 @@ export interface ISignStakeAndBakeParams
32
33
  * The spender address that will be authorized to spend tokens
33
34
  */
34
35
  spender: string;
35
- /**
36
- * The contract address that will verify the signature
37
- */
38
- verifyingContract: string;
39
36
  }
40
37
 
41
38
  export interface ISignStakeAndBakeResult {
@@ -63,7 +60,6 @@ export async function signStakeAndBake({
63
60
  expiry,
64
61
  rpcUrl,
65
62
  spender,
66
- verifyingContract,
67
63
  }: ISignStakeAndBakeParams): Promise<ISignStakeAndBakeResult> {
68
64
  const providerInstance = new Provider({
69
65
  provider,
@@ -71,6 +67,8 @@ export async function signStakeAndBake({
71
67
  chainId,
72
68
  });
73
69
 
70
+ const verifyingContract = getVerifyingContract(chainId);
71
+
74
72
  const typedDataObject = await getStakeAndBakeTypedData({
75
73
  chainId,
76
74
  expiry,
@@ -0,0 +1,16 @@
1
+ import { TChainId } from '../../common/types/types';
2
+ import { getLbtcAddressConfig } from '../lbtcAddressConfig';
3
+
4
+ /**
5
+ * Gets the LBTC contract address for a given chain ID
6
+ * @param chainId The chain ID
7
+ * @returns The LBTC contract address for the chain
8
+ */
9
+ export const getVerifyingContract = (chainId: TChainId): string => {
10
+ const lbtcAddressConfig = getLbtcAddressConfig('stage');
11
+ const address = lbtcAddressConfig[chainId];
12
+ if (!address) {
13
+ throw new Error(`No LBTC contract address configured for chain ID ${chainId}`);
14
+ }
15
+ return address;
16
+ };