@keplr-wallet/hooks-starknet 0.12.133-rc.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 (62) hide show
  1. package/.eslintignore +2 -0
  2. package/.prettierignore +2 -0
  3. package/LICENSE +209 -0
  4. package/build/index.d.ts +1 -0
  5. package/build/index.js +18 -0
  6. package/build/index.js.map +1 -0
  7. package/build/tx/amount.d.ts +27 -0
  8. package/build/tx/amount.js +230 -0
  9. package/build/tx/amount.js.map +1 -0
  10. package/build/tx/chain.d.ts +11 -0
  11. package/build/tx/chain.js +37 -0
  12. package/build/tx/chain.js.map +1 -0
  13. package/build/tx/errors.d.ts +48 -0
  14. package/build/tx/errors.js +132 -0
  15. package/build/tx/errors.js.map +1 -0
  16. package/build/tx/fee.d.ts +30 -0
  17. package/build/tx/fee.js +167 -0
  18. package/build/tx/fee.js.map +1 -0
  19. package/build/tx/gas-simulator.d.ts +72 -0
  20. package/build/tx/gas-simulator.js +491 -0
  21. package/build/tx/gas-simulator.js.map +1 -0
  22. package/build/tx/gas.d.ts +14 -0
  23. package/build/tx/gas.js +116 -0
  24. package/build/tx/gas.js.map +1 -0
  25. package/build/tx/index.d.ts +12 -0
  26. package/build/tx/index.js +29 -0
  27. package/build/tx/index.js.map +1 -0
  28. package/build/tx/noop-amount.d.ts +20 -0
  29. package/build/tx/noop-amount.js +90 -0
  30. package/build/tx/noop-amount.js.map +1 -0
  31. package/build/tx/recipient.d.ts +12 -0
  32. package/build/tx/recipient.js +80 -0
  33. package/build/tx/recipient.js.map +1 -0
  34. package/build/tx/send-tx.d.ts +9 -0
  35. package/build/tx/send-tx.js +22 -0
  36. package/build/tx/send-tx.js.map +1 -0
  37. package/build/tx/sender.d.ts +14 -0
  38. package/build/tx/sender.js +88 -0
  39. package/build/tx/sender.js.map +1 -0
  40. package/build/tx/types.d.ts +63 -0
  41. package/build/tx/types.js +3 -0
  42. package/build/tx/types.js.map +1 -0
  43. package/build/tx/validate.d.ts +11 -0
  44. package/build/tx/validate.js +52 -0
  45. package/build/tx/validate.js.map +1 -0
  46. package/jest.config.js +5 -0
  47. package/package.json +43 -0
  48. package/src/index.ts +1 -0
  49. package/src/tx/amount.ts +275 -0
  50. package/src/tx/chain.ts +32 -0
  51. package/src/tx/errors.ts +127 -0
  52. package/src/tx/fee.ts +209 -0
  53. package/src/tx/gas-simulator.ts +571 -0
  54. package/src/tx/gas.ts +131 -0
  55. package/src/tx/index.ts +12 -0
  56. package/src/tx/noop-amount.ts +92 -0
  57. package/src/tx/recipient.ts +82 -0
  58. package/src/tx/send-tx.ts +53 -0
  59. package/src/tx/sender.ts +104 -0
  60. package/src/tx/types.ts +97 -0
  61. package/src/tx/validate.ts +70 -0
  62. package/tsconfig.json +13 -0
