UNPKG

@abstract-foundation/agw-client

Version:
130 lines 5.45 kB
import { BaseError, encodeAbiParameters, parseAbiParameters, } from "viem"; import { getChainId, readContract, signTypedData } from "viem/actions"; import { assertCurrentChain, getAction, parseAccount } from "viem/utils"; import AGWAccountAbi from "../abis/AGWAccount.js"; import { assertEip712Request, } from "../eip712.js"; import { AccountNotFoundError } from "../errors/account.js"; import { assertSessionKeyPolicies } from "../sessionValidator.js"; import { transformHexValues, VALID_CHAINS } from "../utils.js"; import { signPrivyTransaction } from "./sendPrivyTransaction.js"; export async function signTransaction(client, signerClient, publicClient, args, validator, validationHookData = {}, customPaymasterHandler = undefined, isPrivyCrossApp = false) { const chain = client.chain; if (isPrivyCrossApp) { return signPrivyTransaction(client, args); } if (!chain?.serializers?.transaction) throw new BaseError("transaction serializer not found on chain."); const { transaction, customSignature } = await signEip712TransactionInternal(client, signerClient, publicClient, args, validator, validationHookData, customPaymasterHandler); return chain.serializers.transaction({ ...transaction, customSignature, type: "eip712", }, { r: "0x0", s: "0x0", v: 0n }); } export async function signEip712TransactionInternal(client, signerClient, publicClient, args, validator, validationHookData = {}, customPaymasterHandler = undefined) { // ensure the transaction type is set to eip712 args.type = "eip712"; const { account: account_ = client.account, chain = client.chain, ...transaction } = args; transformHexValues(transaction, [ "value", "nonce", "maxFeePerGas", "maxPriorityFeePerGas", "gas", "chainId", "gasPerPubdata", ]); if (!account_) throw new AccountNotFoundError({ docsPath: "/docs/actions/wallet/signTransaction", }); const smartAccount = parseAccount(account_); const useSignerAddress = transaction.from === signerClient.account.address; const fromAccount = useSignerAddress ? signerClient.account : smartAccount; assertEip712Request({ account: fromAccount, chain, ...transaction, }); if (!chain || VALID_CHAINS[chain.id] === undefined) { throw new BaseError("Invalid chain specified"); } if (!chain?.custom?.getEip712Domain) throw new BaseError("`getEip712Domain` not found on chain."); const chainId = await getAction(client, getChainId, "getChainId")({}); if (chain !== null) assertCurrentChain({ currentChainId: chainId, chain: chain, }); await assertSessionKeyPolicies(publicClient, chainId, fromAccount, transaction); const transactionWithPaymaster = await getTransactionWithPaymasterData(chainId, fromAccount, transaction, customPaymasterHandler); if (transactionWithPaymaster.data === undefined) { // serializer turns undefined into 0x00 which causes issues sending // eth to contracts that don't have a fallback function transactionWithPaymaster.data = "0x"; } const eip712Domain = chain?.custom.getEip712Domain({ ...transactionWithPaymaster, type: "eip712", }); const rawSignature = await signTypedData(signerClient, { ...eip712Domain, account: signerClient.account, }); let signature; if (useSignerAddress) { signature = rawSignature; } else { const hookData = []; if (!useSignerAddress) { const validationHooks = await getAction(client, readContract, "readContract")({ address: client.account.address, abi: AGWAccountAbi, functionName: "listHooks", args: [true], }); for (const hook of validationHooks) { hookData.push(validationHookData[hook] ?? "0x"); } } // Match the expect signature format of the AGW smart account signature = encodeAbiParameters(parseAbiParameters(["bytes", "address", "bytes[]"]), [rawSignature, validator, hookData]); } return { transaction: transactionWithPaymaster, customSignature: signature, }; } async function getTransactionWithPaymasterData(chainId, fromAccount, transaction, customPaymasterHandler = undefined) { if (customPaymasterHandler && !transaction.paymaster && !transaction.paymasterInput) { const paymasterResult = await customPaymasterHandler({ chainId, from: fromAccount.address, data: transaction.data, gas: transaction.gas ?? 0n, gasPrice: transaction.gasPrice ?? 0n, gasPerPubdata: transaction.gasPerPubdata ?? 0n, maxFeePerGas: transaction.maxFeePerGas ?? 0n, maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ?? 0n, nonce: transaction.nonce ?? 0, to: transaction.to ?? "0x0", value: transaction.value ?? 0n, }); return { ...transaction, ...paymasterResult, from: fromAccount.address, chainId, }; } return { ...transaction, from: fromAccount.address, chainId, }; } //# sourceMappingURL=signTransaction.js.map