import {
Address,
createWalletClient,
Hex,
http,
OneOf,
publicActions,
SignTypedDataParameters,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
/**
* Types for different signable payloads.
*/
// Payload for EIP-712 permit signature (excluding the account field)
type SignablePermitPayload = Omit<SignTypedDataParameters, "account">;
// Payload for simple message signing (raw hex message)
type SignableSimplePayload = {
message: {
raw: Hex;
};
};
// Payload for on-chain transaction signing
type SignableOnChainPayload =
| {
data: Hex;
to: Address;
chainId: number;
value: string;
}
| {
data: Hex;
to: Address;
chainId: number;
value?: string | undefined;
};
/**
* Example EOA account and wallet client setup.
* Replace the private key with a real one for production use.
*/
const eoaAccount = privateKeyToAccount("0x"); // ⚠️ Replace with your private key
const walletClient = createWalletClient({
account: eoaAccount,
chain: base,
transport: http(), // ⚠️ Use private paid RPC for production
}).extend(publicActions);
/**
* Signs a simple quote payload (raw message).
*
* @param signablePayload - The payload containing the raw message to sign.
* @returns The signature as a Hex string.
*
* @example
* const signature = await signSimpleQuoteSignablePayload({
* message: { raw: "0x68656c6c6f" }
* });
*/
const signSimpleQuoteSignablePayload = async (
signablePayload: SignableSimplePayload
): Promise<Hex> => {
const signature = await eoaAccount.signMessage(signablePayload);
return signature;
};
/**
* Signs a permit quote payload (EIP-712 typed data).
*
* @param signablePayload - The EIP-712 payload to sign.
* @returns The signature as a Hex string.
*
* @example
* const signature = await signPermitQuoteSignablePayload({
* domain: { ... },
* types: { ... },
* primaryType: "Permit",
* message: { ... }
* });
*/
const signPermitQuoteSignablePayload = async (
signablePayload: SignablePermitPayload
): Promise<Hex> => {
const signature = await walletClient.signTypedData({
...signablePayload,
account: eoaAccount,
});
return signature;
};
/**
* Signs an on-chain quote payload (transaction).
*
* @param signablePayload - The transaction payload to send.
* @returns The transaction hash as a Hex string.
*
* @example
* const txHash = await signOnChainQuoteSignablePayload({
* to: "0x...",
* data: "0x...",
* value: "0",
* chainId: 1
* });
*/
const signOnChainQuoteSignablePayload = async (
signablePayload: SignableOnChainPayload
): Promise<Hex> => {
const hash = await walletClient.sendTransaction({
to: signablePayload.to,
data: signablePayload.data,
value: BigInt(signablePayload.value || "0")
});
// Wait for 5 confirmations before returning the hash
await walletClient.waitForTransactionReceipt({ hash, confirmations: 5 });
return hash;
};
/**
* Union type for all supported payloads to sign.
*/
type PayloadToSign = OneOf<
| {
signablePayload: SignableSimplePayload;
metadata?: any;
}
| {
signablePayload: SignablePermitPayload;
metadata: {
nonce: string;
name: string;
version: string;
domainSeparator: string;
owner: string;
spender: string;
amount: string;
};
}
| SignableOnChainPayload
>;
/**
* Signs a quote payload based on its type.
*
* @param quoteType - The type of quote from the API response.
* @param payloadToSign - The payload to sign.
* @returns The signature or transaction hash as a Hex string.
*
* @example
* // Simple message
* const sig = await signQuoteSignablePayload("simple", {
* message: { raw: "0x68656c6c6f" }
* });
*
* // Permit (EIP-712)
* const sig = await signQuoteSignablePayload("permit", {
* signablePayload: { domain: {...}, types: {...}, primaryType: "...", message: {...} },
* metadata: { ... }
* });
*
* // On-chain transaction
* const txHash = await signQuoteSignablePayload("onchain", {
* to: "0x...",
* data: "0x...",
* value: "0",
* chainId: 1
* });
*/
const signQuoteSignablePayload = async (
quoteType: string,
payloadToSign: PayloadToSign
): Promise<Hex> => {
let signature: Hex = "0x";
switch (quoteType) {
case "simple":
signature = await signSimpleQuoteSignablePayload(payloadToSign);
break;
case "permit":
signature = await signPermitQuoteSignablePayload(payloadToSign.signablePayload);
break;
case "onchain":
signature = await signOnChainQuoteSignablePayload(payloadToSign);
break;
default:
throw new Error("Unsupported quote type, can't sign the payload");
}
return signature;
};