Skip to content

Commit 361818a

Browse files
authored
[dapp-kit] execute from dApp rather than wallet when using useSignAndExecuteTransactionBlock (#14200)
## Description Describe the changes or additions included in this PR. ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes
1 parent 9a89ca6 commit 361818a

File tree

4 files changed

+61
-17
lines changed

4 files changed

+61
-17
lines changed

.changeset/dull-dryers-smash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@mysten/dapp-kit': minor
3+
---
4+
5+
execute transaction from dApp rather than wallet in useSignAndExecuteTransactionBlock

sdk/dapp-kit/src/hooks/wallet/useSignAndExecuteTransactionBlock.ts

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
WalletNotConnectedError,
1616
} from '../../errors/walletErrors.js';
1717
import type { PartialBy } from '../../types/utilityTypes.js';
18+
import { useSuiClient } from '../useSuiClient.js';
1819
import { useCurrentAccount } from './useCurrentAccount.js';
1920
import { useCurrentWallet } from './useCurrentWallet.js';
2021

@@ -39,43 +40,71 @@ type UseSignAndExecuteTransactionBlockMutationOptions = Omit<
3940
unknown
4041
>,
4142
'mutationFn'
42-
>;
43+
> & {
44+
executeFromWallet?: boolean;
45+
};
4346

