@alchemy/aa-core
Version:
viem based SDK that enables interactions with ERC-4337 Smart Accounts. ABIs are based off the definitions generated in @account-abstraction/contracts
257 lines • 10.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseSmartContractAccount = exports.DeploymentState = void 0;
const viem_1 = require("viem");
const EntryPointAbi_v6_js_1 = require("../abis/EntryPointAbi_v6.js");
const bundlerClient_js_1 = require("../client/bundlerClient.js");
const index_js_1 = require("../entrypoint/index.js");
const account_js_1 = require("../errors/account.js");
const client_js_1 = require("../errors/client.js");
const logger_js_1 = require("../logger.js");
const utils_js_1 = require("../signer/utils.js");
const schema_js_1 = require("./schema.js");
var DeploymentState;
(function (DeploymentState) {
DeploymentState["UNDEFINED"] = "0x0";
DeploymentState["NOT_DEPLOYED"] = "0x1";
DeploymentState["DEPLOYED"] = "0x2";
})(DeploymentState || (exports.DeploymentState = DeploymentState = {}));
class BaseSmartContractAccount {
constructor(params_) {
Object.defineProperty(this, "factoryAddress", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "deploymentState", {
enumerable: true,
configurable: true,
writable: true,
value: DeploymentState.UNDEFINED
});
Object.defineProperty(this, "accountAddress", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "accountInitCode", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "signer", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "entryPoint", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "entryPointAddress", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "rpcProvider", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "encodeUpgradeToAndCall", {
enumerable: true,
configurable: true,
writable: true,
value: async (_upgradeToImplAddress, _upgradeToInitData) => {
throw new account_js_1.UpgradeToAndCallNotSupportedError("BaseAccount");
}
});
Object.defineProperty(this, "extend", {
enumerable: true,
configurable: true,
writable: true,
value: (fn) => {
const extended = fn(this);
for (const key in this) {
delete extended[key];
}
return Object.assign(this, extended);
}
});
const params = (0, schema_js_1.createBaseSmartAccountParamsSchema)().parse(params_);
this.entryPointAddress =
params.entryPointAddress ?? (0, index_js_1.getEntryPoint)(params.chain).address;
const rpcUrl = typeof params.rpcClient === "string"
? params.rpcClient
: params.rpcClient.transport.type === "http"
? params.rpcClient.transport.url || params.chain.rpcUrls.default.http[0]
: undefined;
const fetchOptions = typeof params.rpcClient === "string"
? undefined
: params.rpcClient.transport.type === "http"
? params.rpcClient.transport.fetchOptions
: undefined;
this.rpcProvider = rpcUrl
? (0, bundlerClient_js_1.createBundlerClient)({
chain: params.chain,
transport: (0, viem_1.http)(rpcUrl, {
fetchOptions: {
...fetchOptions,
headers: {
...fetchOptions?.headers,
...(rpcUrl.toLowerCase().indexOf("alchemy") > -1
? {
"Alchemy-Aa-Sdk-Signer": params.signer?.signerType || "unknown",
"Alchemy-Aa-Sdk-Factory-Address": params.factoryAddress,
}
: undefined),
},
},
}),
})
: params.rpcClient;
this.accountAddress = params.accountAddress;
this.factoryAddress = params.factoryAddress;
this.signer = params.signer;
this.accountInitCode = params.initCode;
this.entryPoint = (0, viem_1.getContract)({
address: this.entryPointAddress,
abi: EntryPointAbi_v6_js_1.EntryPointAbi_v6,
client: this.rpcProvider,
});
}
async signUserOperationHash(uoHash) {
return this.signMessage(uoHash);
}
async signTypedData(_params) {
throw new Error("signTypedData not supported");
}
async signMessageWith6492(msg) {
const [isDeployed, signature] = await Promise.all([
this.isAccountDeployed(),
this.signMessage(msg),
]);
return this.create6492Signature(isDeployed, signature);
}
async signTypedDataWith6492(params) {
const [isDeployed, signature] = await Promise.all([
this.isAccountDeployed(),
this.signTypedData(params),
]);
return this.create6492Signature(isDeployed, signature);
}
async encodeBatchExecute(_txs) {
throw new account_js_1.BatchExecutionNotSupportedError("BaseAccount");
}
async getNonce() {
if (!(await this.isAccountDeployed())) {
return 0n;
}
const address = await this.getAddress();
return this.entryPoint.read.getNonce([address, BigInt(0)]);
}
async getInitCode() {
if (this.deploymentState === DeploymentState.DEPLOYED) {
return "0x";
}
const contractCode = await this.rpcProvider.getBytecode({
address: await this.getAddress(),
});
if ((contractCode?.length ?? 0) > 2) {
this.deploymentState = DeploymentState.DEPLOYED;
return "0x";
}
else {
this.deploymentState = DeploymentState.NOT_DEPLOYED;
}
return this._getAccountInitCode();
}
async getAddress() {
if (!this.accountAddress) {
const initCode = await this._getAccountInitCode();
logger_js_1.Logger.verbose("[BaseSmartContractAccount](getAddress) initCode: ", initCode);
try {
await this.entryPoint.simulate.getSenderAddress([initCode]);
}
catch (err) {
logger_js_1.Logger.verbose("[BaseSmartContractAccount](getAddress) getSenderAddress err: ", err);
if (err.cause?.data?.errorName === "SenderAddressResult") {
this.accountAddress = err.cause.data.args[0];
logger_js_1.Logger.verbose("[BaseSmartContractAccount](getAddress) entryPoint.getSenderAddress result:", this.accountAddress);
return this.accountAddress;
}
if (err.details === "Invalid URL") {
throw new client_js_1.InvalidRpcUrlError();
}
}
throw new account_js_1.GetCounterFactualAddressError();
}
return this.accountAddress;
}
getSigner() {
return this.signer;
}
getFactoryAddress() {
return this.factoryAddress;
}
getEntryPointAddress() {
return this.entryPointAddress;
}
async isAccountDeployed() {
return (await this.getDeploymentState()) === DeploymentState.DEPLOYED;
}
async getDeploymentState() {
if (this.deploymentState === DeploymentState.UNDEFINED) {
const initCode = await this.getInitCode();
return initCode === "0x"
? DeploymentState.DEPLOYED
: DeploymentState.NOT_DEPLOYED;
}
else {
return this.deploymentState;
}
}
async parseFactoryAddressFromAccountInitCode() {
const initCode = await this._getAccountInitCode();
const factoryAddress = `0x${initCode.substring(2, 42)}`;
const factoryCalldata = `0x${initCode.substring(42)}`;
return [factoryAddress, factoryCalldata];
}
async getImplementationAddress() {
const accountAddress = await this.getAddress();
const storage = await this.rpcProvider.getStorageAt({
address: accountAddress,
slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
});
if (storage == null) {
throw new account_js_1.FailedToGetStorageSlotError("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", "Proxy Implementation Address");
}
return (0, viem_1.trim)(storage);
}
async _getAccountInitCode() {
return this.accountInitCode ?? this.getAccountInitCode();
}
async create6492Signature(isDeployed, signature) {
if (isDeployed) {
return signature;
}
const [factoryAddress, factoryCalldata] = await this.parseFactoryAddressFromAccountInitCode();
logger_js_1.Logger.verbose(`[BaseSmartContractAccount](create6492Signature)\
factoryAddress: ${factoryAddress}, factoryCalldata: ${factoryCalldata}`);
return (0, utils_js_1.wrapSignatureWith6492)({
factoryAddress,
factoryCalldata,
signature,
});
}
}
exports.BaseSmartContractAccount = BaseSmartContractAccount;
//# sourceMappingURL=base.js.map