@lombard.finance/sdk-starknet 0.3.0-canary.2

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 (58) hide show
  1. package/README.md +128 -0
  2. package/dist/index.cjs +2 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.js +20 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index2.cjs +229 -0
  7. package/dist/index2.cjs.map +1 -0
  8. package/dist/index2.js +30378 -0
  9. package/dist/index2.js.map +1 -0
  10. package/dist/index3.cjs +2 -0
  11. package/dist/index3.cjs.map +1 -0
  12. package/dist/index3.js +2316 -0
  13. package/dist/index3.js.map +1 -0
  14. package/package.json +66 -0
  15. package/src/contract-functions/approve.stories.tsx +74 -0
  16. package/src/contract-functions/approve.ts +56 -0
  17. package/src/contract-functions/balance-of.stories.tsx +54 -0
  18. package/src/contract-functions/balance-of.ts +41 -0
  19. package/src/contract-functions/mint.ts +109 -0
  20. package/src/contract-functions/redeem.ts +107 -0
  21. package/src/index.ts +25 -0
  22. package/src/module/createStarknetModule.ts +38 -0
  23. package/src/services/StarknetServiceImpl.ts +83 -0
  24. package/src/services/index.ts +7 -0
  25. package/src/stories/components/Button/Button.css +10 -0
  26. package/src/stories/components/Button/Button.tsx +52 -0
  27. package/src/stories/components/Button/index.ts +1 -0
  28. package/src/stories/components/CodeBlock/CodeBlock.tsx +38 -0
  29. package/src/stories/components/CodeBlock/CodeBlockStyles.css +3 -0
  30. package/src/stories/components/CodeBlock/index.ts +1 -0
  31. package/src/stories/components/ConnectButton/connect-button.tsx +112 -0
  32. package/src/stories/components/ConnectButton/index.ts +1 -0
  33. package/src/stories/components/Spinner/Spinner.tsx +24 -0
  34. package/src/stories/components/Spinner/index.ts +1 -0
  35. package/src/stories/components/decorators/function-type.tsx +66 -0
  36. package/src/stories/components/decorators/index.ts +1 -0
  37. package/src/stories/components/decorators/starknet-context.tsx +21 -0
  38. package/src/stories/components/error-block.tsx +21 -0
  39. package/src/stories/hooks/use-connection.ts +70 -0
  40. package/src/stories/hooks/use-query.ts +56 -0
  41. package/src/tokens/abi/ERC20_ABI.ts +1122 -0
  42. package/src/tokens/abi/LBTC_ABI.ts +1615 -0
  43. package/src/tokens/abi/LBTC_BASCULE_ABI.ts +709 -0
  44. package/src/tokens/abi/LBTC_BRIDGE_ABI.ts +1568 -0
  45. package/src/tokens/lib/tokens.ts +267 -0
  46. package/src/utils/account.ts +81 -0
  47. package/src/utils/chains.ts +33 -0
  48. package/src/utils/common.ts +11 -0
  49. package/src/utils/env.ts +6 -0
  50. package/src/utils/err.ts +121 -0
  51. package/src/utils/rpc-providers.ts +25 -0
  52. package/src/utils/signature.ts +60 -0
  53. package/src/utils/span.ts +56 -0
  54. package/src/utils/typed-data.ts +36 -0
  55. package/src/utils/wallet-account.ts +9 -0
  56. package/src/wallet-functions/sign-message.stories.tsx +72 -0
  57. package/src/wallet-functions/sign-message.ts +127 -0
  58. package/src/wallet-functions/sign-terms-of-service.ts +45 -0
