@biconomy/abstractjs
Version:
SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.
335 lines • 14.3 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 constants_1 = require("../constants/index.js");
const abi_1 = require("../constants/abi/index.js");
const abi_2 = require("../constants/abi/index.js");
const toEmptyHook_1 = require("../modules/toEmptyHook.js");
const toDefaultModule_1 = require("../modules/validators/default/toDefaultModule.js");
const toLegacyK1Module_1 = require("../modules/validators/legacyK1/toLegacyK1Module.js");
const getFactoryData_1 = require("./decorators/getFactoryData.js");
const getNexusAddress_1 = require("./decorators/getNexusAddress.js");
const getNonceWithKey_1 = require("./decorators/getNonceWithKey.js");
const Constants_1 = require("./utils/Constants.js");
const Utils_1 = require("./utils/Utils.js");
const getVersion_1 = require("./utils/getVersion.js");
const toInitData_1 = require("./utils/toInitData.js");
const toSigner_1 = require("./utils/toSigner.js");
const toWalletClient_1 = require("./utils/toWalletClient.js");
const toNexusAccount = async (parameters) => {
const { chain, transport: transportConfig, signer: _signer, index = 0n, validators: customValidators, executors: customExecutors, hook: customHook, fallbacks: customFallbacks, prevalidationHooks: customPrevalidationHooks, accountAddress: accountAddress_, nexusVersion, attesterThreshold = 1, useK1Config = false } = parameters;
let { initData, factoryAddress = constants_1.NEXUS_ACCOUNT_FACTORY_ADDRESS, bootStrapAddress = constants_1.NEXUS_BOOTSTRAP_ADDRESS, implementationAddress = constants_1.NEXUS_IMPLEMENTATION_ADDRESS, registryAddress, attesters, k1ValidatorAddress, k1FactoryAddress } = parameters;
if (nexusVersion && (0, getVersion_1.isVersionOlder)(nexusVersion, "1.2.0")) {
;
({
factoryAddress,
bootStrapAddress,
implementationAddress,
registryAddress,
attesters,
k1ValidatorAddress,
k1FactoryAddress
} = (0, getVersion_1.getConfigFromNexusVersion)(nexusVersion));
if (useK1Config) {
factoryAddress = k1FactoryAddress;
}
}
const signer = await (0, toSigner_1.toSigner)({ signer: _signer });
const walletClient = (0, toWalletClient_1.toWalletClient)({
unresolvedSigner: _signer,
resolvedSigner: signer,
chain,
transport: transportConfig
});
const publicClient = (0, viem_1.createPublicClient)({ chain, transport: transportConfig });
const defaultValidator = (0, toDefaultModule_1.toDefaultModule)({ signer });
const validators = customValidators || [];
let k1Validator = undefined;
if (useK1Config && k1ValidatorAddress) {
k1Validator = (0, toLegacyK1Module_1.toLegacyK1Module)({
signer,
module: k1ValidatorAddress
});
}
let module = k1Validator || customValidators?.[0] || defaultValidator;
const executors = customExecutors || [];
const hook = customHook || (0, toEmptyHook_1.toEmptyHook)();
const fallbacks = customFallbacks || [];
const prevalidationHooks = customPrevalidationHooks || [];
let factoryData = "0x";
if (useK1Config) {
factoryData = (0, getFactoryData_1.getK1FactoryData)({
signerAddress: signer.address,
index,
attesters: attesters,
attesterThreshold
});
}
else {
if (!initData) {
initData = (0, getFactoryData_1.getInitData)({
defaultValidator: (0, toInitData_1.toInitData)(defaultValidator),
prevalidationHooks,
validators: validators.map(toInitData_1.toInitData),
executors: executors.map(toInitData_1.toInitData),
hook: (0, toInitData_1.toInitData)(hook),
fallbacks: fallbacks.map(toInitData_1.toInitData),
bootStrapAddress,
registryAddress,
attesters,
attesterThreshold,
nexusVersion
});
factoryData = (0, getFactoryData_1.getFactoryData)({ initData, index });
}
}
const getInitCode = () => (0, viem_1.concatHex)([useK1Config ? k1FactoryAddress : factoryAddress, factoryData]);
let _accountAddress = accountAddress_;
const accountId = (await publicClient.readContract({
address: 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 = useK1Config
? await (0, getNexusAddress_1.getK1NexusAddress)({
k1FactoryAddress: k1FactoryAddress,
index,
ownerAddress: signer.address,
attesters: attesters,
attesterThreshold,
publicClient
})
: await (0, getNexusAddress_1.getNexusAddress)({
factoryAddress,
index,
initData: initData,
publicClient
});
if (!(0, Utils_1.addressEquals)(addressFromFactory, viem_1.zeroAddress)) {
_accountAddress = addressFromFactory;
return addressFromFactory;
}
throw new Error("Failed to get account address");
};
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 composableCalls = calls.map((call) => {
return {
to: call.to,
value: call.value ?? 0n,
functionSig: call.functionSig,
inputParams: call.inputParams,
outputParams: call.outputParams
};
});
return (0, viem_1.encodeFunctionData)({
abi: abi_2.COMPOSABILITY_MODULE_ABI,
functionName: "executeComposable",
args: [composableCalls]
});
};
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 { message, primaryType, types: _types, domain } = parameters;
if (!domain)
throw new Error("Missing domain");
if (!message)
throw new Error("Missing message");
const types = {
EIP712Domain: (0, Utils_1.getTypesForEIP712Domain)({ domain }),
..._types
};
const messageStuff = message.stuff;
(0, viem_1.validateTypedData)({
domain,
message,
primaryType,
types
});
const appDomainSeparator = (0, viem_1.domainSeparator)({ domain });
const accountDomainStructFields = await (0, Utils_1.getAccountDomainStructFields)(publicClient, await getAddress());
const parentStructHash = (0, viem_1.keccak256)((0, viem_1.encodePacked)(["bytes", "bytes"], [
(0, viem_1.encodeAbiParameters)((0, viem_1.parseAbiParameters)(["bytes32, bytes32"]), [
(0, viem_1.keccak256)((0, viem_1.toBytes)(Constants_1.PARENT_TYPEHASH)),
messageStuff
]),
accountDomainStructFields
]));
const wrappedTypedHash = (0, Utils_1.eip712WrapHash)(parentStructHash, appDomainSeparator);
let signature = await module.signMessage({ raw: (0, viem_1.toBytes)(wrappedTypedHash) });
const contentsType = (0, viem_1.toBytes)((0, Utils_1.typeToString)(types)[1]);
const signatureData = (0, viem_1.concatHex)([
signature,
appDomainSeparator,
messageStuff,
(0, viem_1.toHex)(contentsType),
(0, viem_1.toHex)(contentsType.length, { size: 2 })
]);
signature = (0, viem_1.encodePacked)(["address", "bytes"], [module.module, signatureData]);
return signature;
}
const setModule = (validationModule) => {
module = validationModule;
};
async function toDelegation(params) {
const { authorization: authorization_, multiChain, delegatedContract } = params || {};
const contractAddress = delegatedContract || implementationAddress;
const authorization = authorization_ ||
(await walletClient.signAuthorization({
contractAddress
}));
const eip7702Auth = {
chainId: `0x${(multiChain ? 0 : chain.id).toString(16)}`,
address: authorization.address,
nonce: `0x${authorization.nonce.toString(16)}`,
r: authorization.r,
s: authorization.s,
v: `0x${authorization.v.toString(16)}`,
yParity: `0x${authorization.yParity.toString(16)}`
};
return eip7702Auth;
}
async function isDelegated() {
const code = await publicClient.getCode({ address: signer.address });
return (!!code &&
code
?.toLowerCase()
.includes(constants_1.NEXUS_IMPLEMENTATION_ADDRESS.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: async () => ({
factory: factoryAddress,
factoryData
}),
getStubSignature: async () => module.getStubSignature(),
async signMessage({ message }) {
const tempSignature = await module.signMessage(message);
return (0, viem_1.encodePacked)(["address", "bytes"], [module.module, tempSignature]);
},
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.signUserOpHash(hash);
},
getNonce,
extend: {
isDelegated,
toDelegation,
unDelegate,
entryPointAddress: account_abstraction_1.entryPoint07Address,
getAddress,
accountId,
getInitCode,
getNonceWithKey,
encodeExecute,
encodeExecuteBatch,
encodeExecuteComposable,
getUserOpHash,
factoryData,
factoryAddress,
registryAddress,
signer,
walletClient,
publicClient,
chain,
setModule,
getModule: () => module
}
});
};
exports.toNexusAccount = toNexusAccount;
//# sourceMappingURL=toNexusAccount.js.map