How to integrate wallet connection in React frontends using @aptos-labs/wallet-adapter-react. Covers AptosWalletAdapterProvider setup, useWallet() hook, frontend transaction submission, and wallet connection UI. Triggers on: 'wallet adapter', 'connect wallet', 'useWallet', 'AptosWalletAdapterProvider', 'wallet-adapter-react', 'wallet connection'.
71
89%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Guide wallet connection and frontend transaction submission in React using @aptos-labs/wallet-adapter-react. End users sign transactions via their browser wallet (Petra, Nightly, etc.) — never via raw private keys.
@aptos-labs/wallet-adapter-react for frontend wallet integration — this is the standard React adapter.AptosWalletAdapterProvider — all useWallet() calls require this context.useWallet() hook to access wallet functions in React components.signAndSubmitTransaction (from useWallet()) in frontend — NOT the SDK's direct aptos.signAndSubmitTransaction.aptos.waitForTransaction({ transactionHash }) after submit — the wallet returns when the tx is accepted, not committed.Account.generate() or raw private keys in browser/frontend — use wallet adapter for end users.aptos.signAndSubmitTransaction in React components — use the wallet adapter's version from useWallet().wallets array from useWallet() for a dynamic list.npm install @aptos-labs/wallet-adapter-reactModern AIP-62 standard wallets (Petra, Nightly, etc.) are autodetected and do NOT require additional packages. Legacy wallets need their plugin package installed separately.
Wrap your app root with AptosWalletAdapterProvider:
// main.tsx or App.tsx
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";
import { Network } from "@aptos-labs/ts-sdk";
function App() {
return (
<AptosWalletAdapterProvider
autoConnect={true}
dappConfig={{
network: Network.TESTNET,
}}
onError={(error) => console.error("Wallet error:", error)}
>
<YourApp />
</AptosWalletAdapterProvider>
);
}import { useWallet } from "@aptos-labs/wallet-adapter-react";
function MyComponent() {
const {
account, // Current connected account { address, publicKey }
connected, // Boolean: is wallet connected?
wallet, // Current wallet info { name, icon, url }
wallets, // Array of available wallets
connect, // (walletName) => Promise<void>
disconnect, // () => Promise<void>
signAndSubmitTransaction, // Submit entry function calls (use THIS in frontend)
signTransaction, // Sign without submitting
submitTransaction, // Submit a signed transaction
signMessage, // Sign an arbitrary message
signMessageAndVerify, // Sign and verify a message
changeNetwork, // Switch networks (not all wallets support this)
network, // Current network info
} = useWallet();
}Use typed payloads with InputTransactionData:
// entry-functions/increment.ts
import { InputTransactionData } from "@aptos-labs/wallet-adapter-react";
import { MODULE_ADDRESS } from "../lib/aptos";
export function buildIncrementPayload(): InputTransactionData {
return {
data: {
function: `${MODULE_ADDRESS}::counter::increment`,
functionArguments: [],
},
};
}// components/IncrementButton.tsx
import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { aptos } from "../lib/aptos";
import { buildIncrementPayload } from "../entry-functions/increment";
function IncrementButton() {
const { signAndSubmitTransaction } = useWallet();
const handleClick = async () => {
try {
const response = await signAndSubmitTransaction(buildIncrementPayload());
await aptos.waitForTransaction({
transactionHash: response.hash,
});
} catch (error) {
console.error("Transaction failed:", error);
}
};
return <button onClick={handleClick}>Increment</button>;
}import { useWallet } from "@aptos-labs/wallet-adapter-react";
function WalletInfo() {
const { account, connected, connect, disconnect, wallet, wallets } = useWallet();
if (!connected) {
return (
<div>
{wallets.map((w) => (
<button key={w.name} onClick={() => connect(w.name)}>
Connect {w.name}
</button>
))}
</div>
);
}
return (
<div>
<p>Connected: {account?.address}</p>
<p>Wallet: {wallet?.name}</p>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}| Mistake | Correct approach |
|---|---|
Missing AptosWalletAdapterProvider wrapper | Wrap app root with the provider |
| Not waiting for transaction after submit | Always call aptos.waitForTransaction() |
Using SDK aptos.signAndSubmitTransaction in React | Use the wallet adapter's signAndSubmitTransaction from useWallet() |
Using Account.generate() in frontend | Use wallet adapter; generate only in server/scripts |
| Not handling user rejection | Catch and check for rejection-related error messages |
| Hardcoding wallet names | Use wallets array from useWallet() for dynamic list |
919362b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.