@@ -0,0 +1,52 @@
1
+ import './Button.css';
2
+
3
+ import React from 'react';
4
+
5
+ import { Spinner } from '../Spinner';
6
+
7
+ export interface ButtonProps {
8
+ disabled?: boolean;
9
+ children?: React.ReactNode;
10
+ actionName?: string;
11
+ primary?: boolean;
12
+ size?: 'small' | 'medium' | 'large';
13
+ isLoading?: boolean;
14
+ onClick?: () => void;
15
+ }
16
+
17
+ /**
18
+ * Execute action button
19
+ */
20
+ export const Button = ({
21
+ primary = true,
22
+ size = 'medium',
23
+ actionName,
24
+ children,
25
+ isLoading,
26
+ ...props
27
+ }: ButtonProps) => {
28
+ const label = actionName ? (
29
+ <span>
30
+ Execute: <span style={{ fontFamily: 'monospace' }}>{actionName}</span>
31
+ </span>
32
+ ) : (
33
+ children
34
+ );
35
+
36
+ return (
37
+ <button
38
+ type="button"
39
+ className={[
40
+ 'btn',
41
+ size === 'small' ? 'btn-sm' : '',
42
+ size === 'large' ? 'btn-lg' : '',
43
+ 'story-btn',
44
+ ].join(' ')}
45
+ {...props}
46
+ >
47
+ {label}
48
+
49
+ {isLoading && <Spinner color="text-primary" className="ms-2" />}
50
+ </button>
51
+ );
52
+ };
@@ -0,0 +1 @@
1
+ export * from './Button';
@@ -0,0 +1,38 @@
1
+ import './CodeBlockStyles.css';
2
+
3
+ interface ICodeBlockProps {
4
+ text?: unknown;
5
+ withFormatting?: boolean;
6
+ }
7
+
8
+ export function CodeBlock({
9
+ text,
10
+ withFormatting = true,
11
+ }: ICodeBlockProps): JSX.Element | null {
12
+ if (text === undefined || text === null) {
13
+ return null;
14
+ }
15
+
16
+ const formattedCode: string = withFormatting
17
+ ? JSON.stringify(text, null, 2)
18
+ : String(text);
19
+
20
+ const isError = text instanceof Error;
21
+
22
+ return (
23
+ <pre
24
+ className="card my-3 code-block--max-height"
25
+ style={
26
+ isError
27
+ ? {
28
+ color: 'white',
29
+ background: 'red',
30
+ borderColor: 'darkred',
31
+ }
32
+ : undefined
33
+ }
34
+ >
35
+ <code className="card-body">{formattedCode}</code>
36
+ </pre>
37
+ );
38
+ }
@@ -0,0 +1,3 @@
1
+ .code-block--max-height {
2
+ max-height: 500px;
3
+ }
@@ -0,0 +1 @@
1
+ export * from './CodeBlock';
@@ -0,0 +1,112 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { StarknetChainId } from '../../../utils/chains';
4
+ import { useConnection } from '../../hooks/use-connection';
5
+
6
+ export type ConnectButtonProps = {
7
+ desiredChainId?: StarknetChainId;
8
+ label?: string;
9
+ };
10
+
11
+ export function ConnectButton({ desiredChainId, label }: ConnectButtonProps) {
12
+ const [chainId, setChainId] = useState<StarknetChainId | undefined>(
13
+ undefined,
14
+ );
15
+ const { account, connect, disconnect } = useConnection();
16
+
17
+ useEffect(() => {
18
+ if (!account) {
19
+ if (!chainId) setChainId(undefined);
20
+ return;
21
+ }
22
+
23
+ async () => {
24
+ const connectedChainId = (await account.getChainId()) as StarknetChainId;
25
+
26
+ if (chainId !== connectedChainId) {
27
+ setChainId(connectedChainId);
28
+ }
29
+ };
30
+ }, [account, chainId]);
31
+
32
+ if (account) {
33
+ return (
34
+ <div
35
+ style={{
36
+ display: 'inline-flex',
37
+ flexDirection: 'row',
38
+ alignItems: 'center',
39
+ gap: '5px',
40
+ border: '1px solid var(--bs-gray-900)',
41
+ borderRadius: '5px',
42
+ padding: '5px',
43
+ height: '38px',
44
+ }}
45
+ >
46
+ <span
47
+ style={{
48
+ background: 'var(--bs-green)',
49
+ color: '#ffffff',
50
+ borderRadius: '5px',
51
+ padding: '2px',
52
+ fontSize: '0.8em',
53
+ }}
54
+ >
55
+ connected
56
+ </span>
57
+
58
+ <span
59
+ style={{
60
+ background: 'var(--bs-gray-100)',
61
+ borderRadius: '5px',
62
+ padding: '2px',
63
+ fontSize: '0.8em',
64
+ }}
65
+ >
66
+ {account.address}
67
+ </span>
68
+
69
+ <span
70
+ style={{
71
+ background: chainId ? 'var(--bs-gray-200)' : 'var(--bs-red)',
72
+ color: chainId ? 'var(--bs-black)' : 'var(--bs-white)',
73
+ borderRadius: '5px',
74
+ padding: '2px',
75
+ fontSize: '0.8em',
76
+ }}
77
+ >
78
+ {chainId}
79
+ </span>
80
+
81
+ <button
82
+ type="button"
83
+ style={{
84
+ background: 'var(--bs-danger)',
85
+ color: 'var(--bs-white)',
86
+ border: '0',
87
+ borderRadius: '5px',
88
+ padding: '2px',
89
+ fontSize: '0.8em',
90
+ cursor: 'pointer',
91
+ }}
92
+ onClick={() => disconnect()}
93
+ >
94
+ Disconnect
95
+ </button>
96
+ </div>
97
+ );
98
+ }
99
+
100
+ return (
101
+ <button
102
+ className="btn"
103
+ style={{
104
+ border: '1px solid var(--bs-gray-900)',
105
+ }}
106
+ type="button"
107
+ onClick={() => connect(desiredChainId)}
108
+ >
109
+ {label || 'Connect wallet'}
110
+ </button>
111
+ );
112
+ }
@@ -0,0 +1 @@
1
+ export { ConnectButton, type ConnectButtonProps } from './connect-button';
@@ -0,0 +1,24 @@
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
+ <output
14
+ className={[
15
+ 'spinner-border',
16
+ color,
17
+ size === 'sm' ? 'spinner-border-sm' : '',
18
+ className || '',
19
+ ].join(' ')}
20
+ >
21
+ <span className="visually-hidden">Loading...</span>
22
+ </output>
23
+ );
24
+ }
@@ -0,0 +1 @@
1
+ export * from './Spinner';
@@ -0,0 +1,66 @@
1
+ type FuncType = 'api-get' | 'api-post' | 'read' | 'write' | 'flow';
2
+
3
+ export const functionType =
4
+ (type: FuncType) => (Story: React.ComponentType) => {
5
+ return (
6
+ <div
7
+ style={{
8
+ display: 'flex',
9
+ gap: '5px',
10
+ flexDirection: 'column',
11
+ border: `1px solid ${colors[type]}`,
12
+ borderRadius: '5px',
13
+ overflow: 'hidden',
14
+ }}
15
+ >
16
+ <div
17
+ style={{
18
+ display: 'inline-flex',
19
+ flexDirection: 'row',
20
+ gap: '5px',
21
+ fontSize: '0.8em',
22
+ background: colors[type],
23
+ color: 'var(--bs-white)',
24
+ padding: '2px 5px',
25
+ // borderRadius: '5px',
26
+ }}
27
+ >
28
+ <span style={{ fontWeight: '800 ' }}>{labels[type]}</span>
29
+ <span style={{ opacity: '0.8' }}>{descriptions[type]}</span>
30
+ </div>
31
+
32
+ <div
33
+ style={{
34
+ padding: '20px',
35
+ }}
36
+ >
37
+ <Story />
38
+ </div>
39
+ </div>
40
+ );
41
+ };
42
+
43
+ const labels: Record<FuncType, string> = {
44
+ 'api-get': 'API (get)',
45
+ 'api-post': 'API (post)',
46
+ read: 'READ',
47
+ write: 'WRITE',
48
+ flow: 'FLOW',
49
+ };
50
+
51
+ const descriptions: Record<FuncType, string> = {
52
+ 'api-get': 'The function gets data from the Lombard API(s)',
53
+ 'api-post': 'The function posts data to the Lombard API(s)',
54
+ read: 'The function reads data from the contract(s)',
55
+ write:
56
+ 'The function writes data to the contract(s) or performs a wallet action.',
57
+ flow: '',
58
+ };
59
+
60
+ const colors: Record<FuncType, string> = {
61
+ 'api-get': 'rgb(100 100 255)',
62
+ 'api-post': 'rgb(100 0 255)',
63
+ read: 'rgb(200 100 255)',
64
+ write: 'rgb(200 0 255)',
65
+ flow: 'rgb(0 155 255)',
66
+ };
@@ -0,0 +1 @@
1
+ export { functionType } from './function-type';
@@ -0,0 +1,21 @@
1
+ import { useState } from 'react';
2
+ import { WalletAccount } from 'starknet';
3
+
4
+ import { StarknetContext } from '../../hooks/use-connection';
5
+
6
+ export const starknetContext = () => (Story: React.ComponentType) => {
7
+ const [walletAccount, setWalletAccount] = useState<WalletAccount | undefined>(
8
+ undefined,
9
+ );
10
+
11
+ return (
12
+ <StarknetContext.Provider
13
+ value={{
14
+ walletAccount,
15
+ setWalletAccount,
16
+ }}
17
+ >
18
+ <Story />
19
+ </StarknetContext.Provider>
20
+ );
21
+ };
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ export const ErrorBlock = ({ children }: { children: ReactNode }) =>
4
+ children && (
5
+ <div
6
+ style={{
7
+ margin: '20px 0',
8
+ padding: '10px 0',
9
+ paddingLeft: '20px',
10
+ borderLeft: '3px solid var(--bs-red)',
11
+ whiteSpace: 'pre-wrap',
12
+ fontSize: '0.8em',
13
+ color: 'var(--bs-red)',
14
+ background: '#fef5f6',
15
+ overflow: 'hidden',
16
+ borderRadius: '5px',
17
+ }}
18
+ >
19
+ {children}
20
+ </div>
21
+ );
@@ -0,0 +1,70 @@
1
+ import {
2
+ connect as starknet_connect,
3
+ disconnect as starknet_disconnect,
4
+ } from '@starknet-io/get-starknet';
5
+ import { createContext, useCallback, useContext } from 'react';
6
+ import { defaultProvider,RpcProvider, WalletAccount } from 'starknet';
7
+
8
+ import { StarknetChainId } from '../../utils/chains';
9
+ import { ERR_NO_STARKNET_WINDOW_OBJECT } from '../../utils/err';
10
+ import { getRpcProvider } from '../../utils/rpc-providers';
11
+
12
+ const connectStarknet = async (rpcProvider?: RpcProvider) => {
13
+ const starknetWindowObject = await starknet_connect({
14
+ modalMode: 'alwaysAsk',
15
+ modalTheme: 'light',
16
+ });
17
+ if (!starknetWindowObject) {
18
+ throw ERR_NO_STARKNET_WINDOW_OBJECT;
19
+ }
20
+
21
+ const walletAccount = await WalletAccount.connect(
22
+ rpcProvider || defaultProvider,
23
+ starknetWindowObject,
24
+ );
25
+
26
+ return walletAccount;
27
+ };
28
+
29
+ export function useConnection() {
30
+ const { walletAccount, setWalletAccount } = useContext(StarknetContext);
31
+
32
+ const connect = useCallback(
33
+ async (chainId?: StarknetChainId) => {
34
+ console.info('Connecting starknet to', chainId);
35
+ try {
36
+ const walletAccount = await connectStarknet(
37
+ getRpcProvider(chainId || StarknetChainId.SN_SEPOLIA),
38
+ );
39
+ setWalletAccount(walletAccount);
40
+ } catch (err) {
41
+ console.info('Could not connect to Starknet.', err);
42
+ }
43
+ },
44
+ [setWalletAccount],
45
+ );
46
+
47
+ const disconnect = useCallback(async () => {
48
+ console.info('disconnecting starknet');
49
+ setWalletAccount(undefined);
50
+ await starknet_disconnect();
51
+ }, [setWalletAccount]);
52
+
53
+ return {
54
+ account: walletAccount,
55
+ connect,
56
+ disconnect,
57
+ };
58
+ }
59
+
60
+ export const StarknetContext = createContext<{
61
+ walletAccount: WalletAccount | undefined;
62
+ setWalletAccount: (walletAccount: WalletAccount | undefined) => void;
63
+ }>({
64
+ walletAccount: undefined,
65
+ setWalletAccount: () => {
66
+ throw new Error(
67
+ 'Do not use directly, use with the `starknetContext` decorator',
68
+ );
69
+ },
70
+ });
@@ -0,0 +1,56 @@
1
+ import { extractErrorMessage } from '@lombard.finance/sdk-common/utils/err';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+
4
+ type QueryFn<T> = () => Promise<T>;
5
+
6
+ interface UseQueryResult<T> {
7
+ data: T | undefined;
8
+ error: string | undefined;
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: unknown[] = [],
25
+ shouldFetch = true,
26
+ ): UseQueryResult<T> {
27
+ const [data, setData] = useState<T | undefined>(undefined);
28
+ const [error, setError] = useState<string | undefined>(undefined);
29
+ const [isLoading, setLoading] = useState<boolean>(false);
30
+
31
+ const fetchData = useCallback(async () => {
32
+ setLoading(true);
33
+ setError(undefined);
34
+ setData(undefined);
35
+ try {
36
+ const result = await queryFn();
37
+ setData(result);
38
+ } catch (err) {
39
+ console.error(err);
40
+ const errorMsg = extractErrorMessage(err);
41
+ setError(errorMsg);
42
+ } finally {
43
+ setLoading(false);
44
+ }
45
+ }, [queryFn, ...dependencies]);
46
+
47
+ useEffect(() => {
48
+ if (shouldFetch) {
49
+ void fetchData();
50
+ }
51
+ }, [shouldFetch, fetchData, ...dependencies]);
52
+
53
+ return { data, error, isLoading, refetch: fetchData };
54
+ }
55
+
56
+ export default useQuery;