Skip to main content

Migration Guide: Scaffold-Stark v2 โ†’ v3

This guide covers the breaking changes when migrating from Scaffold-Stark v2 (using @starknet-react/core) to Scaffold-Stark v3 (using @starknet-start/react).

Package Changesโ€‹

Update your imports across the codebase:

Old PackageNew Package
@starknet-react/core@starknet-start/react
@starknet-react/chains@starknet-start/chains
# Example: find and replace in your project
grep -r "@starknet-react/core" --include="*.ts" --include="*.tsx" -l
grep -r "@starknet-react/chains" --include="*.ts" --include="*.tsx" -l

Wallet Connectionโ€‹

Before (v2): Wallets were configured manually using connector classes like InjectedConnector.

After (v3): Wallets are auto-discovered via the wallet standard (get-starknet). No manual connector setup is needed for standard wallets.

Hook Changesโ€‹

useAccountโ€‹

The useAccount hook no longer returns an account: AccountInterface object.

// v2
const { account, address, status } = useAccount();
// account was an AccountInterface instance

// v3
const { address, status, chainId, connector } = useAccount();
// No account object โ€” use address and other fields directly

useScaffoldContractโ€‹

The hook no longer accepts an account parameter. It returns a read-only contract instance.

// v2
import { useAccount } from "@starknet-react/core";
const { account } = useAccount();
const { data: contract } = useScaffoldContract({
contractName: "YourContract",
account, // No longer supported
});
await contract?.write.setGreeting(["Hello"]);

// v3
const { data: contract } = useScaffoldContract({
contractName: "YourContract",
});
// Read-only โ€” use .call() for reads
await contract?.call("greeting");
// For writes, use useScaffoldWriteContract instead

useContractWrite โ†’ Removedโ€‹

useContractWrite no longer exists in @starknet-start/react. Use useSendTransaction or the scaffold wrapper useScaffoldWriteContract.

// v2
const { sendAsync, isPending } = useContractWrite({ calls });
await sendAsync();

// v3 โ€” use useScaffoldWriteContract
const { sendAsync } = useScaffoldWriteContract({
contractName: "YourContract",
functionName: "set_greeting",
args: ["Hello"],
});
await sendAsync();

useContract โ†’ Removedโ€‹

useContract no longer exists. Use starknet.js Contract class directly if you need low-level contract instances.

// v2
import { useContract } from "@starknet-react/core";
const { contract } = useContract({ abi, address });

// v3 โ€” use starknet.js directly
import { Contract, RpcProvider } from "starknet";
const provider = new RpcProvider({ nodeUrl: "..." });
const contract = new Contract(abi, address, provider);

useTransactorโ€‹

The API has changed significantly:

// v2
const writeTx = useTransactor(_walletClient); // accepted optional wallet client
await writeTx(() => sendAsync()); // took a callback function

// v3
const { writeTransaction, transactionReceiptInstance, sendTransactionInstance } = useTransactor();
// No arguments to useTransactor()
// writeTransaction takes Call[] directly, not a callback
await writeTransaction([
{
contractAddress: "0x...",
entrypoint: "transfer",
calldata: ["0x...", "1", "0"],
},
]);

Key differences:

  • useTransactor() takes no arguments (no _walletClient parameter)
  • Returns { writeTransaction, transactionReceiptInstance, sendTransactionInstance }
  • writeTransaction(calls: Call[]) takes a Call[] array directly instead of a callback function
  • Use sendTransactionInstance.isPending for loading state

Burner Walletโ€‹

The burner wallet integration has changed completely:

// v2 โ€” BurnerConnector class added to connectors array
import { BurnerConnector } from "@scaffold-stark/stark-burner";
const burnerConnector = new BurnerConnector();
connectors.push(burnerConnector);
// Switch accounts via: burnerConnector.burnerAccount = accounts[index];

// v3 โ€” createBurnerWallet() factory returns a MockWallet, passed via extraWallets
import { createBurnerWallet } from "@scaffold-stark/stark-burner";
const burnerWallet = createBurnerWallet(chain);
// Pass to StarknetConfig via extraWallets prop:
// <StarknetConfig extraWallets={[burnerWallet]} ...>
// Switch accounts via: burnerWallet.switchAccount(index);

Key differences:

  • Package version: @scaffold-stark/stark-burner@0.2.0 (v3) vs 0.1.x (v2)
  • BurnerConnector class โ†’ createBurnerWallet() factory function
  • Returns a MockWallet instance (from @starknet-start/react), not a connector
  • Passed via extraWallets prop to StarknetConfig, not added to connectors array
  • Account switching: connector.switchAccount(index) instead of connector.burnerAccount = ...

URL Changes for starknet-react Documentationโ€‹

If you reference starknet-react docs, the domain and URL format have changed:

Old URLNew URL
https://starknet-react.com/...https://start.starknet-react.com/...
https://www.starknet-react.com/...https://start.starknet-react.com/...

Hook URL paths changed from kebab-case to camelCase:

Old PathNew Path
/docs/hooks/use-read-contract/docs/hooks/useReadContract
/docs/hooks/use-send-transaction/docs/hooks/useSendTransaction
/docs/hooks/use-transaction-receipt/docs/hooks/useTransactionReceipt

Block Explorer: Starkscan โ†’ Voyagerโ€‹

The default block explorer is now Voyager instead of Starkscan. Block explorer links in the UI (transaction links, address links, etc.) will now point to voyager.online and sepolia.voyager.online instead of starkscan.co.

No changes are required in your app code โ€” this is handled internally by the template. The only case where you need to act is if you customized ScaffoldStarkAppWithProviders.tsx to pass explorer={starkscan}:

// If you have this in your customized ScaffoldStarkAppWithProviders.tsx:
import { starkscan } from "@starknet-react/core"; // remove this

// Replace with:
import { voyager } from "@starknet-start/explorers";
// <StarknetConfig explorer={voyager} ...>

Keplr: Custom Connector Removedโ€‹

The custom KeplrConnector has been removed in v3 โ€” Keplr is still usable, but you no longer need to import and configure it manually. If Keplr supports the Starknet wallet standard in the user's browser, it will be auto-discovered without any connector code, saving you the bundle size cost of the @keplr-wallet/* packages.

If your v2 project explicitly installed those packages, you can remove them:

npm uninstall @keplr-wallet/types @keplr-wallet/cosmos @keplr-wallet/crypto @keplr-wallet/common @keplr-wallet/unit

Quick Migration Checklistโ€‹

  • Replace all @starknet-react/core imports with @starknet-start/react
  • Replace all @starknet-react/chains imports with @starknet-start/chains
  • Remove account parameter from useScaffoldContract calls
  • Replace useContractWrite usage with useScaffoldWriteContract or useSendTransaction
  • Replace useContract usage with starknet.js Contract directly
  • Update useTransactor usage: remove arguments, use writeTransaction(calls) instead of callback pattern
  • Remove manual connector setup โ€” wallets are auto-discovered via wallet standard
  • Migrate burner wallet from BurnerConnector to createBurnerWallet() + extraWallets prop
  • Update @scaffold-stark/stark-burner to 0.2.0
  • Update any starknet-react documentation links to use start.starknet-react.com
  • Remove @keplr-wallet/* packages from package.json (optional โ€” Keplr is auto-discovered if installed)
  • If you customized ScaffoldStarkAppWithProviders.tsx: update explorer from starkscan to voyager (@starknet-start/explorers)