@@ -0,0 +1,92 @@
1
+ import { IAmountConfig, ISenderConfig, UIProperties } from "./types";
2
+ import { TxChainSetter } from "./chain";
3
+ import { ChainGetter } from "@keplr-wallet/stores";
4
+ import { action, computed, makeObservable, observable } from "mobx";
5
+ import { ERC20Currency } from "@keplr-wallet/types";
6
+ import { CoinPretty, Dec, DecUtils } from "@keplr-wallet/unit";
7
+ import { useState } from "react";
8
+
9
+ export class NoopAmountConfig extends TxChainSetter implements IAmountConfig {
10
+ @observable.ref
11
+ protected _currency?: ERC20Currency = undefined;
12
+
13
+ constructor(
14
+ chainGetter: ChainGetter,
15
+ initialChainId: string,
16
+ protected readonly senderConfig: ISenderConfig
17
+ ) {
18
+ super(chainGetter, initialChainId);
19
+
20
+ makeObservable(this);
21
+ }
22
+
23
+ @computed
24
+ get value(): string {
25
+ return "0";
26
+ }
27
+
28
+ @action
29
+ setValue(_value: string): void {
30
+ // noop
31
+ }
32
+
33
+ @computed
34
+ get amount(): CoinPretty[] {
35
+ return [
36
+ new CoinPretty(
37
+ this.currency,
38
+ new Dec(0)
39
+ .mul(DecUtils.getTenExponentN(this.currency.coinDecimals))
40
+ .truncate()
41
+ ),
42
+ ];
43
+ }
44
+
45
+ @computed
46
+ get currency(): ERC20Currency {
47
+ const modularChainInfo = this.modularChainInfo;
48
+ if (!("starknet" in modularChainInfo)) {
49
+ throw new Error("Chain doesn't support the starknet");
50
+ }
51
+
52
+ return modularChainInfo.starknet.currencies[0];
53
+ }
54
+
55
+ @action
56
+ setCurrency(_currency: ERC20Currency | undefined) {
57
+ // noop
58
+ }
59
+
60
+ get fraction(): number {
61
+ return 0;
62
+ }
63
+
64
+ @action
65
+ setFraction(_fraction: number): void {
66
+ // noop
67
+ }
68
+
69
+ canUseCurrency(_currency: ERC20Currency): boolean {
70
+ // noop
71
+ return true;
72
+ }
73
+
74
+ @computed
75
+ get uiProperties(): UIProperties {
76
+ // noop
77
+ return {};
78
+ }
79
+ }
80
+
81
+ export const useNoopAmountConfig = (
82
+ chainGetter: ChainGetter,
83
+ chainId: string,
84
+ senderConfig: ISenderConfig
85
+ ) => {
86
+ const [txConfig] = useState(
87
+ () => new NoopAmountConfig(chainGetter, chainId, senderConfig)
88
+ );
89
+ txConfig.setChain(chainId);
90
+
91
+ return txConfig;
92
+ };
@@ -0,0 +1,82 @@
1
+ import { IRecipientConfig, UIProperties } from "./types";
2
+ import { TxChainSetter } from "./chain";
3
+ import { ChainGetter } from "@keplr-wallet/stores";
4
+ import { action, computed, makeObservable, observable } from "mobx";
5
+ import { EmptyAddressError, InvalidHexError } from "./errors";
6
+ import { useState } from "react";
7
+ import { Buffer } from "buffer/";
8
+
9
+ export class RecipientConfig extends TxChainSetter implements IRecipientConfig {
10
+ @observable
11
+ protected _value: string = "";
12
+
13
+ constructor(chainGetter: ChainGetter, initialChainId: string) {
14
+ super(chainGetter, initialChainId);
15
+
16
+ makeObservable(this);
17
+ }
18
+
19
+ get recipient(): string {
20
+ const rawRecipient = this.value.trim();
21
+
22
+ const modularChainInfo = this.modularChainInfo;
23
+ if (!("starknet" in modularChainInfo)) {
24
+ throw new Error("Chain doesn't support the starknet");
25
+ }
26
+
27
+ return rawRecipient;
28
+ }
29
+
30
+ @computed
31
+ get uiProperties(): UIProperties {
32
+ const rawRecipient = this.value.trim();
33
+
34
+ if (!rawRecipient) {
35
+ return {
36
+ error: new EmptyAddressError("Address is empty"),
37
+ };
38
+ }
39
+
40
+ if (!rawRecipient.startsWith("0x")) {
41
+ return {
42
+ error: new InvalidHexError("Invalid hex address for chain"),
43
+ };
44
+ }
45
+
46
+ {
47
+ const hex = rawRecipient.replace("0x", "");
48
+ const buf = Buffer.from(hex, "hex");
49
+ if (buf.length !== 32) {
50
+ return {
51
+ error: new InvalidHexError("Invalid hex address for chain"),
52
+ };
53
+ }
54
+ if (hex.toLowerCase() !== buf.toString("hex").toLowerCase()) {
55
+ return {
56
+ error: new InvalidHexError("Invalid hex address for chain"),
57
+ };
58
+ }
59
+ }
60
+
61
+ return {};
62
+ }
63
+
64
+ get value(): string {
65
+ return this._value;
66
+ }
67
+
68
+ @action
69
+ setValue(value: string): void {
70
+ this._value = value;
71
+ }
72
+ }
73
+
74
+ export const useRecipientConfig = (
75
+ chainGetter: ChainGetter,
76
+ chainId: string
77
+ ) => {
78
+ const [config] = useState(() => new RecipientConfig(chainGetter, chainId));
79
+ config.setChain(chainId);
80
+
81
+ return config;
82
+ };
@@ -0,0 +1,53 @@
1
+ import { ChainGetter } from "@keplr-wallet/stores";
2
+ import {
3
+ useFeeConfig,
4
+ useGasConfig,
5
+ useRecipientConfig,
6
+ useSenderConfig,
7
+ } from "./index";
8
+ import { useAmountConfig } from "./amount";
9
+ import { StarknetQueriesStore } from "@keplr-wallet/stores-starknet";
10
+
11
+ export const useSendTxConfig = (
12
+ chainGetter: ChainGetter,
13
+ starknetQueriesStore: StarknetQueriesStore,
14
+ chainId: string,
15
+ sender: string,
16
+ initialGas: number
17
+ ) => {
18
+ const senderConfig = useSenderConfig(
19
+ chainGetter,
20
+ starknetQueriesStore,
21
+ chainId,
22
+ sender
23
+ );
24
+
25
+ const amountConfig = useAmountConfig(
26
+ chainGetter,
27
+ starknetQueriesStore,
28
+ chainId,
29
+ senderConfig
30
+ );
31
+
32
+ const gasConfig = useGasConfig(chainGetter, chainId, initialGas);
33
+ const feeConfig = useFeeConfig(
34
+ chainGetter,
35
+ starknetQueriesStore,
36
+ chainId,
37
+ senderConfig,
38
+ amountConfig,
39
+ gasConfig
40
+ );
41
+
42
+ amountConfig.setFeeConfig(feeConfig);
43
+
44
+ const recipientConfig = useRecipientConfig(chainGetter, chainId);
45
+
46
+ return {
47
+ senderConfig,
48
+ amountConfig,
49
+ gasConfig,
50
+ feeConfig,
51
+ recipientConfig,
52
+ };
53
+ };
@@ -0,0 +1,104 @@
1
+ import { ISenderConfig, UIProperties } from "./types";
2
+ import { TxChainSetter } from "./chain";
3
+ import { action, makeObservable, observable } from "mobx";
4
+ import { ChainGetter } from "@keplr-wallet/stores";
5
+ import { useState } from "react";
6
+ import { StarknetQueriesStore } from "@keplr-wallet/stores-starknet";
7
+ import {
8
+ AccountNotDeployed,
9
+ EmptyAddressError,
10
+ InvalidHexError,
11
+ } from "./errors";
12
+ import { Buffer } from "buffer";
13
+
14
+ export class SenderConfig extends TxChainSetter implements ISenderConfig {
15
+ @observable
16
+ protected _value: string = "";
17
+
18
+ constructor(
19
+ chainGetter: ChainGetter,
20
+ protected readonly starknetQueriesStore: StarknetQueriesStore,
21
+ initialChainId: string,
22
+ initialSender: string
23
+ ) {
24
+ super(chainGetter, initialChainId);
25
+
26
+ this._value = initialSender;
27
+
28
+ makeObservable(this);
29
+ }
30
+
31
+ get sender(): string {
32
+ return this._value;
33
+ }
34
+
35
+ get value(): string {
36
+ return this._value;
37
+ }
38
+
39
+ @action
40
+ setValue(value: string): void {
41
+ this._value = value;
42
+ }
43
+
44
+ get uiProperties(): UIProperties {
45
+ if (!this.value) {
46
+ return {
47
+ error: new EmptyAddressError("Address is empty"),
48
+ };
49
+ }
50
+
51
+ if (!this.value.startsWith("0x")) {
52
+ return {
53
+ error: new InvalidHexError("Invalid hex address for chain"),
54
+ };
55
+ }
56
+
57
+ {
58
+ const hex = this.value.replace("0x", "");
59
+ const buf = Buffer.from(hex, "hex");
60
+ if (buf.length !== 32) {
61
+ return {
62
+ error: new InvalidHexError("Invalid hex address for chain"),
63
+ };
64
+ }
65
+ if (hex.toLowerCase() !== buf.toString("hex").toLowerCase()) {
66
+ return {
67
+ error: new InvalidHexError("Invalid hex address for chain"),
68
+ };
69
+ }
70
+ }
71
+
72
+ const queryNonce = this.starknetQueriesStore
73
+ .get(this.chainId)
74
+ .queryAccountNonce.getNonce(this.value);
75
+ if (!queryNonce.response && !queryNonce.error) {
76
+ return {
77
+ loadingState: "loading-block",
78
+ };
79
+ }
80
+
81
+ if (queryNonce.error?.message === "Contract not found") {
82
+ return {
83
+ error: new AccountNotDeployed("Account not deployed"),
84
+ };
85
+ }
86
+
87
+ return {};
88
+ }
89
+ }
90
+
91
+ export const useSenderConfig = (
92
+ chainGetter: ChainGetter,
93
+ starknetQueriesStore: StarknetQueriesStore,
94
+ chainId: string,
95
+ sender: string
96
+ ) => {
97
+ const [config] = useState(
98
+ () => new SenderConfig(chainGetter, starknetQueriesStore, chainId, sender)
99
+ );
100
+ config.setChain(chainId);
101
+ config.setValue(sender);
102
+
103
+ return config;
104
+ };
@@ -0,0 +1,97 @@
1
+ import { ERC20Currency } from "@keplr-wallet/types";
2
+ import { CoinPretty } from "@keplr-wallet/unit";
3
+
4
+ export interface ITxChainSetter {
5
+ chainId: string;
6
+ setChain(chainId: string): void;
7
+ }
8
+
9
+ export interface UIProperties {
10
+ // There is an error that cannot proceed the tx.
11
+ readonly error?: Error;
12
+ // Able to handle tx but prefer to show warning
13
+ readonly warning?: Error;
14
+ // Prefer that the loading UI is displayed.
15
+ // In the case of "loading-block", the UI should handle it so that the user cannot proceed until loading is completed.
16
+ readonly loadingState?: "loading" | "loading-block";
17
+ }
18
+
19
+ export interface IGasConfig extends ITxChainSetter {
20
+ value: string;
21
+ setValue(value: string | number): void;
22
+
23
+ gas: number;
24
+
25
+ uiProperties: UIProperties;
26
+ }
27
+
28
+ export interface ISenderConfig extends ITxChainSetter {
29
+ value: string;
30
+ setValue(value: string): void;
31
+
32
+ sender: string;
33
+
34
+ uiProperties: UIProperties;
35
+ }
36
+
37
+ export interface IFeeConfig extends ITxChainSetter {
38
+ type: "ETH" | "STRK";
39
+ setType(type: "ETH" | "STRK"): void;
40
+
41
+ gasPrice: CoinPretty | undefined;
42
+ maxGasPrice: CoinPretty | undefined;
43
+ setGasPrice(
44
+ gasPrice:
45
+ | {
46
+ gasPrice: CoinPretty;
47
+ maxGasPrice: CoinPretty;
48
+ }
49
+ | undefined
50
+ ): void;
51
+
52
+ fee: CoinPretty | undefined;
53
+ maxFee: CoinPretty | undefined;
54
+
55
+ uiProperties: UIProperties;
56
+ }
57
+
58
+ export interface IRecipientConfig extends ITxChainSetter {
59
+ value: string;
60
+ setValue(value: string): void;
61
+
62
+ recipient: string;
63
+
64
+ uiProperties: UIProperties;
65
+ }
66
+
67
+ export interface IAmountConfig extends ITxChainSetter {
68
+ amount: CoinPretty[];
69
+
70
+ value: string;
71
+ setValue(value: string): void;
72
+
73
+ currency: ERC20Currency;
74
+ setCurrency(currency: ERC20Currency | undefined): void;
75
+ canUseCurrency(currency: ERC20Currency): boolean;
76
+
77
+ // Zero means unset.
78
+ fraction: number;
79
+ setFraction(fraction: number): void;
80
+
81
+ uiProperties: UIProperties;
82
+ }
83
+
84
+ export interface IGasSimulator {
85
+ enabled: boolean;
86
+ setEnabled(value: boolean): void;
87
+
88
+ isSimulating: boolean;
89
+
90
+ gasEstimated: number | undefined;
91
+ gasAdjustment: number;
92
+
93
+ gasAdjustmentValue: string;
94
+ setGasAdjustmentValue(gasAdjustment: string | number): void;
95
+
96
+ uiProperties: UIProperties;
97
+ }
@@ -0,0 +1,70 @@
1
+ import {
2
+ IAmountConfig,
3
+ IFeeConfig,
4
+ IGasConfig,
5
+ IGasSimulator,
6
+ IRecipientConfig,
7
+ ISenderConfig,
8
+ } from "./types";
9
+
10
+ // CONTRACT: Use with `observer`
11
+ export const useTxConfigsValidate = (configs: {
12
+ amountConfig?: IAmountConfig;
13
+ senderConfig?: ISenderConfig;
14
+ recipientConfig?: IRecipientConfig;
15
+ gasConfig?: IGasConfig;
16
+ feeConfig?: IFeeConfig;
17
+ gasSimulator?: IGasSimulator;
18
+ }) => {
19
+ const interactionBlocked = (() => {
20
+ /*
21
+ * XXX: 밑의 예시같은 식으로 처리하면 안된다...
22
+ * 그러면 또는(||)에 의해서 앞에꺼에서 true가 나오면 뒤에꺼가 실행도 안되는 문제가 있다.
23
+ * mobx observable의 특성상 이렇게 처리되면 의도에 맞지 않는다.
24
+ * if (
25
+ configs.amountConfig?.uiProperties.error ||
26
+ configs.senderConfig?.uiProperties.error ||
27
+ configs.recipientConfig?.uiProperties.error ||
28
+ configs.gasConfig?.uiProperties.error ||
29
+ configs.feeConfig?.uiProperties.error ||
30
+ configs.gasSimulator?.uiProperties.error
31
+ ) {
32
+ return true;
33
+ }
34
+ */
35
+ const amountConfigUIProperties = configs.amountConfig?.uiProperties;
36
+ const senderConfigUIProperties = configs.senderConfig?.uiProperties;
37
+ const recipientConfigUIProperties = configs.recipientConfig?.uiProperties;
38
+ const gasConfigUIProperties = configs.gasConfig?.uiProperties;
39
+ const feeConfigUIProperties = configs.feeConfig?.uiProperties;
40
+ const gasSimulatorUIProperties = configs.gasSimulator?.uiProperties;
41
+
42
+ if (
43
+ amountConfigUIProperties?.error ||
44
+ senderConfigUIProperties?.error ||
45
+ recipientConfigUIProperties?.error ||
46
+ gasConfigUIProperties?.error ||
47
+ feeConfigUIProperties?.error ||
48
+ gasSimulatorUIProperties?.error
49
+ ) {
50
+ return true;
51
+ }
52
+
53
+ if (
54
+ amountConfigUIProperties?.loadingState === "loading-block" ||
55
+ senderConfigUIProperties?.loadingState === "loading-block" ||
56
+ recipientConfigUIProperties?.loadingState === "loading-block" ||
57
+ gasConfigUIProperties?.loadingState === "loading-block" ||
58
+ feeConfigUIProperties?.loadingState === "loading-block" ||
59
+ gasSimulatorUIProperties?.loadingState === "loading-block"
60
+ ) {
61
+ return true;
62
+ }
63
+
64
+ return false;
65
+ })();
66
+
67
+ return {
68
+ interactionBlocked,
69
+ };
70
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "outDir": "build",
6
+ "declaration": true,
7
+ "rootDir": "src",
8
+ "jsx": "react"
9
+ },
10
+ "include": [
11
+ "src/**/*"
12
+ ]
13
+ }