@abstract-foundation/agw-client
Version:
Abstract Global Wallet Client SDK
147 lines (142 loc) • 4.76 kB
text/typescript
import type {
Account,
Address,
Calls,
Client,
GetChainParameter,
Hex,
Narrow,
PublicClient,
Transport,
WalletClient,
} from "viem";
import type { GetAccountParameter } from "viem/_types/types/account.js";
import type { ChainEIP712, SignEip712TransactionReturnType } from "viem/zksync";
import type { CustomPaymasterHandler } from "../types/customPaymaster.js";
import { encodeCalls } from "../utils.js";
import { signPrivyTransaction } from "./sendPrivyTransaction.js";
import { getBatchTransactionObject } from "./sendTransactionBatch.js";
import { signTransaction } from "./signTransaction.js";
export type SignTransactionBatchParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
calls extends readonly unknown[] = readonly unknown[],
> = {
calls: Calls<Narrow<calls>>;
forceAtomic?: boolean;
paymaster?: Address | undefined;
paymasterInput?: Hex | undefined;
} & GetAccountParameter<account, Account | Address, true, true> &
GetChainParameter<chain, chainOverride>;
/**
* Function to sign a batch of transactions in a single call using the connected Abstract Global Wallet.
*
* @example
* ```tsx
* import { useAbstractClient } from "@abstract-foundation/agw-react";
* import { encodeFunctionData, parseUnits } from "viem";
*
* export default function SignTransactionBatch() {
* const { data: agwClient } = useAbstractClient();
*
* async function signTransactionBatch() {
* if (!agwClient) return;
*
* // Sign a batch of multiple transactions in a single call
* const rawTransaction = await agwClient.signTransactionBatch({
* calls: [
* // 1. Simple ETH transfer
* {
* to: "0x1234567890123456789012345678901234567890",
* value: parseUnits("0.1", 18), // 0.1 ETH
* },
* // 2. Contract interaction
* {
* to: "0xabcdef0123456789abcdef0123456789abcdef01",
* data: encodeFunctionData({
* abi: [
* {
* name: "transfer",
* type: "function",
* inputs: [
* { name: "to", type: "address" },
* { name: "amount", type: "uint256" }
* ],
* outputs: [{ type: "bool" }],
* stateMutability: "nonpayable"
* }
* ],
* functionName: "transfer",
* args: ["0x9876543210987654321098765432109876543210", parseUnits("10", 18)]
* })
* }
* ]
* });
*
* console.log("Serialized transaction:", rawTransaction);
* }
* }
* ```
*
* @param parameters - Parameters for signing a batch of transactions
* @param parameters.calls - An array of transaction requests. Each transaction can include:
* - to: The recipient address (required)
* - data: Contract code or method call with encoded args
* - value: Amount in wei to send
* @param parameters.paymaster - Address of the paymaster smart contract that will pay the gas fees
* @param parameters.paymasterInput - Input data to the paymaster
* @returns The transaction hash of the submitted transaction batch
*/
export async function signTransactionBatch<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
const calls extends readonly unknown[] = readonly unknown[],
>(
client: Client<Transport, ChainEIP712, Account>,
signerClient: WalletClient<Transport, ChainEIP712, Account>,
publicClient: PublicClient<Transport, ChainEIP712>,
parameters: SignTransactionBatchParameters<
chain,
account,
chainOverride,
calls
>,
validator: Address,
validationHookData: Record<string, Hex> = {},
customPaymasterHandler: CustomPaymasterHandler | undefined = undefined,
isPrivyCrossApp = false,
): Promise<SignEip712TransactionReturnType> {
const { calls, ...rest } = parameters;
if (calls.length === 0) {
throw new Error("No calls provided");
}
if (isPrivyCrossApp) {
return await signPrivyTransaction(client, {
...rest,
calls: encodeCalls(calls),
} as any);
}
const batchTransaction = getBatchTransactionObject<
chain,
account,
chainOverride,
calls
>(client.account.address, {
calls,
...rest,
});
return signTransaction(
client,
signerClient,
publicClient,
{
...batchTransaction,
...rest,
} as any,
validator,
validationHookData,
customPaymasterHandler,
);
}