-
Notifications
You must be signed in to change notification settings - Fork 588
Expand file tree
/
Copy pathwallet-prefill-provider.ts
More file actions
68 lines (57 loc) · 2.86 KB
/
wallet-prefill-provider.ts
File metadata and controls
68 lines (57 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import type { InstructionData } from '@entities/idl';
import { PublicKey } from '@solana/web3.js';
import type { MutableRefObject } from 'react';
import type { FieldPath, UseFormReturn } from 'react-hook-form';
import type { FormValue, InstructionFormData, InstructionFormFieldNames } from '../../use-instruction-form';
import { isPrefilledAccount, WALLET_ACCOUNT_PATTERNS } from '../const';
import { traverseInstructionAccounts } from './traverse-accounts';
/**
* Creates a wallet prefill dependency that automatically fills signer accounts
* with the wallet's public key when the wallet connects or changes.
*/
export function createWalletPrefillDependency(
instruction: InstructionData,
fieldNames: Pick<InstructionFormFieldNames, 'account'>,
lastPrefillAddressRef: MutableRefObject<string | undefined>,
): { onValueChange: (value: unknown, form: UseFormReturn<InstructionFormData>) => void } {
const signerPaths: FieldPath<InstructionFormData>[] = [];
traverseInstructionAccounts(instruction, (account, parentGroup) => {
// Skip accounts that have known addresses (e.g., system program, token program)
if (isPrefilledAccount(account.name)) {
return;
}
const normalizedName = account.name.toLowerCase().trim();
const isWalletAccount = WALLET_ACCOUNT_PATTERNS.some(p => normalizedName === p.toLowerCase());
// Prefill wallet address for:
// - signer accounts (user needs to sign)
// - accounts matching wallet patterns (e.g., authority)
// - writable accounts that are not PDAs (likely owned/controlled by the user)
const shouldPrefill = account.signer || isWalletAccount || (account.writable && !account.pda);
if (shouldPrefill) {
if (parentGroup) {
signerPaths.push(fieldNames.account(parentGroup, account));
} else {
signerPaths.push(fieldNames.account(account));
}
}
});
return {
onValueChange: (value: unknown, form: UseFormReturn<InstructionFormData>) => {
if (!value || !(value instanceof PublicKey)) return;
const walletAddress = value.toBase58();
const lastPrefillAddress = lastPrefillAddressRef.current;
for (const path of signerPaths) {
const currentValue = String(form.getValues(path) ?? '').trim();
const isEmpty = currentValue === '';
const hasPreviousWallet = lastPrefillAddress !== undefined && currentValue === lastPrefillAddress;
if (isEmpty || hasPreviousWallet) {
form.setValue(path, walletAddress as unknown as FormValue, {
shouldDirty: false,
shouldValidate: false,
});
}
}
lastPrefillAddressRef.current = walletAddress;
},
};
}