4447
/**
4548
* Mutation hook for prompting the user to sign and execute a transaction block.
4649
*/
4750
export function useSignAndExecuteTransactionBlock({
4851
mutationKey,
52+
executeFromWallet,
4953
...mutationOptions
5054
}: UseSignAndExecuteTransactionBlockMutationOptions = {}) {
5155
const currentWallet = useCurrentWallet();
5256
const currentAccount = useCurrentAccount();
57+
const client = useSuiClient();
5358

5459
return useMutation({
5560
mutationKey: walletMutationKeys.signAndExecuteTransactionBlock(mutationKey),
56-
mutationFn: async (signAndExecuteTransactionBlockArgs) => {
61+
mutationFn: async ({ requestType, options, ...signTransactionBlockArgs }) => {
5762
if (!currentWallet) {
5863
throw new WalletNotConnectedError('No wallet is connected.');
5964
}
6065

61-
const signerAccount = signAndExecuteTransactionBlockArgs.account ?? currentAccount;
66+
const signerAccount = signTransactionBlockArgs.account ?? currentAccount;
6267
if (!signerAccount) {
6368
throw new WalletNoAccountSelectedError(
6469
'No wallet account is selected to sign and execute the transaction block with.',
6570
);
6671
}
6772

68-
const walletFeature = currentWallet.features['sui:signAndExecuteTransactionBlock'];
73+
if (executeFromWallet) {
74+
const walletFeature = currentWallet.features['sui:signAndExecuteTransactionBlock'];
75+
if (!walletFeature) {
76+
throw new WalletFeatureNotSupportedError(
77+
"This wallet doesn't support the `signAndExecuteTransactionBlock` feature.",
78+
);
79+
}
80+
81+
return walletFeature.signAndExecuteTransactionBlock({
82+
...signTransactionBlockArgs,
83+
account: signerAccount,
84+
chain: signTransactionBlockArgs.chain ?? signerAccount.chains[0],
85+
requestType,
86+
options,
87+
});
88+
}
89+
90+
const walletFeature = currentWallet.features['sui:signTransactionBlock'];
6991
if (!walletFeature) {
7092
throw new WalletFeatureNotSupportedError(
71-
"This wallet doesn't support the `signAndExecuteTransactionBlock` feature.",
93+
"This wallet doesn't support the `signTransactionBlock` feature.",
7294
);
7395
}
7496

75-
return await walletFeature.signAndExecuteTransactionBlock({
76-
...signAndExecuteTransactionBlockArgs,
97+
const { signature, transactionBlockBytes } = await walletFeature.signTransactionBlock({
98+
...signTransactionBlockArgs,
7799
account: signerAccount,
78-
chain: signAndExecuteTransactionBlockArgs.chain ?? signerAccount.chains[0],
100+
chain: signTransactionBlockArgs.chain ?? signerAccount.chains[0],
101+
});
102+
103+
return client.executeTransactionBlock({
104+
transactionBlock: transactionBlockBytes,
105+
signature,
106+
requestType,
107+
options,
79108
});
80109
},
81110
...mutationOptions,

sdk/dapp-kit/test/hooks/useSignAndExecuteTransactionBlock.test.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Mysten Labs, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client';
45
import { TransactionBlock } from '@mysten/sui.js/transactions';
56
import { act, renderHook, waitFor } from '@testing-library/react';
67
import type { Mock } from 'vitest';
@@ -59,7 +60,12 @@ describe('useSignAndExecuteTransactionBlock', () => {
5960
features: suiFeatures,
6061
});
6162

62-
const wrapper = createWalletProviderContextWrapper();
63+
const suiClient = new SuiClient({ url: getFullnodeUrl('localnet') });
64+
const executeTransactionBlock = vi.spyOn(suiClient, 'executeTransactionBlock');
65+
66+
executeTransactionBlock.mockReturnValueOnce(Promise.resolve({ digest: '123' }));
67+
68+
const wrapper = createWalletProviderContextWrapper({}, suiClient);
6369
const { result } = renderHook(
6470
() => ({
6571
connectWallet: useConnectWallet(),
@@ -72,13 +78,12 @@ describe('useSignAndExecuteTransactionBlock', () => {
7278

7379
await waitFor(() => expect(result.current.connectWallet.isSuccess).toBe(true));
7480

75-
const useSignAndExecuteTransactionBlockFeature =
76-
mockWallet.features['sui:signAndExecuteTransactionBlock'];
77-
const useSignAndExecuteTransactionBlockMock = useSignAndExecuteTransactionBlockFeature!
78-
.signAndExecuteTransactionBlock as Mock;
81+
const signTransactionBlockFeature = mockWallet.features['sui:signTransactionBlock'];
82+
const signTransactionBlockMock = signTransactionBlockFeature!.signTransactionBlock as Mock;
7983

80-
useSignAndExecuteTransactionBlockMock.mockReturnValueOnce({
81-
digest: '123',
84+
signTransactionBlockMock.mockReturnValueOnce({
85+
transactionBlockBytes: 'abc',
86+
signature: '123',
8287
});
8388

8489
result.current.useSignAndExecuteTransactionBlock.mutate({
@@ -92,6 +97,10 @@ describe('useSignAndExecuteTransactionBlock', () => {
9297
expect(result.current.useSignAndExecuteTransactionBlock.data).toStrictEqual({
9398
digest: '123',
9499
});
100+
expect(suiClient.executeTransactionBlock).toHaveBeenCalledWith({
101+
transactionBlock: 'abc',
102+
signature: '123',
103+
});
95104

96105
act(() => unregister());
97106
});

sdk/dapp-kit/test/test-utils.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Mysten Labs, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import type { SuiClient } from '@mysten/sui.js/client';
4+
import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client';
55
import type { IdentifierRecord, ReadonlyWalletAccount } from '@mysten/wallet-standard';
66
import { getWallets } from '@mysten/wallet-standard';
77
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -20,11 +20,12 @@ export function createSuiClientContextWrapper(client: SuiClient) {
2020

2121
export function createWalletProviderContextWrapper(
2222
providerProps: Omit<ComponentProps<typeof WalletProvider>, 'children'> = {},
23+
suiClient: SuiClient = new SuiClient({ url: getFullnodeUrl('localnet') }),
2324
) {
2425
const queryClient = new QueryClient();
2526
return function WalletProviderContextWrapper({ children }: { children: React.ReactNode }) {
2627
return (
27-
<SuiClientProvider>
28+
<SuiClientProvider networks={{ test: suiClient }}>
2829
<QueryClientProvider client={queryClient}>
2930
<WalletProvider {...providerProps}>{children}</WalletProvider>;
3031
</QueryClientProvider>

0 commit comments

Comments
 (0)