@multiversx/sdk-dapp-liquidity 2.0.0 → 2.1.0-alpha.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/helpers/assertRateConfirmationMatchesIntent.d.ts +8 -0
- package/helpers/assertRateConfirmationMatchesIntent.js +24 -0
- package/helpers/assertRateConfirmationMatchesIntent.mjs +23 -0
- package/helpers/index.d.ts +2 -0
- package/helpers/index.js +4 -0
- package/helpers/index.mjs +4 -0
- package/helpers/safeImageUrl.d.ts +1 -0
- package/helpers/safeImageUrl.js +24 -0
- package/helpers/safeImageUrl.mjs +23 -0
- package/helpers/serializeTransaction.js +1 -1
- package/helpers/serializeTransaction.mjs +1 -1
- package/helpers/tests/assertRateConfirmationMatchesIntent.spec.d.ts +1 -0
- package/helpers/tests/assertRateConfirmationMatchesIntent.spec.js +64 -0
- package/helpers/tests/assertRateConfirmationMatchesIntent.spec.mjs +62 -0
- package/helpers/tests/safeImageUrl.spec.d.ts +1 -0
- package/helpers/tests/safeImageUrl.spec.js +49 -0
- package/helpers/tests/safeImageUrl.spec.mjs +47 -0
- package/helpers/tests/serializeTransaction.spec.d.ts +1 -0
- package/helpers/tests/serializeTransaction.spec.js +37 -0
- package/helpers/tests/serializeTransaction.spec.mjs +35 -0
- package/index.js +7 -3
- package/index.mjs +10 -6
- package/package.json +13 -8
- package/react.esm-7GsOwMPq.js +11815 -0
- package/react.esm-CU-Iqz8D.mjs +11796 -0
- package/reactjs/adapters/SuiAdapter.d.ts +14 -0
- package/reactjs/adapters/SuiAdapter.js +31 -2
- package/reactjs/adapters/SuiAdapter.mjs +31 -2
- package/reactjs/components/BridgeForm/Deposit.js +9 -7
- package/reactjs/components/BridgeForm/Deposit.mjs +8 -6
- package/reactjs/components/BridgeForm/Transfer.js +8 -6
- package/reactjs/components/BridgeForm/Transfer.mjs +7 -5
- package/reactjs/components/BridgeHistory/BridgeHistory.js +20 -6
- package/reactjs/components/BridgeHistory/BridgeHistory.mjs +20 -6
- package/reactjs/components/Connect/BridgeConnectButton.js +2 -1
- package/reactjs/components/Connect/BridgeConnectButton.mjs +2 -1
- package/reactjs/components/CopyButton/CopyButton.mjs +2 -2
- package/reactjs/components/TokenSelector/components/ChainSelect/components/ChainOptionLabel.js +5 -1
- package/reactjs/components/TokenSelector/components/ChainSelect/components/ChainOptionLabel.mjs +6 -2
- package/reactjs/components/TokenSelector/components/ChainSelect/components/SelectedChainOption.js +5 -1
- package/reactjs/components/TokenSelector/components/ChainSelect/components/SelectedChainOption.mjs +6 -2
- package/reactjs/components/TokenSelector/components/TokenIcon.js +2 -1
- package/reactjs/components/TokenSelector/components/TokenIcon.mjs +2 -1
- package/reactjs/context/Web3AppProvider.js +4 -2
- package/reactjs/context/Web3AppProvider.mjs +6 -4
- package/reactjs/hooks/tests/useGenericSignMessage.spec.d.ts +1 -0
- package/reactjs/hooks/tests/useGenericSignMessage.spec.js +69 -0
- package/reactjs/hooks/tests/useGenericSignMessage.spec.mjs +67 -0
- package/reactjs/hooks/tests/useSignTransaction.spec.d.ts +1 -0
- package/reactjs/hooks/tests/useSignTransaction.spec.js +196 -0
- package/reactjs/hooks/tests/useSignTransaction.spec.mjs +194 -0
- package/reactjs/hooks/useBridgeFormik.js +5 -0
- package/reactjs/hooks/useBridgeFormik.mjs +5 -0
- package/reactjs/hooks/useFetchTokens.js +4 -2
- package/reactjs/hooks/useFetchTokens.mjs +4 -2
- package/reactjs/hooks/useGenericSignMessage.js +23 -3
- package/reactjs/hooks/useGenericSignMessage.mjs +23 -3
- package/reactjs/hooks/useSignTransaction.js +27 -1
- package/reactjs/hooks/useSignTransaction.mjs +28 -2
- package/reactjs/index.js +3 -3
- package/reactjs/index.mjs +6 -6
- package/reactjs/init/init.d.ts +1 -0
- package/reactjs/init/init.js +11 -3
- package/reactjs/init/init.mjs +11 -3
- package/reactjs/queries/index.js +3 -3
- package/reactjs/queries/index.mjs +7 -7
- package/reactjs/queries/useCheckAccount.query.js +1 -1
- package/reactjs/queries/useCheckAccount.query.mjs +1 -1
- package/reactjs/queries/useGetAllTokens.query.js +1 -1
- package/reactjs/queries/useGetAllTokens.query.mjs +1 -1
- package/reactjs/queries/useGetChains.query.js +1 -1
- package/reactjs/queries/useGetChains.query.mjs +1 -1
- package/reactjs/queries/useGetHistory.query.d.ts +1 -1
- package/reactjs/queries/useGetHistory.query.js +10 -9
- package/reactjs/queries/useGetHistory.query.mjs +12 -11
- package/reactjs/queries/useGetMvxTokensBalances.query.d.ts +1 -1
- package/reactjs/queries/useGetMvxTokensBalances.query.js +9 -14
- package/reactjs/queries/useGetMvxTokensBalances.query.mjs +12 -17
- package/reactjs/queries/useGetNonMvxTokensBalances.query.d.ts +1 -1
- package/reactjs/queries/useGetNonMvxTokensBalances.query.js +8 -8
- package/reactjs/queries/useGetNonMvxTokensBalances.query.mjs +11 -11
- package/types/errors.d.ts +3 -0
- package/types/errors.js +10 -0
- package/types/errors.mjs +9 -0
- package/reactjs/hooks/useSignTransaction.d.ts +0 -511
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { useAppKitProvider, useAppKitAccount } from "@reown/appkit/react";
|
|
2
|
+
import { r as renderHook } from "../../../react.esm-CU-Iqz8D.mjs";
|
|
3
|
+
import { useSendTransaction } from "wagmi";
|
|
4
|
+
import { useSignTransaction } from "../useSignTransaction.mjs";
|
|
5
|
+
jest.mock("@reown/appkit-adapter-solana/react", () => ({
|
|
6
|
+
useAppKitConnection: jest.fn(() => ({ connection: null }))
|
|
7
|
+
}));
|
|
8
|
+
jest.mock("@solana/web3.js", () => ({
|
|
9
|
+
PublicKey: jest.fn(),
|
|
10
|
+
Transaction: jest.fn(() => ({ add: jest.fn().mockReturnThis() })),
|
|
11
|
+
TransactionInstruction: jest.fn()
|
|
12
|
+
}));
|
|
13
|
+
const mockUseAppKitProvider = jest.mocked(useAppKitProvider);
|
|
14
|
+
const mockUseAppKitAccount = jest.mocked(useAppKitAccount);
|
|
15
|
+
const mockUseSendTransaction = jest.mocked(useSendTransaction);
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
mockUseSendTransaction.mockReturnValue({
|
|
18
|
+
data: void 0,
|
|
19
|
+
sendTransactionAsync: jest.fn(),
|
|
20
|
+
error: null,
|
|
21
|
+
isError: false,
|
|
22
|
+
isIdle: true,
|
|
23
|
+
isPending: false,
|
|
24
|
+
isSuccess: false,
|
|
25
|
+
reset: jest.fn(),
|
|
26
|
+
sendTransaction: jest.fn(),
|
|
27
|
+
status: "idle",
|
|
28
|
+
variables: void 0,
|
|
29
|
+
context: void 0,
|
|
30
|
+
failureCount: 0,
|
|
31
|
+
failureReason: null,
|
|
32
|
+
isPaused: false,
|
|
33
|
+
submittedAt: 0,
|
|
34
|
+
mutate: jest.fn(),
|
|
35
|
+
mutateAsync: jest.fn()
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
const CONNECTED_SUI_ADDRESS = "0xabc123def456aaa000111222333444555666777888999aaabbbcccdddeeefff00";
|
|
39
|
+
function setupSuiMocks(suiRequest) {
|
|
40
|
+
mockUseAppKitProvider.mockImplementation((namespace) => {
|
|
41
|
+
if (namespace === "sui") {
|
|
42
|
+
return { walletProvider: { request: suiRequest } };
|
|
43
|
+
}
|
|
44
|
+
return { walletProvider: void 0 };
|
|
45
|
+
});
|
|
46
|
+
mockUseAppKitAccount.mockImplementation((opts) => {
|
|
47
|
+
if ((opts == null ? void 0 : opts.namespace) === "sui") {
|
|
48
|
+
return {
|
|
49
|
+
address: CONNECTED_SUI_ADDRESS,
|
|
50
|
+
isConnected: true,
|
|
51
|
+
status: "connected"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
address: void 0,
|
|
56
|
+
isConnected: false,
|
|
57
|
+
status: "disconnected"
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
describe("useSignTransaction — signSuiTransaction", () => {
|
|
62
|
+
const validBase64 = btoa("valid transaction bytes");
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
mockUseSendTransaction.mockReturnValue({
|
|
65
|
+
data: void 0,
|
|
66
|
+
sendTransactionAsync: jest.fn(),
|
|
67
|
+
error: null,
|
|
68
|
+
isError: false,
|
|
69
|
+
isIdle: true,
|
|
70
|
+
isPending: false,
|
|
71
|
+
isSuccess: false,
|
|
72
|
+
reset: jest.fn(),
|
|
73
|
+
sendTransaction: jest.fn(),
|
|
74
|
+
status: "idle",
|
|
75
|
+
variables: void 0,
|
|
76
|
+
context: void 0,
|
|
77
|
+
failureCount: 0,
|
|
78
|
+
failureReason: null,
|
|
79
|
+
isPaused: false,
|
|
80
|
+
submittedAt: 0,
|
|
81
|
+
mutate: jest.fn(),
|
|
82
|
+
mutateAsync: jest.fn()
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
it("succeeds with valid base64 payload", async () => {
|
|
86
|
+
const mockRequest = jest.fn().mockResolvedValue({ signature: "sui-sig-ok" });
|
|
87
|
+
setupSuiMocks(mockRequest);
|
|
88
|
+
const { result } = renderHook(() => useSignTransaction());
|
|
89
|
+
const sig = await result.current.sui.signTransaction({
|
|
90
|
+
transaction: validBase64,
|
|
91
|
+
address: CONNECTED_SUI_ADDRESS
|
|
92
|
+
});
|
|
93
|
+
expect(sig).toBe("sui-sig-ok");
|
|
94
|
+
expect(mockRequest).toHaveBeenCalledWith(
|
|
95
|
+
expect.objectContaining({ method: "sui_signTransaction" })
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
it("throws when payload is not valid base64", async () => {
|
|
99
|
+
const mockRequest = jest.fn();
|
|
100
|
+
setupSuiMocks(mockRequest);
|
|
101
|
+
const { result } = renderHook(() => useSignTransaction());
|
|
102
|
+
await expect(
|
|
103
|
+
result.current.sui.signTransaction({
|
|
104
|
+
transaction: "not-valid-base64!!!",
|
|
105
|
+
address: CONNECTED_SUI_ADDRESS
|
|
106
|
+
})
|
|
107
|
+
).rejects.toThrow("not valid base64");
|
|
108
|
+
expect(mockRequest).not.toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
it("throws when payload exceeds 32 KiB", async () => {
|
|
111
|
+
const mockRequest = jest.fn();
|
|
112
|
+
setupSuiMocks(mockRequest);
|
|
113
|
+
const largeBytes = new Uint8Array(32 * 1024 + 1);
|
|
114
|
+
const largeBase64 = btoa(String.fromCharCode(...largeBytes));
|
|
115
|
+
const { result } = renderHook(() => useSignTransaction());
|
|
116
|
+
await expect(
|
|
117
|
+
result.current.sui.signTransaction({
|
|
118
|
+
transaction: largeBase64,
|
|
119
|
+
address: CONNECTED_SUI_ADDRESS
|
|
120
|
+
})
|
|
121
|
+
).rejects.toThrow("maximum size");
|
|
122
|
+
expect(mockRequest).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
it("throws when payload is an empty string", async () => {
|
|
125
|
+
const mockRequest = jest.fn();
|
|
126
|
+
setupSuiMocks(mockRequest);
|
|
127
|
+
const { result } = renderHook(() => useSignTransaction());
|
|
128
|
+
await expect(
|
|
129
|
+
result.current.sui.signTransaction({
|
|
130
|
+
transaction: "",
|
|
131
|
+
address: CONNECTED_SUI_ADDRESS
|
|
132
|
+
})
|
|
133
|
+
).rejects.toThrow("No Sui transaction bytes provided");
|
|
134
|
+
expect(mockRequest).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe("useSignTransaction — signPSBT", () => {
|
|
138
|
+
it("forwards signInputs verbatim to btcWalletProvider.signPSBT", async () => {
|
|
139
|
+
const mockSignPSBT = jest.fn().mockResolvedValue({ psbt: "signed-psbt" });
|
|
140
|
+
mockUseAppKitProvider.mockImplementation((namespace) => {
|
|
141
|
+
if (namespace === "bip122") {
|
|
142
|
+
return { walletProvider: { signPSBT: mockSignPSBT } };
|
|
143
|
+
}
|
|
144
|
+
return { walletProvider: void 0 };
|
|
145
|
+
});
|
|
146
|
+
const { result } = renderHook(() => useSignTransaction());
|
|
147
|
+
const signInputs = [
|
|
148
|
+
{
|
|
149
|
+
address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
|
|
150
|
+
index: 0,
|
|
151
|
+
sighashTypes: [1]
|
|
152
|
+
}
|
|
153
|
+
];
|
|
154
|
+
const params = {
|
|
155
|
+
psbt: "base64psbt==",
|
|
156
|
+
signInputs: [...signInputs],
|
|
157
|
+
broadcast: false
|
|
158
|
+
};
|
|
159
|
+
const originalSignInputs = params.signInputs;
|
|
160
|
+
const psbt = await result.current.bitcoin.signTransaction(params);
|
|
161
|
+
expect(mockSignPSBT).toHaveBeenCalledWith(
|
|
162
|
+
expect.objectContaining({
|
|
163
|
+
signInputs: [
|
|
164
|
+
{
|
|
165
|
+
address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
|
|
166
|
+
index: 0,
|
|
167
|
+
sighashTypes: [1]
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
expect(mockSignPSBT).not.toHaveBeenCalledWith(
|
|
173
|
+
expect.objectContaining({ signInputs: [] })
|
|
174
|
+
);
|
|
175
|
+
expect(params.signInputs).toBe(originalSignInputs);
|
|
176
|
+
expect(params.signInputs).toEqual(signInputs);
|
|
177
|
+
expect(psbt).toBe("signed-psbt");
|
|
178
|
+
});
|
|
179
|
+
it("throws when btcWalletProvider is not available", async () => {
|
|
180
|
+
mockUseAppKitProvider.mockImplementation(
|
|
181
|
+
() => ({
|
|
182
|
+
walletProvider: void 0
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
const { result } = renderHook(() => useSignTransaction());
|
|
186
|
+
await expect(
|
|
187
|
+
result.current.bitcoin.signTransaction({
|
|
188
|
+
psbt: "base64psbt==",
|
|
189
|
+
signInputs: [],
|
|
190
|
+
broadcast: false
|
|
191
|
+
})
|
|
192
|
+
).rejects.toThrow("user is disconnected");
|
|
193
|
+
});
|
|
194
|
+
});
|
|
@@ -7,6 +7,7 @@ const yup = require("yup");
|
|
|
7
7
|
const reactjs_hooks_validation_useAmountSchema = require("./validation/useAmountSchema.js");
|
|
8
8
|
const reactjs_hooks_validation_useSecondAmountSchema = require("./validation/useSecondAmountSchema.js");
|
|
9
9
|
const api_confirmRate = require("../../api/confirmRate.js");
|
|
10
|
+
const helpers_assertRateConfirmationMatchesIntent = require("../../helpers/assertRateConfirmationMatchesIntent.js");
|
|
10
11
|
const helpers_getApiURL = require("../../helpers/getApiURL.js");
|
|
11
12
|
const types_providerType = require("../../types/providerType.js");
|
|
12
13
|
const reactjs_context_useWeb3App = require("../context/useWeb3App.js");
|
|
@@ -76,6 +77,10 @@ const useBridgeFormik = ({
|
|
|
76
77
|
pendingSigningRef.current = false;
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
80
|
+
helpers_assertRateConfirmationMatchesIntent.assertRateConfirmationMatchesIntent(
|
|
81
|
+
{ fromChainId: values.fromChainId ?? "", sender: sender ?? "" },
|
|
82
|
+
transactions
|
|
83
|
+
);
|
|
79
84
|
resetSwapForm();
|
|
80
85
|
onSubmit({
|
|
81
86
|
transactions,
|
|
@@ -4,6 +4,7 @@ import { object, string } from "yup";
|
|
|
4
4
|
import { useAmountSchema } from "./validation/useAmountSchema.mjs";
|
|
5
5
|
import { useSecondAmountSchema } from "./validation/useSecondAmountSchema.mjs";
|
|
6
6
|
import { confirmRate } from "../../api/confirmRate.mjs";
|
|
7
|
+
import { assertRateConfirmationMatchesIntent } from "../../helpers/assertRateConfirmationMatchesIntent.mjs";
|
|
7
8
|
import { getApiURL } from "../../helpers/getApiURL.mjs";
|
|
8
9
|
import { ProviderType } from "../../types/providerType.mjs";
|
|
9
10
|
import { useWeb3App } from "../context/useWeb3App.mjs";
|
|
@@ -73,6 +74,10 @@ const useBridgeFormik = ({
|
|
|
73
74
|
pendingSigningRef.current = false;
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
77
|
+
assertRateConfirmationMatchesIntent(
|
|
78
|
+
{ fromChainId: values.fromChainId ?? "", sender: sender ?? "" },
|
|
79
|
+
transactions
|
|
80
|
+
);
|
|
76
81
|
resetSwapForm();
|
|
77
82
|
onSubmit({
|
|
78
83
|
transactions,
|
|
@@ -17,6 +17,8 @@ const useFetchTokens = ({
|
|
|
17
17
|
const bridgeApiChainId = reactjs_hooks_useBridgeApiChainId.useBridgeApiChainId();
|
|
18
18
|
const account = reactjs_hooks_useAccount.useAccount();
|
|
19
19
|
const { nativeAuthToken, bridgeOnly } = reactjs_context_useWeb3App.useWeb3App();
|
|
20
|
+
const invalidateMvxTokensBalancesQuery = reactjs_queries_useGetMvxTokensBalances_query.useInvalidateMvxTokensBalancesQuery();
|
|
21
|
+
const invalidateEvmTokensBalances = reactjs_queries_useGetNonMvxTokensBalances_query.useInvalidateEvmTokensBalances();
|
|
20
22
|
const {
|
|
21
23
|
data: tokens,
|
|
22
24
|
isLoading: isTokensLoading,
|
|
@@ -90,14 +92,14 @@ const useFetchTokens = ({
|
|
|
90
92
|
}, [nonMvxTokens, nonMvxTokensBalances]);
|
|
91
93
|
React.useEffect(() => {
|
|
92
94
|
if (mvxAddress) {
|
|
93
|
-
|
|
95
|
+
invalidateMvxTokensBalancesQuery();
|
|
94
96
|
}
|
|
95
97
|
}, [refetchTrigger, mvxAddress]);
|
|
96
98
|
React.useEffect(() => {
|
|
97
99
|
if (!account.address) {
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
100
|
-
|
|
102
|
+
invalidateEvmTokensBalances();
|
|
101
103
|
}, [refetchTrigger, bridgeApiChainId, account.address]);
|
|
102
104
|
return {
|
|
103
105
|
isTokensLoading,
|
|
@@ -4,8 +4,8 @@ import { useBridgeApiChainId } from "./useBridgeApiChainId.mjs";
|
|
|
4
4
|
import { MVX_CHAIN_IDS } from "../../constants/index.mjs";
|
|
5
5
|
import { useWeb3App } from "../context/useWeb3App.mjs";
|
|
6
6
|
import { useGetAllTokensQuery } from "../queries/useGetAllTokens.query.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { useInvalidateMvxTokensBalancesQuery, useGetMvxTokensBalancesQuery } from "../queries/useGetMvxTokensBalances.query.mjs";
|
|
8
|
+
import { useInvalidateEvmTokensBalances, useGetNonMvxTokensBalancesQuery } from "../queries/useGetNonMvxTokensBalances.query.mjs";
|
|
9
9
|
const useFetchTokens = ({
|
|
10
10
|
mvxAddress,
|
|
11
11
|
mvxApiURL,
|
|
@@ -14,6 +14,8 @@ const useFetchTokens = ({
|
|
|
14
14
|
const bridgeApiChainId = useBridgeApiChainId();
|
|
15
15
|
const account = useAccount();
|
|
16
16
|
const { nativeAuthToken, bridgeOnly } = useWeb3App();
|
|
17
|
+
const invalidateMvxTokensBalancesQuery = useInvalidateMvxTokensBalancesQuery();
|
|
18
|
+
const invalidateEvmTokensBalances = useInvalidateEvmTokensBalances();
|
|
17
19
|
const {
|
|
18
20
|
data: tokens,
|
|
19
21
|
isLoading: isTokensLoading,
|
|
@@ -35,11 +35,31 @@ const useGenericSignMessage = () => {
|
|
|
35
35
|
throw new Error("Sui wallet not connected");
|
|
36
36
|
}
|
|
37
37
|
const encodedMessage = new TextEncoder().encode(message);
|
|
38
|
+
const params = {
|
|
39
|
+
message: Buffer.from(encodedMessage).toString("base64")
|
|
40
|
+
};
|
|
41
|
+
const MAX_SUI_MESSAGE_BYTES = 32 * 1024;
|
|
42
|
+
if (!params.message || typeof params.message !== "string") {
|
|
43
|
+
throw new Error(
|
|
44
|
+
"Invalid Sui message: payload must be a non-empty string"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const decoded = atob(params.message);
|
|
49
|
+
if (decoded.length > MAX_SUI_MESSAGE_BYTES) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Sui message payload exceeds maximum size of ${MAX_SUI_MESSAGE_BYTES} bytes`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
if (e instanceof Error && e.message.includes("maximum size")) {
|
|
56
|
+
throw e;
|
|
57
|
+
}
|
|
58
|
+
throw new Error("Invalid Sui message: payload is not valid base64");
|
|
59
|
+
}
|
|
38
60
|
const result = await suiWalletProvider.request({
|
|
39
61
|
method: "sui_signPersonalMessage",
|
|
40
|
-
params
|
|
41
|
-
message: Buffer.from(encodedMessage).toString("base64")
|
|
42
|
-
}
|
|
62
|
+
params
|
|
43
63
|
});
|
|
44
64
|
return result.signature;
|
|
45
65
|
}
|
|
@@ -32,11 +32,31 @@ const useGenericSignMessage = () => {
|
|
|
32
32
|
throw new Error("Sui wallet not connected");
|
|
33
33
|
}
|
|
34
34
|
const encodedMessage = new TextEncoder().encode(message);
|
|
35
|
+
const params = {
|
|
36
|
+
message: Buffer.from(encodedMessage).toString("base64")
|
|
37
|
+
};
|
|
38
|
+
const MAX_SUI_MESSAGE_BYTES = 32 * 1024;
|
|
39
|
+
if (!params.message || typeof params.message !== "string") {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"Invalid Sui message: payload must be a non-empty string"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const decoded = atob(params.message);
|
|
46
|
+
if (decoded.length > MAX_SUI_MESSAGE_BYTES) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Sui message payload exceeds maximum size of ${MAX_SUI_MESSAGE_BYTES} bytes`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
if (e instanceof Error && e.message.includes("maximum size")) {
|
|
53
|
+
throw e;
|
|
54
|
+
}
|
|
55
|
+
throw new Error("Invalid Sui message: payload is not valid base64");
|
|
56
|
+
}
|
|
35
57
|
const result = await suiWalletProvider.request({
|
|
36
58
|
method: "sui_signPersonalMessage",
|
|
37
|
-
params
|
|
38
|
-
message: Buffer.from(encodedMessage).toString("base64")
|
|
39
|
-
}
|
|
59
|
+
params
|
|
40
60
|
});
|
|
41
61
|
return result.signature;
|
|
42
62
|
}
|
|
@@ -15,6 +15,9 @@ const useSignTransaction = () => {
|
|
|
15
15
|
const { walletProvider: solWalletProvider } = react$1.useAppKitProvider("solana");
|
|
16
16
|
const { walletProvider: btcWalletProvider } = react$1.useAppKitProvider("bip122");
|
|
17
17
|
const { walletProvider: suiWalletProvider } = react$1.useAppKitProvider("sui");
|
|
18
|
+
const { address: suiAddress } = react$1.useAppKitAccount({
|
|
19
|
+
namespace: "sui"
|
|
20
|
+
});
|
|
18
21
|
const signTransactionSolanaTransaction = async ({
|
|
19
22
|
feePayer,
|
|
20
23
|
instructions,
|
|
@@ -36,7 +39,6 @@ const useSignTransaction = () => {
|
|
|
36
39
|
if (!btcWalletProvider) {
|
|
37
40
|
throw Error("user is disconnected");
|
|
38
41
|
}
|
|
39
|
-
params.signInputs = [];
|
|
40
42
|
const signature = await btcWalletProvider.signPSBT(params);
|
|
41
43
|
return signature.psbt;
|
|
42
44
|
};
|
|
@@ -51,6 +53,30 @@ const useSignTransaction = () => {
|
|
|
51
53
|
if (!suiWalletProvider) {
|
|
52
54
|
throw new Error("Sui wallet not connected");
|
|
53
55
|
}
|
|
56
|
+
const MAX_SUI_PAYLOAD_BYTES = 32 * 1024;
|
|
57
|
+
if (!transaction || typeof transaction !== "string") {
|
|
58
|
+
throw new Error(
|
|
59
|
+
"Invalid Sui transaction: payload must be a non-empty string"
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const decoded = atob(transaction);
|
|
64
|
+
if (decoded.length > MAX_SUI_PAYLOAD_BYTES) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Sui transaction payload exceeds maximum size of ${MAX_SUI_PAYLOAD_BYTES} bytes`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
if (e instanceof Error && e.message.includes("maximum size")) {
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
73
|
+
throw new Error("Invalid Sui transaction: payload is not valid base64");
|
|
74
|
+
}
|
|
75
|
+
if (suiParams.address && suiAddress && suiParams.address !== suiAddress) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Sui address mismatch: expected ${suiAddress}, got ${suiParams.address}`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
54
80
|
const result = await suiWalletProvider.request({
|
|
55
81
|
method: "sui_signTransaction",
|
|
56
82
|
params: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useAppKitProvider } from "@reown/appkit/react";
|
|
1
|
+
import { useAppKitProvider, useAppKitAccount } from "@reown/appkit/react";
|
|
2
2
|
import { useAppKitConnection } from "@reown/appkit-adapter-solana/react";
|
|
3
3
|
import { TransactionInstruction, Transaction, PublicKey } from "@solana/web3.js";
|
|
4
4
|
import { useSendTransaction } from "wagmi";
|
|
@@ -12,6 +12,9 @@ const useSignTransaction = () => {
|
|
|
12
12
|
const { walletProvider: solWalletProvider } = useAppKitProvider("solana");
|
|
13
13
|
const { walletProvider: btcWalletProvider } = useAppKitProvider("bip122");
|
|
14
14
|
const { walletProvider: suiWalletProvider } = useAppKitProvider("sui");
|
|
15
|
+
const { address: suiAddress } = useAppKitAccount({
|
|
16
|
+
namespace: "sui"
|
|
17
|
+
});
|
|
15
18
|
const signTransactionSolanaTransaction = async ({
|
|
16
19
|
feePayer,
|
|
17
20
|
instructions,
|
|
@@ -33,7 +36,6 @@ const useSignTransaction = () => {
|
|
|
33
36
|
if (!btcWalletProvider) {
|
|
34
37
|
throw Error("user is disconnected");
|
|
35
38
|
}
|
|
36
|
-
params.signInputs = [];
|
|
37
39
|
const signature = await btcWalletProvider.signPSBT(params);
|
|
38
40
|
return signature.psbt;
|
|
39
41
|
};
|
|
@@ -48,6 +50,30 @@ const useSignTransaction = () => {
|
|
|
48
50
|
if (!suiWalletProvider) {
|
|
49
51
|
throw new Error("Sui wallet not connected");
|
|
50
52
|
}
|
|
53
|
+
const MAX_SUI_PAYLOAD_BYTES = 32 * 1024;
|
|
54
|
+
if (!transaction || typeof transaction !== "string") {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Invalid Sui transaction: payload must be a non-empty string"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const decoded = atob(transaction);
|
|
61
|
+
if (decoded.length > MAX_SUI_PAYLOAD_BYTES) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Sui transaction payload exceeds maximum size of ${MAX_SUI_PAYLOAD_BYTES} bytes`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if (e instanceof Error && e.message.includes("maximum size")) {
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
throw new Error("Invalid Sui transaction: payload is not valid base64");
|
|
71
|
+
}
|
|
72
|
+
if (suiParams.address && suiAddress && suiParams.address !== suiAddress) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Sui address mismatch: expected ${suiAddress}, got ${suiParams.address}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
51
77
|
const result = await suiWalletProvider.request({
|
|
52
78
|
method: "sui_signTransaction",
|
|
53
79
|
params: {
|
package/reactjs/index.js
CHANGED
|
@@ -123,12 +123,12 @@ exports.SuiMethods = reactjs_init_init.SuiMethods;
|
|
|
123
123
|
exports.init = reactjs_init_init.init;
|
|
124
124
|
exports.useGetAllTokensQuery = reactjs_queries_useGetAllTokens_query.useGetAllTokensQuery;
|
|
125
125
|
exports.useGetChainsQuery = reactjs_queries_useGetChains_query.useGetChainsQuery;
|
|
126
|
-
exports.invalidateEvmTokensBalances = reactjs_queries_useGetNonMvxTokensBalances_query.invalidateEvmTokensBalances;
|
|
127
126
|
exports.useGetNonMvxTokensBalancesQuery = reactjs_queries_useGetNonMvxTokensBalances_query.useGetNonMvxTokensBalancesQuery;
|
|
128
|
-
exports.
|
|
127
|
+
exports.useInvalidateEvmTokensBalances = reactjs_queries_useGetNonMvxTokensBalances_query.useInvalidateEvmTokensBalances;
|
|
129
128
|
exports.useGetHistoryQuery = reactjs_queries_useGetHistory_query.useGetHistoryQuery;
|
|
130
|
-
exports.
|
|
129
|
+
exports.useInvalidateHistoryQuery = reactjs_queries_useGetHistory_query.useInvalidateHistoryQuery;
|
|
131
130
|
exports.useGetMvxTokensBalancesQuery = reactjs_queries_useGetMvxTokensBalances_query.useGetMvxTokensBalancesQuery;
|
|
131
|
+
exports.useInvalidateMvxTokensBalancesQuery = reactjs_queries_useGetMvxTokensBalances_query.useInvalidateMvxTokensBalancesQuery;
|
|
132
132
|
exports.useGetRateMutation = reactjs_queries_useGetRate_mutation.useGetRateMutation;
|
|
133
133
|
exports.delay = reactjs_utils_delay.delay;
|
|
134
134
|
exports.formatAmount = reactjs_utils_formatAmount.formatAmount;
|
package/reactjs/index.mjs
CHANGED
|
@@ -48,9 +48,9 @@ import { useSuiConnect } from "./hooks/useSuiConnect.mjs";
|
|
|
48
48
|
import { SuiMethods, init } from "./init/init.mjs";
|
|
49
49
|
import { useGetAllTokensQuery } from "./queries/useGetAllTokens.query.mjs";
|
|
50
50
|
import { useGetChainsQuery } from "./queries/useGetChains.query.mjs";
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
51
|
+
import { useGetNonMvxTokensBalancesQuery, useInvalidateEvmTokensBalances } from "./queries/useGetNonMvxTokensBalances.query.mjs";
|
|
52
|
+
import { useGetHistoryQuery, useInvalidateHistoryQuery } from "./queries/useGetHistory.query.mjs";
|
|
53
|
+
import { useGetMvxTokensBalancesQuery, useInvalidateMvxTokensBalancesQuery } from "./queries/useGetMvxTokensBalances.query.mjs";
|
|
54
54
|
import { useGetRateMutation } from "./queries/useGetRate.mutation.mjs";
|
|
55
55
|
import { delay } from "./utils/delay.mjs";
|
|
56
56
|
import { formatAmount } from "./utils/formatAmount.mjs";
|
|
@@ -109,9 +109,6 @@ export {
|
|
|
109
109
|
getQueryClient,
|
|
110
110
|
hasEnoughFunds,
|
|
111
111
|
init,
|
|
112
|
-
invalidateEvmTokensBalances,
|
|
113
|
-
invalidateHistoryQuery,
|
|
114
|
-
invalidateMvxTokensBalancesQuery,
|
|
115
112
|
isStringFloat,
|
|
116
113
|
mxClsx,
|
|
117
114
|
pipe,
|
|
@@ -144,6 +141,9 @@ export {
|
|
|
144
141
|
useGetMvxTokensBalancesQuery,
|
|
145
142
|
useGetNonMvxTokensBalancesQuery,
|
|
146
143
|
useGetRateMutation,
|
|
144
|
+
useInvalidateEvmTokensBalances,
|
|
145
|
+
useInvalidateHistoryQuery,
|
|
146
|
+
useInvalidateMvxTokensBalancesQuery,
|
|
147
147
|
useResolveTokenChain,
|
|
148
148
|
useSecondAmountSchema,
|
|
149
149
|
useSendTransactions,
|
package/reactjs/init/init.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type InitOptions = {
|
|
|
14
14
|
mvxChainId: '31' | '44' | '54';
|
|
15
15
|
suiEnvironment?: 'mainnet' | 'testnet' | 'devnet';
|
|
16
16
|
suiFeaturedWalletIds?: string[];
|
|
17
|
+
expectedSuiAddress?: string;
|
|
17
18
|
};
|
|
18
19
|
export declare enum SuiMethods {
|
|
19
20
|
SIGN_TRANSACTION = "sui_signTransaction",
|
package/reactjs/init/init.js
CHANGED
|
@@ -82,7 +82,7 @@ var SuiMethods = /* @__PURE__ */ ((SuiMethods2) => {
|
|
|
82
82
|
return SuiMethods2;
|
|
83
83
|
})(SuiMethods || {});
|
|
84
84
|
async function init(options) {
|
|
85
|
-
var _a, _b, _c, _d;
|
|
85
|
+
var _a, _b, _c, _d, _e;
|
|
86
86
|
const store = store_inMemoryStore.InMemoryStore.getInstance();
|
|
87
87
|
store.setItem("apiURL", options.apiURL);
|
|
88
88
|
store.setItem("bridgeURL", options.bridgeURL);
|
|
@@ -114,7 +114,12 @@ async function init(options) {
|
|
|
114
114
|
if (options.suiEnvironment) {
|
|
115
115
|
const suiNetwork = suiNetworkDefinitions[options.suiEnvironment];
|
|
116
116
|
const explicitSuiCaip = suiNetwork.caipNetworkId ?? `sui:${suiNetwork.id}`;
|
|
117
|
-
adapters.push(
|
|
117
|
+
adapters.push(
|
|
118
|
+
new reactjs_adapters_SuiAdapter.SuiAdapter({
|
|
119
|
+
explicitCaipChains: [explicitSuiCaip],
|
|
120
|
+
expectedSuiAddress: options.expectedSuiAddress
|
|
121
|
+
})
|
|
122
|
+
);
|
|
118
123
|
}
|
|
119
124
|
const appKit = react.createAppKit({
|
|
120
125
|
...options.appKitOptions,
|
|
@@ -126,7 +131,10 @@ async function init(options) {
|
|
|
126
131
|
const wc = await appKit.getUniversalProvider();
|
|
127
132
|
const suiNs = (_b = (_a = wc == null ? void 0 : wc.session) == null ? void 0 : _a.namespaces) == null ? void 0 : _b["sui"];
|
|
128
133
|
if (((_c = suiNs == null ? void 0 : suiNs.accounts) == null ? void 0 : _c.length) && !appKit.getCaipAddress("sui")) {
|
|
129
|
-
|
|
134
|
+
const firstSuiAddress = (_d = suiNs.accounts[0]) == null ? void 0 : _d.split(":").pop();
|
|
135
|
+
if (!options.expectedSuiAddress || firstSuiAddress === options.expectedSuiAddress) {
|
|
136
|
+
await ((_e = appKit.syncWalletConnectAccount) == null ? void 0 : _e.call(appKit));
|
|
137
|
+
}
|
|
130
138
|
}
|
|
131
139
|
}
|
|
132
140
|
return {
|
package/reactjs/init/init.mjs
CHANGED
|
@@ -62,7 +62,7 @@ var SuiMethods = /* @__PURE__ */ ((SuiMethods2) => {
|
|
|
62
62
|
return SuiMethods2;
|
|
63
63
|
})(SuiMethods || {});
|
|
64
64
|
async function init(options) {
|
|
65
|
-
var _a, _b, _c, _d;
|
|
65
|
+
var _a, _b, _c, _d, _e;
|
|
66
66
|
const store = InMemoryStore.getInstance();
|
|
67
67
|
store.setItem("apiURL", options.apiURL);
|
|
68
68
|
store.setItem("bridgeURL", options.bridgeURL);
|
|
@@ -94,7 +94,12 @@ async function init(options) {
|
|
|
94
94
|
if (options.suiEnvironment) {
|
|
95
95
|
const suiNetwork = suiNetworkDefinitions[options.suiEnvironment];
|
|
96
96
|
const explicitSuiCaip = suiNetwork.caipNetworkId ?? `sui:${suiNetwork.id}`;
|
|
97
|
-
adapters.push(
|
|
97
|
+
adapters.push(
|
|
98
|
+
new SuiAdapter({
|
|
99
|
+
explicitCaipChains: [explicitSuiCaip],
|
|
100
|
+
expectedSuiAddress: options.expectedSuiAddress
|
|
101
|
+
})
|
|
102
|
+
);
|
|
98
103
|
}
|
|
99
104
|
const appKit = createAppKit({
|
|
100
105
|
...options.appKitOptions,
|
|
@@ -106,7 +111,10 @@ async function init(options) {
|
|
|
106
111
|
const wc = await appKit.getUniversalProvider();
|
|
107
112
|
const suiNs = (_b = (_a = wc == null ? void 0 : wc.session) == null ? void 0 : _a.namespaces) == null ? void 0 : _b["sui"];
|
|
108
113
|
if (((_c = suiNs == null ? void 0 : suiNs.accounts) == null ? void 0 : _c.length) && !appKit.getCaipAddress("sui")) {
|
|
109
|
-
|
|
114
|
+
const firstSuiAddress = (_d = suiNs.accounts[0]) == null ? void 0 : _d.split(":").pop();
|
|
115
|
+
if (!options.expectedSuiAddress || firstSuiAddress === options.expectedSuiAddress) {
|
|
116
|
+
await ((_e = appKit.syncWalletConnectAccount) == null ? void 0 : _e.call(appKit));
|
|
117
|
+
}
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
return {
|
package/reactjs/queries/index.js
CHANGED
|
@@ -9,10 +9,10 @@ const reactjs_queries_useGetMvxTokensBalances_query = require("./useGetMvxTokens
|
|
|
9
9
|
const reactjs_queries_useGetRate_mutation = require("./useGetRate.mutation.js");
|
|
10
10
|
exports.useGetAllTokensQuery = reactjs_queries_useGetAllTokens_query.useGetAllTokensQuery;
|
|
11
11
|
exports.useGetChainsQuery = reactjs_queries_useGetChains_query.useGetChainsQuery;
|
|
12
|
-
exports.invalidateEvmTokensBalances = reactjs_queries_useGetNonMvxTokensBalances_query.invalidateEvmTokensBalances;
|
|
13
12
|
exports.useGetNonMvxTokensBalancesQuery = reactjs_queries_useGetNonMvxTokensBalances_query.useGetNonMvxTokensBalancesQuery;
|
|
14
|
-
exports.
|
|
13
|
+
exports.useInvalidateEvmTokensBalances = reactjs_queries_useGetNonMvxTokensBalances_query.useInvalidateEvmTokensBalances;
|
|
15
14
|
exports.useGetHistoryQuery = reactjs_queries_useGetHistory_query.useGetHistoryQuery;
|
|
16
|
-
exports.
|
|
15
|
+
exports.useInvalidateHistoryQuery = reactjs_queries_useGetHistory_query.useInvalidateHistoryQuery;
|
|
17
16
|
exports.useGetMvxTokensBalancesQuery = reactjs_queries_useGetMvxTokensBalances_query.useGetMvxTokensBalancesQuery;
|
|
17
|
+
exports.useInvalidateMvxTokensBalancesQuery = reactjs_queries_useGetMvxTokensBalances_query.useInvalidateMvxTokensBalancesQuery;
|
|
18
18
|
exports.useGetRateMutation = reactjs_queries_useGetRate_mutation.useGetRateMutation;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { useGetAllTokensQuery } from "./useGetAllTokens.query.mjs";
|
|
2
2
|
import { useGetChainsQuery } from "./useGetChains.query.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { useGetNonMvxTokensBalancesQuery, useInvalidateEvmTokensBalances } from "./useGetNonMvxTokensBalances.query.mjs";
|
|
4
|
+
import { useGetHistoryQuery, useInvalidateHistoryQuery } from "./useGetHistory.query.mjs";
|
|
5
|
+
import { useGetMvxTokensBalancesQuery, useInvalidateMvxTokensBalancesQuery } from "./useGetMvxTokensBalances.query.mjs";
|
|
6
6
|
import { useGetRateMutation } from "./useGetRate.mutation.mjs";
|
|
7
7
|
export {
|
|
8
|
-
invalidateEvmTokensBalances,
|
|
9
|
-
invalidateHistoryQuery,
|
|
10
|
-
invalidateMvxTokensBalancesQuery,
|
|
11
8
|
useGetAllTokensQuery,
|
|
12
9
|
useGetChainsQuery,
|
|
13
10
|
useGetHistoryQuery,
|
|
14
11
|
useGetMvxTokensBalancesQuery,
|
|
15
12
|
useGetNonMvxTokensBalancesQuery,
|
|
16
|
-
useGetRateMutation
|
|
13
|
+
useGetRateMutation,
|
|
14
|
+
useInvalidateEvmTokensBalances,
|
|
15
|
+
useInvalidateHistoryQuery,
|
|
16
|
+
useInvalidateMvxTokensBalancesQuery
|
|
17
17
|
};
|
|
@@ -29,7 +29,7 @@ const useCheckAccountQuery = () => {
|
|
|
29
29
|
return ((_a = error.response) == null ? void 0 : _a.status) === 404;
|
|
30
30
|
};
|
|
31
31
|
return reactQuery.useQuery({
|
|
32
|
-
queryKey: ["check-account", address, bridgeApiChainId
|
|
32
|
+
queryKey: ["check-account", address, bridgeApiChainId],
|
|
33
33
|
queryFn,
|
|
34
34
|
retry,
|
|
35
35
|
refetchOnWindowFocus: false,
|
|
@@ -26,7 +26,7 @@ const useCheckAccountQuery = () => {
|
|
|
26
26
|
return ((_a = error.response) == null ? void 0 : _a.status) === 404;
|
|
27
27
|
};
|
|
28
28
|
return useQuery({
|
|
29
|
-
queryKey: ["check-account", address, bridgeApiChainId
|
|
29
|
+
queryKey: ["check-account", address, bridgeApiChainId],
|
|
30
30
|
queryFn,
|
|
31
31
|
retry,
|
|
32
32
|
refetchOnWindowFocus: false,
|
|
@@ -25,7 +25,7 @@ const useGetAllTokensQuery = ({
|
|
|
25
25
|
return ((_a = error.response) == null ? void 0 : _a.status) === 404;
|
|
26
26
|
};
|
|
27
27
|
return reactQuery.useQuery({
|
|
28
|
-
queryKey: ["all-tokens",
|
|
28
|
+
queryKey: ["all-tokens", bridgeOnly],
|
|
29
29
|
queryFn,
|
|
30
30
|
retry,
|
|
31
31
|
refetchOnWindowFocus: false,
|
|
@@ -22,7 +22,7 @@ const useGetAllTokensQuery = ({
|
|
|
22
22
|
return ((_a = error.response) == null ? void 0 : _a.status) === 404;
|
|
23
23
|
};
|
|
24
24
|
return useQuery({
|
|
25
|
-
queryKey: ["all-tokens",
|
|
25
|
+
queryKey: ["all-tokens", bridgeOnly],
|
|
26
26
|
queryFn,
|
|
27
27
|
retry,
|
|
28
28
|
refetchOnWindowFocus: false,
|