@abstract-foundation/agw-client
Version:
Abstract Global Wallet Client SDK
168 lines • 6.05 kB
JavaScript
import { BaseError, concat, encodeFunctionData, fromHex, isHex, keccak256, toBytes, toHex, } from "viem";
import { parseAccount } from "viem/accounts";
import { getCode } from "viem/actions";
import { abstract, abstractTestnet, zksync, zksyncSepoliaTestnet, } from "viem/chains";
import { getAction } from "viem/utils";
import AccountFactoryAbi from "./abis/AccountFactory.js";
import { AGWRegistryAbi } from "./abis/AGWRegistryAbi.js";
import { AGW_REGISTRY_ADDRESS, SMART_ACCOUNT_FACTORY_ADDRESS, } from "./constants.js";
import { isEIP712Transaction } from "./eip712.js";
export const VALID_CHAINS = {
[abstractTestnet.id]: abstractTestnet,
[abstract.id]: abstract,
[zksync.id]: zksync,
[zksyncSepoliaTestnet.id]: zksyncSepoliaTestnet,
};
export function convertBigIntToString(value) {
if (typeof value === "bigint") {
return value.toString();
}
else if (Array.isArray(value)) {
return value.map(convertBigIntToString);
}
else if (typeof value === "object" && value !== null) {
const result = {};
for (const key in value) {
result[key] = convertBigIntToString(value[key]);
}
return result;
}
return value;
}
export async function getSmartAccountAddressFromInitialSigner(initialSigner, publicClient) {
if (initialSigner === undefined) {
throw new Error("Initial signer is required to get smart account address");
}
// Generate salt based off address
const addressBytes = toBytes(initialSigner);
const salt = keccak256(addressBytes);
// Get the deployed account address
const accountAddress = (await publicClient.readContract({
address: SMART_ACCOUNT_FACTORY_ADDRESS,
abi: AccountFactoryAbi,
functionName: "getAddressForSalt",
args: [salt],
}));
return accountAddress;
}
export async function isAGWAccount(publicClient, address) {
return await publicClient.readContract({
address: AGW_REGISTRY_ADDRESS,
abi: AGWRegistryAbi,
functionName: "isAGW",
args: [address],
});
}
export async function isSmartAccountDeployed(client, address) {
const bytecode = await getAction(client, getCode, "getCode")({
address: address,
});
return bytecode !== undefined;
}
export function getInitializerCalldata(initialOwnerAddress, validatorAddress, initialCall) {
return encodeFunctionData({
abi: [
{
name: "initialize",
type: "function",
inputs: [
{ name: "initialK1Owner", type: "address" },
{ name: "initialK1Validator", type: "address" },
{ name: "modules", type: "bytes[]" },
{
name: "initCall",
type: "tuple",
components: [
{ name: "target", type: "address" },
{ name: "allowFailure", type: "bool" },
{ name: "value", type: "uint256" },
{ name: "callData", type: "bytes" },
],
},
],
outputs: [],
stateMutability: "nonpayable",
},
],
functionName: "initialize",
args: [initialOwnerAddress, validatorAddress, [], initialCall],
});
}
export function transformHexValues(transaction, keys) {
if (!transaction)
return;
for (const key of keys) {
if (isHex(transaction[key])) {
transaction[key] = fromHex(transaction[key], "bigint");
}
}
}
export function isEip712TypedData(typedData) {
return (typedData.message &&
typedData.domain?.name === "zkSync" &&
typedData.domain?.version === "2" &&
isEIP712Transaction(typedData.message));
}
export function transformEip712TypedData(typedData) {
if (!isEip712TypedData(typedData)) {
throw new BaseError("Typed data is not an EIP712 transaction");
}
if (typedData.domain?.chainId === undefined) {
throw new BaseError("Chain ID is required for EIP712 transaction");
}
return {
chainId: Number(typedData.domain.chainId),
account: parseAccount(toHex(BigInt(typedData.message.from), {
size: 20,
})),
to: toHex(BigInt(typedData.message.to), {
size: 20,
}),
gas: BigInt(typedData.message.gasLimit),
gasPerPubdata: BigInt(typedData.message.gasPerPubdataByteLimit),
maxFeePerGas: BigInt(typedData.message.maxFeePerGas),
maxPriorityFeePerGas: BigInt(typedData.message.maxPriorityFeePerGas),
paymaster: typedData.message.paymaster !== "0"
? toHex(BigInt(typedData.message.paymaster), {
size: 20,
})
: undefined,
nonce: typedData.message.nonce,
value: BigInt(typedData.message.value),
data: typedData.message.data === "0x0" ? "0x" : typedData.message.data,
factoryDeps: typedData.message.factoryDeps,
paymasterInput: typedData.message.paymasterInput !== "0x"
? typedData.message.paymasterInput
: undefined,
};
}
function encodeCall(call_) {
const call = call_;
const data = call.abi
? encodeFunctionData({
abi: call.abi,
functionName: call.functionName,
args: call.args,
})
: call.data;
return {
data: call.dataSuffix && data ? concat([data, call.dataSuffix]) : data,
to: call.to,
value: call.value,
};
}
export function encodeCalls(calls) {
return calls.map(encodeCall);
}
export function formatCalls(calls) {
return calls.map((call_) => {
const call = encodeCall(call_);
return {
callData: call.data ?? "0x",
target: call.to,
value: call.value ?? 0n,
allowFailure: false,
};
});
}
//# sourceMappingURL=utils.js.map