useScaffoldMultiWriteContract
Use this hook to execute multiple contract calls in a single transaction batch. This is more gas-efficient than sending individual transactions and ensures atomicity - either all calls succeed or none do.
const { sendAsync, isLoading } = useScaffoldMultiWriteContract({
calls: [
{
contractName: "Token",
functionName: "approve",
args: [spenderAddress, amount],
},
{
contractName: "DEX",
functionName: "swap",
args: [tokenIn, tokenOut, amount],
},
],
});
// Execute all calls in a single transaction
await sendAsync();
Configurationโ
| Parameter | Type | Description |
|---|---|---|
| calls | Array<ScaffoldWriteConfig | Call> | Array of contract calls to execute. Can be scaffold config objects or raw Starknet Call objects. |
| options (optional) | InvocationsDetails | Additional transaction options (max fee, nonce, etc.) |
Call Configuration Objectโ
Each call in the calls array can be:
Scaffold Config Format:
{
contractName: string; // Name of deployed contract
functionName: string; // External function to call
args: unknown[]; // Function arguments
}
Raw Call Format (Starknet.js):
{
contractAddress: string; // Contract address
entrypoint: string; // Function selector
calldata: string[]; // Encoded calldata
}
Return Valuesโ
| Property | Type | Description |
|---|---|---|
| sendAsync | () => Promise<string | undefined> | Function to execute all calls. Returns transaction hash. |
| isLoading | boolean | true while the transaction is being processed |
| error | Error | null | Error object if the transaction failed, null otherwise |
| status | "idle" | "loading" | "success" | "error" | Current transaction state |
Usage Examplesโ
Approve and Swapโ
A common DeFi pattern - approve token spending and swap in one transaction:
import { View, Button, Alert } from "react-native";
import { useScaffoldMultiWriteContract } from "@/hooks/scaffold-stark";
export default function SwapButton({ amount, tokenIn, tokenOut, dexAddress }) {
const { sendAsync, isLoading } = useScaffoldMultiWriteContract({
calls: [
{
contractName: "ERC20",
functionName: "approve",
args: [dexAddress, amount],
},
{
contractName: "DEX",
functionName: "swap",
args: [tokenIn, tokenOut, amount, 0], // minAmountOut = 0
},
],
});
const handleSwap = async () => {
try {
const txHash = await sendAsync();
Alert.alert("Success", `Swap completed: ${txHash}`);
} catch (error) {
Alert.alert("Error", error.message);
}
};
return (
<Button
title={isLoading ? "Swapping..." : "Approve & Swap"}
onPress={handleSwap}
disabled={isLoading}
/>
);
}
Batch Transfersโ
Send tokens to multiple recipients in one transaction:
import { View, Text, Button } from "react-native";
import { useScaffoldMultiWriteContract, createContractCall } from "@/hooks/scaffold-stark";
export default function BatchTransfer({ recipients }) {
// recipients = [{ address: "0x...", amount: 100n }, ...]
const calls = recipients.map((r) =>
createContractCall("Token", "transfer", [r.address, r.amount])
);
const { sendAsync, isLoading, status } = useScaffoldMultiWriteContract({
calls,
});
return (
<View>
<Button
title={isLoading ? "Sending..." : `Send to ${recipients.length} recipients`}
onPress={() => sendAsync()}
disabled={isLoading}
/>
{status === "success" && (
<Text>All transfers completed!</Text>
)}
</View>
);
}
Mixed Call Formatsโ
Combine scaffold config and raw calls:
import { Button } from "react-native";
import { useScaffoldMultiWriteContract } from "@/hooks/scaffold-stark";
export default function MixedCalls() {
const { sendAsync, isLoading } = useScaffoldMultiWriteContract({
calls: [
// Scaffold config format
{
contractName: "YourContract",
functionName: "doSomething",
args: [123],
},
// Raw Starknet.js Call format
{
contractAddress: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
entrypoint: "transfer",
calldata: ["0x123...", "1000", "0"],
},
],
});
return (
<Button
title="Execute Mixed Calls"
onPress={() => sendAsync()}
disabled={isLoading}
/>
);
}
NFT Minting with Metadataโ
Mint an NFT and set its metadata atomically:
import { useState } from "react";
import { View, TextInput, Button } from "react-native";
import { useScaffoldMultiWriteContract } from "@/hooks/scaffold-stark";
export default function MintWithMetadata() {
const [tokenUri, setTokenUri] = useState("");
const { sendAsync, isLoading } = useScaffoldMultiWriteContract({
calls: [
{
contractName: "NFT",
functionName: "mint",
args: [],
},
{
contractName: "NFT",
functionName: "setTokenURI",
args: [nextTokenId, tokenUri], // nextTokenId from a useScaffoldReadContract call
},
],
});
return (
<View style={{ gap: 12 }}>
<TextInput
placeholder="Token URI"
value={tokenUri}
onChangeText={setTokenUri}
style={{ borderWidth: 1, padding: 8 }}
/>
<Button
title={isLoading ? "Minting..." : "Mint NFT"}
onPress={() => sendAsync()}
disabled={isLoading || !tokenUri}
/>
</View>
);
}
Helper Functionโ
createContractCallโ
A helper function to create properly typed call objects:
import { createContractCall } from "@/hooks/scaffold-stark";
const call = createContractCall("Token", "transfer", [recipient, amount]);
The function takes three separate arguments: contractName, functionName, and args. This is useful when building calls dynamically or in loops.
Atomicityโ
All calls in a multi-write transaction are atomic:
- If all calls succeed, the transaction is confirmed
- If any call fails, the entire transaction reverts
- No partial execution is possible
This is critical for operations that must happen together (like approve + swap).
Gas Efficiencyโ
Batching multiple calls into a single transaction is more gas-efficient than sending them separately:
| Approach | Transaction Count | Gas Overhead |
|---|---|---|
| Individual transactions | N | N ร base fee |
| Multi-write (batched) | 1 | 1 ร base fee |
Differences from Web Versionโ
The React Native version is functionally identical to the web version. The main differences are:
- Uses React Native UI components
- Integrates with mobile wallet (Cavos Aegis)
- Mobile-optimized toast notifications
Related Hooksโ
- useScaffoldWriteContract - Single transaction writes
- useScaffoldReadContract - Read contract data
- useTransactor - Low-level transaction handling