@biconomy/abstractjs
Version:
SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.
469 lines • 20.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toNexusAccount = void 0;
const viem_1 = require("viem");
const account_abstraction_1 = require("viem/account-abstraction");
const actions_1 = require("viem/actions");
const constants_1 = require("../constants/index.js");
const abi_1 = require("../constants/abi/index.js");
const modules_1 = require("../modules/index.js");
const toEmptyHook_1 = require("../modules/toEmptyHook.js");
const composabilityCalls_1 = require("../modules/utils/composabilityCalls.js");
const toDefaultModule_1 = require("../modules/validators/default/toDefaultModule.js");
const toMeeK1Module_1 = require("../modules/validators/meeK1/toMeeK1Module.js");
const getFactoryData_1 = require("./decorators/getFactoryData.js");
const getNexusAddress_1 = require("./decorators/getNexusAddress.js");
const getNonceWithKey_1 = require("./decorators/getNonceWithKey.js");
const utils_1 = require("./utils/index.js");
const Constants_1 = require("./utils/Constants.js");
const Utils_1 = require("./utils/Utils.js");
const getVersion_1 = require("./utils/getVersion.js");
const toP256Signer_1 = require("./utils/toP256Signer.js");
const toSigner_1 = require("./utils/toSigner.js");
const toWalletClient_1 = require("./utils/toWalletClient.js");
const prepareValidators = async (walletClient, meeConfig, customValidators) => {
let validators = [];
if (customValidators && customValidators.length > 0) {
return customValidators;
}
if ((0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) {
validators = [
(0, toMeeK1Module_1.toMeeK1Module)({
walletClient,
module: meeConfig.defaultValidatorAddress
})
];
}
else {
validators = [];
}
return validators;
};
const prepareExecutors = (meeConfig, customExecutors) => {
let executors = [];
if ((0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) {
if (!meeConfig.composableModuleAddress) {
throw new Error("Composable module address is missing");
}
const composableExecutor = (0, modules_1.toComposableExecutor)(meeConfig.composableModuleAddress);
executors = [composableExecutor];
for (const executor of customExecutors || []) {
if (!(0, Utils_1.addressEquals)(executor.module, composableExecutor.module)) {
executors.push(executor);
}
}
}
else {
executors = customExecutors || [];
}
return executors;
};
const prepareFallbacks = (meeConfig, customFallbacks) => {
let fallbacks = [];
if ((0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) {
if (!meeConfig.composableModuleAddress) {
throw new Error("Composable module address is missing");
}
const composableFallback = (0, modules_1.toComposableFallback)(meeConfig.composableModuleAddress);
fallbacks = [composableFallback];
for (const fallback of customFallbacks || []) {
if (!(0, Utils_1.addressEquals)(fallback.module, composableFallback.module)) {
fallbacks.push(fallback);
}
}
}
else {
fallbacks = customFallbacks || [];
}
return fallbacks;
};
const prepareFactoryData = (meeConfig, initDataParams) => {
let factoryData = "0x";
let initData = "0x";
switch (meeConfig.version) {
case constants_1.MEEVersion.V1_0_0:
case constants_1.MEEVersion.V1_1_0: {
if (!meeConfig.moduleRegistry) {
throw new Error("Module registry not found in nexus config");
}
initData =
initDataParams.customInitData ||
(0, getFactoryData_1.getInitDataWithRegistry)({
bootStrapAddress: meeConfig.bootStrapAddress,
validators: initDataParams.validators,
registryAddress: meeConfig.moduleRegistry.registryAddress,
attesters: meeConfig.moduleRegistry.attesters,
attesterThreshold: meeConfig.moduleRegistry.attesterThreshold,
meeVersion: meeConfig.version
});
factoryData = (0, getFactoryData_1.getFactoryData)({
initData,
index: initDataParams.accountIndex
});
break;
}
default: {
initData =
initDataParams.customInitData ||
(0, getFactoryData_1.getInitDataNoRegistry)({
defaultValidator: initDataParams.defaultValidator,
prevalidationHooks: initDataParams.prevalidationHooks,
validators: initDataParams.validators,
executors: initDataParams.executors,
hook: initDataParams.hook,
fallbacks: initDataParams.fallbacks,
bootStrapAddress: meeConfig.bootStrapAddress
});
factoryData = (0, getFactoryData_1.getFactoryData)({
initData,
index: initDataParams.accountIndex
});
break;
}
}
return { initData, factoryData };
};
const toNexusAccount = async (parameters) => {
const { signer: _signer, chainConfiguration: { chain, version: meeConfig, transport: transportConfig, versionCheck = true, accountAddress: accountAddress_ }, index = 0n, validators: customValidators, executors: customExecutors, hook: customHook, fallbacks: customFallbacks, prevalidationHooks: customPrevalidationHooks, initData: customInitData, defaultModuleParameters } = parameters;
if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V2_0_0)) {
const hasCancun = await (0, Utils_1.supportsCancun)({
chain,
transport: transportConfig
});
if (!hasCancun) {
throw new Error(`MEE version (${meeConfig.version}) is not supported for the ${chain.name} chain. Please use a version earlier than 2.0.0 or a chain that supports Cancun.`);
}
}
const publicClient = (0, viem_1.createPublicClient)({ chain, transport: transportConfig });
if (versionCheck) {
const addressesToDeploymentSet = new Set([
meeConfig.bootStrapAddress,
meeConfig.defaultValidatorAddress,
meeConfig.validatorAddress,
meeConfig.factoryAddress,
meeConfig.implementationAddress
]);
if (meeConfig.moduleRegistry) {
addressesToDeploymentSet.add(meeConfig.moduleRegistry.registryAddress);
}
if (meeConfig.composableModuleAddress) {
addressesToDeploymentSet.add(meeConfig.composableModuleAddress);
}
const addressesToDeploymentCheck = [...addressesToDeploymentSet].filter((address) => address !== viem_1.zeroAddress);
await Promise.all(addressesToDeploymentCheck.map(async (address) => {
const bytecode = await publicClient.getCode({
address
});
if (!bytecode || bytecode === "0x") {
console.error(`MEE version (${meeConfig.version}) is not supported for the ${chain.name} chain. Contract address (${address}) is not deployed`);
throw new Error(`MEE version (${meeConfig.version}) is not supported for the ${chain.name} chain.`);
}
}));
}
const signer = await (0, toSigner_1.toSigner)({ signer: _signer });
if ((0, toP256Signer_1.isP256Signer)(signer) &&
(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0)) {
throw new Error(`P256 signers require MEE version ${constants_1.MEEVersion.V3_0_0} or higher. Current version: ${meeConfig.version}`);
}
const walletClient = (0, toWalletClient_1.toWalletClient)({
unresolvedSigner: _signer,
resolvedSigner: signer,
chain,
transport: transportConfig
});
const validators = await prepareValidators(walletClient, meeConfig, customValidators);
const defaultValidator = (0, toDefaultModule_1.toDefaultModule)({
...defaultModuleParameters,
walletClient,
signer,
meeConfig
});
let module = validators[0] || defaultValidator;
const executors = prepareExecutors(meeConfig, customExecutors);
const hook = customHook || (0, toEmptyHook_1.toEmptyHook)();
const fallbacks = prepareFallbacks(meeConfig, customFallbacks);
const prevalidationHooks = customPrevalidationHooks || [];
const { initData, factoryData } = prepareFactoryData(meeConfig, {
accountIndex: index,
defaultValidator: (0, utils_1.toInitData)(defaultValidator),
prevalidationHooks,
validators: validators.map(utils_1.toInitData),
executors: executors.map(utils_1.toInitData),
hook: (0, utils_1.toInitData)(hook),
fallbacks: fallbacks.map(utils_1.toInitData),
customInitData
});
const getInitCode = () => (0, viem_1.concatHex)([meeConfig.factoryAddress, factoryData]);
let _accountAddress = accountAddress_;
let _eip712Domain;
const accountId = (await publicClient.readContract({
address: meeConfig.implementationAddress,
abi: (0, viem_1.parseAbi)(["function accountId() public view returns (string)"]),
functionName: "accountId",
args: []
}));
const getAddress = async () => {
if (!(0, Utils_1.isNullOrUndefined)(_accountAddress))
return _accountAddress;
const addressFromFactory = await (0, getNexusAddress_1.getNexusAddress)({
factoryAddress: meeConfig.factoryAddress,
index,
initData,
publicClient
});
if (!(0, Utils_1.addressEquals)(addressFromFactory, viem_1.zeroAddress)) {
_accountAddress = addressFromFactory;
return addressFromFactory;
}
throw new Error("Failed to get account address");
};
const getEip712Domain = async () => {
if (!(0, Utils_1.isNullOrUndefined)(_eip712Domain))
return _eip712Domain;
const eip712Domain = await (0, actions_1.getEip712Domain)(publicClient, {
address: await getAddress(),
factory: meeConfig.factoryAddress,
factoryData
});
_eip712Domain = eip712Domain;
return eip712Domain;
};
const getUserOpHash = (userOp) => (0, account_abstraction_1.getUserOperationHash)({
chainId: chain.id,
entryPointAddress: account_abstraction_1.entryPoint07Address,
entryPointVersion: "0.7",
userOperation: userOp
});
const encodeExecuteBatch = async (calls, mode = Constants_1.EXECUTE_BATCH) => {
const executionAbiParams = {
type: "tuple[]",
components: [
{ name: "target", type: "address" },
{ name: "value", type: "uint256" },
{ name: "callData", type: "bytes" }
]
};
const executions = calls.map((tx) => ({
target: tx.to,
callData: tx.data ?? "0x",
value: BigInt(tx.value ?? 0n)
}));
const executionCalldataPrep = (0, viem_1.encodeAbiParameters)([executionAbiParams], [executions]);
return (0, viem_1.encodeFunctionData)({
abi: (0, viem_1.parseAbi)([
"function execute(bytes32 mode, bytes calldata executionCalldata) external"
]),
functionName: "execute",
args: [mode, executionCalldataPrep]
});
};
const encodeExecute = async (call, mode = Constants_1.EXECUTE_SINGLE) => {
const executionCalldata = (0, viem_1.encodePacked)(["address", "uint256", "bytes"], [call.to, BigInt(call.value ?? 0n), (call.data ?? "0x")]);
return (0, viem_1.encodeFunctionData)({
abi: (0, viem_1.parseAbi)([
"function execute(bytes32 mode, bytes calldata executionCalldata) external"
]),
functionName: "execute",
args: [mode, executionCalldata]
});
};
const encodeExecuteComposable = async (calls) => {
const isComposability_v1_0_0 = calls.every((call) => !!call.to) &&
!calls.every((call) => call.inputParams.some((param) => param.paramType === composabilityCalls_1.InputParamType.TARGET));
const composableCallsFormattedByVersion = calls.map((call) => {
return isComposability_v1_0_0
? {
to: call.to,
value: call.value ?? 0n,
functionSig: call.functionSig,
inputParams: call.inputParams,
outputParams: call.outputParams
}
: {
functionSig: call.functionSig,
inputParams: call.inputParams,
outputParams: call.outputParams
};
});
return (0, viem_1.encodeFunctionData)({
abi: isComposability_v1_0_0
? abi_1.COMPOSABILITY_MODULE_ABI_V1_0_0
: abi_1.COMPOSABILITY_MODULE_ABI_V1_1_0,
functionName: "executeComposable",
args: [composableCallsFormattedByVersion]
});
};
const getFactoryArgs = async () => {
return {
factory: meeConfig.factoryAddress,
factoryData
};
};
const getNonceWithKey = async (accountAddress, parameters) => {
const defaultNonceKey = await (0, getNonceWithKey_1.getDefaultNonceKey)(accountAddress, chain.id);
const { key = defaultNonceKey, validationMode = "0x00", moduleAddress = module.module } = parameters ?? {};
return (0, getNonceWithKey_1.getNonceWithKeyUtil)(publicClient, accountAddress, {
key,
validationMode,
moduleAddress
});
};
const getNonce = async (parameters) => {
const accountAddress = await getAddress();
const { nonce } = await getNonceWithKey(accountAddress, parameters);
return nonce;
};
async function signTypedData(parameters) {
const typedDataParams = parameters;
const signature = (await module.erc7739VersionSupported()) === 0
? await module.signTypedData(typedDataParams)
: await module.signTypedDataErc7739(typedDataParams, (await getEip712Domain()).domain);
let wrappedSignature = signature;
if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0) &&
(0, toP256Signer_1.isP256Signer)(signer)) {
wrappedSignature = (0, viem_1.encodePacked)(["bytes4", "bytes"], [Constants_1.SIG_TYPE_NO_STX_P256, signature]);
}
return (0, viem_1.encodePacked)(["address", "bytes"], [module.module, wrappedSignature]);
}
const signMessage = async (parameters) => {
const { message } = parameters;
const signature = (await module.erc7739VersionSupported()) === 0
? await module.signMessage(message)
: await module.signMessageErc7739(message, (await getEip712Domain()).domain);
let wrappedSignature = signature;
if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0) &&
(0, toP256Signer_1.isP256Signer)(signer)) {
wrappedSignature = (0, viem_1.encodePacked)(["bytes4", "bytes"], [Constants_1.SIG_TYPE_NO_STX_P256, signature]);
}
return (0, viem_1.encodePacked)(["address", "bytes"], [module.module, wrappedSignature]);
};
const signMessage1271 = async (parameters) => {
const { message } = parameters;
const [rawSignature, code] = await Promise.all([
module.signMessage(message),
getAddress().then((addr) => publicClient.getCode({ address: addr }))
]);
let signature = rawSignature;
if (!(0, getVersion_1.isVersionOlder)(meeConfig.version, constants_1.MEEVersion.V3_0_0)) {
const prefix = (0, toP256Signer_1.isP256Signer)(signer)
? Constants_1.SIG_TYPE_NO_STX_VANILLA_1271_P256
: Constants_1.SIG_TYPE_NO_STX_VANILLA_1271_EOA;
signature = (0, viem_1.encodePacked)(["bytes4", "bytes"], [prefix, signature]);
}
const wrappedSignature = (0, viem_1.encodePacked)(["address", "bytes"], [module.module, signature]);
const isDeployed = Boolean(code);
if (!isDeployed) {
return (0, Utils_1.wrapSignatureWith6492)({
factoryAddress: meeConfig.factoryAddress,
factoryCalldata: factoryData,
signature: wrappedSignature
});
}
return wrappedSignature;
};
const setModule = (validationModule) => {
module = validationModule;
};
async function toDelegation(params) {
const { authorization: authorization_, multiChain, delegatedContract, chainId } = params || {};
const contractAddress = delegatedContract || meeConfig.implementationAddress;
const authorization = authorization_ ||
(await walletClient.signAuthorization({
contractAddress,
chainId: multiChain ? 0 : chainId
}));
const eip7702Auth = {
chainId: `0x${(authorization.chainId).toString(16)}`,
address: authorization.address,
nonce: `0x${authorization.nonce.toString(16)}`,
r: authorization.r,
s: authorization.s,
yParity: `0x${authorization.yParity.toString(16)}`
};
return eip7702Auth;
}
async function isDelegated() {
const code = await publicClient.getCode({ address: signer.address });
return (!!code &&
code
?.toLowerCase()
.includes(meeConfig.implementationAddress.substring(2).toLowerCase()));
}
async function unDelegate(params) {
const { authorization } = params || {};
const deAuthorization = authorization ||
(await walletClient.signAuthorization({
address: viem_1.zeroAddress,
executor: "self"
}));
return await walletClient.sendTransaction({
to: signer.address,
data: "0xdeadbeef",
type: "eip7702",
authorizationList: [deAuthorization]
});
}
return (0, account_abstraction_1.toSmartAccount)({
client: publicClient,
entryPoint: {
abi: abi_1.EntrypointAbi,
address: constants_1.ENTRY_POINT_ADDRESS,
version: "0.7"
},
getAddress,
encodeCalls: (calls) => {
return calls.length === 1
? encodeExecute(calls[0])
: encodeExecuteBatch(calls);
},
getFactoryArgs,
getStubSignature: async () => module.getStubSignature(),
signMessage,
signMessage1271,
signTypedData,
signUserOperation: async (parameters) => {
const { chainId = publicClient.chain.id, ...userOpWithoutSender } = parameters;
const address = await getAddress();
const userOperation = {
...userOpWithoutSender,
sender: address
};
const hash = (0, account_abstraction_1.getUserOperationHash)({
chainId,
entryPointAddress: account_abstraction_1.entryPoint07Address,
entryPointVersion: "0.7",
userOperation
});
return await module.signUserOperationHash(hash);
},
getNonce,
extend: {
isDelegated,
toDelegation,
unDelegate,
entryPointAddress: account_abstraction_1.entryPoint07Address,
getAddress,
accountId,
getEip712Domain,
getInitCode,
getNonceWithKey,
encodeExecute,
encodeExecuteBatch,
encodeExecuteComposable,
getUserOpHash,
factoryData,
factoryAddress: meeConfig.factoryAddress,
registryAddress: meeConfig.moduleRegistry?.registryAddress || viem_1.zeroAddress,
signer,
walletClient,
publicClient,
chain,
setModule,
signMessage1271,
getModule: () => module,
version: meeConfig
}
});
};
exports.toNexusAccount = toNexusAccount;
//# sourceMappingURL=toNexusAccount.js.map