This hook uses the session key signature (4-element format) instead of the owner signature. The session must be registered on-chain first via useAddSessionKeyToContract.
Usage
const {
executeWithSession,
executeWithSessionAsync,
data,
isLoading,
error,
isSuccess,
reset
} = useExecuteWithSession();
Parameters
| Parameter | Type | Required | Description |
|---|
params.encryptKey | string | Yes | PIN to decrypt the session private key |
params.wallet | WalletData | Yes | Wallet object (session executes on behalf of this wallet) |
params.session | SessionKeyData | Yes | Session key data from useCreateSessionKey |
params.calls | Call[] | Yes | Array of contract calls to execute |
bearerToken | string | Yes | Authentication token from your auth provider |
Call Structure
{
contractAddress: string; // Target contract address
entrypoint: string; // Function name to call
calldata: string[]; // Function arguments
}
Return Value
| Property | Type | Description |
|---|
executeWithSession | function | Trigger execution (fire-and-forget) |
executeWithSessionAsync | function | Trigger execution (returns Promise with tx hash) |
data | string | Transaction hash |
isLoading | boolean | Whether execution is in progress |
isError | boolean | Whether an error occurred |
error | Error | null | Error details if any |
isSuccess | boolean | Whether execution succeeded |
reset | function | Reset mutation state |
Example: Token Transfer
import { useExecuteWithSession } from "@chipi-stack/chipi-react";
const USDC_ADDRESS = "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8";
export function SessionTransfer() {
const { executeWithSessionAsync, isLoading, error, data: txHash } = useExecuteWithSession();
const [amount, setAmount] = useState('');
const [recipient, setRecipient] = useState('');
const handleTransfer = async () => {
const bearerToken = await getBearerToken();
const session = JSON.parse(localStorage.getItem('chipiSession')!);
const pin = await promptForPin(); // Your PIN input method
try {
const hash = await executeWithSessionAsync({
params: {
encryptKey: pin,
wallet: {
publicKey: wallet.publicKey,
encryptedPrivateKey: wallet.encryptedPrivateKey,
walletType: "CHIPI",
},
session,
calls: [{
contractAddress: USDC_ADDRESS,
entrypoint: "transfer",
calldata: [recipient, amount, "0x0"],
}],
},
bearerToken,
});
console.log('Transfer executed:', hash);
} catch (err) {
console.error('Transfer failed:', err);
}
};
return (
<div className="p-6 bg-white rounded-lg shadow">
<h2 className="text-xl font-semibold mb-4">Transfer with Session</h2>
<div className="space-y-4">
<input
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
placeholder="Recipient address (0x...)"
className="w-full p-2 border rounded"
/>
<input
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount (in smallest units)"
className="w-full p-2 border rounded"
/>
<button
onClick={handleTransfer}
disabled={isLoading}
className="w-full bg-green-600 text-white py-2 rounded hover:bg-green-700 disabled:bg-gray-400"
>
{isLoading ? 'Executing...' : 'Transfer'}
</button>
</div>
{error && (
<div className="mt-4 p-3 bg-red-50 text-red-700 rounded">
Error: {error.message}
</div>
)}
{txHash && (
<div className="mt-4 p-3 bg-green-50 rounded">
<a
href={`https://starkscan.co/tx/${txHash}`}
target="_blank"
rel="noopener noreferrer"
className="text-green-700 hover:underline"
>
View transaction →
</a>
</div>
)}
</div>
);
}
Example: Gaming Actions
import { useExecuteWithSession } from "@chipi-stack/chipi-react";
const GAME_CONTRACT = "0x...";
export function GameBoard() {
const { executeWithSessionAsync, isLoading } = useExecuteWithSession();
const makeMove = async (moveData: string) => {
const session = JSON.parse(localStorage.getItem('chipiSession')!);
const bearerToken = await getBearerToken();
// Execute instantly - no wallet popup!
await executeWithSessionAsync({
params: {
encryptKey: userPin,
wallet: { ...wallet, walletType: "CHIPI" },
session,
calls: [{
contractAddress: GAME_CONTRACT,
entrypoint: "make_move",
calldata: [moveData],
}],
},
bearerToken,
});
};
return (
<div className="grid grid-cols-3 gap-2">
{[1, 2, 3, 4, 5, 6, 7, 8, 9].map((cell) => (
<button
key={cell}
onClick={() => makeMove(cell.toString())}
disabled={isLoading}
className="h-20 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-400"
>
{cell}
</button>
))}
</div>
);
}
Multi-Call Transactions
Execute multiple calls in a single transaction:
const txHash = await executeWithSessionAsync({
params: {
encryptKey: pin,
wallet: walletData,
session,
calls: [
// Approve spending
{
contractAddress: USDC_ADDRESS,
entrypoint: "approve",
calldata: [SWAP_CONTRACT, amount, "0x0"],
},
// Execute swap
{
contractAddress: SWAP_CONTRACT,
entrypoint: "swap",
calldata: [USDC_ADDRESS, ETH_ADDRESS, amount, minReceived],
},
],
},
bearerToken,
});
Error Handling
| Error | Cause | Solution |
|---|
Session execution only supports CHIPI wallets | Wallet is ARGENT type | Use a CHIPI wallet |
Session has expired | validUntil timestamp passed | Create and register a new session |
Session not found | Not registered on-chain | Call useAddSessionKeyToContract first |
Max calls exceeded | remainingCalls is 0 | Create a new session with higher maxCalls |
Entrypoint not allowed | Function not in whitelist | Register session with correct allowedEntrypoints |
Session transactions decrement remainingCalls on the contract. Monitor usage with useGetSessionData and create new sessions before exhaustion.
For the best UX, pre-create sessions during onboarding and store the PIN securely. This allows instant transactions without prompting for PIN each time.