@metamask/delegation-toolkit
Version:
The Delegation Toolkit built on top of Viem - a library for interacting with DeleGator Smart Accounts
392 lines (386 loc) • 11.4 kB
JavaScript
import {
actions_exports,
caveatEnforcerActions,
isValid7702Implementation
} from "./chunk-BCY32INP.mjs";
import {
contracts_exports,
read
} from "./chunk-2C2RCEPU.mjs";
import "./chunk-H6FRBM25.mjs";
import {
Implementation,
SIGNABLE_USER_OP_TYPED_DATA,
createDummyWebAuthnSignature,
encodeCallsForCaller,
encodeDeleGatorSignature,
getCounterfactualAccountData,
signUserOperation
} from "./chunk-GODU24FS.mjs";
import "./chunk-MOTJRLZE.mjs";
import {
PREFERRED_VERSION,
getDeleGatorEnvironment,
redeemDelegations
} from "./chunk-HNRGEUMP.mjs";
import {
ExecutionMode,
createExecution
} from "./chunk-CPLIK3VF.mjs";
import {
ANY_BENEFICIARY,
BalanceChangeType,
ROOT_AUTHORITY,
SIGNABLE_DELEGATION_TYPED_DATA,
createCaveat,
createDelegation,
createOpenDelegation,
signDelegation,
toDelegationStruct
} from "./chunk-ONC4XUYQ.mjs";
// src/toMetaMaskSmartAccount.ts
import {
EIP7702StatelessDeleGator,
HybridDeleGator,
MultiSigDeleGator
} from "@metamask/delegation-abis";
import {
entryPoint07Abi,
toPackedUserOperation,
toSmartAccount
} from "viem/account-abstraction";
// src/signatory.ts
import { concat as concat2 } from "viem";
// src/signatures.ts
import { concat } from "viem";
var signatureTypes = ["ECDSA"];
var aggregateSignature = ({
signatures
}) => {
if (signatures.length === 0) {
return "0x";
}
for (const { type } of signatures) {
if (!signatureTypes.includes(type)) {
throw new Error(`Invalid signature type: ${type}`);
}
}
const sortedSignatures = [...signatures].sort(
(a, b) => a.signer.localeCompare(b.signer)
);
return concat(sortedSignatures.map(({ signature }) => signature));
};
// src/signatory.ts
var EOA_STUB_SIGNATURE = "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000011b";
var resolveSignatoryFromWalletConfig = (config) => {
return {
signMessage: config.walletClient.signMessage,
signTypedData: async (typedData) => {
return config.walletClient.signTypedData(typedData);
},
getStubSignature: async () => EOA_STUB_SIGNATURE
};
};
var resolveSignatoryFromAccountConfig = (config) => {
return {
signMessage: config.account.signMessage,
signTypedData: config.account.signTypedData,
getStubSignature: async () => EOA_STUB_SIGNATURE
};
};
var resolveHybridSignatory = (config) => {
if ("walletClient" in config) {
return resolveSignatoryFromWalletConfig(config);
} else if ("account" in config) {
const { signMessage: signMessage2, signTypedData: signTypedData2, getStubSignature: getStubSignature2 } = resolveSignatoryFromAccountConfig(config);
if (!signMessage2) {
throw new Error("Account does not support signMessage");
}
if (!signTypedData2) {
throw new Error("Account does not support signTypedData");
}
return {
signMessage: signMessage2,
signTypedData: signTypedData2,
getStubSignature: getStubSignature2
};
}
const { keyId, webAuthnAccount } = config;
if (webAuthnAccount.type !== "webAuthn") {
throw new Error("Account is not a webAuthn account");
}
const encodeSignature = ({ signature, webauthn }) => encodeDeleGatorSignature(
keyId,
signature,
webauthn.clientDataJSON,
webauthn.authenticatorData
);
const signMessage = async (args) => webAuthnAccount.signMessage(args).then(encodeSignature);
const signTypedData = async (typedDataDefinition) => webAuthnAccount.signTypedData(typedDataDefinition).then(encodeSignature);
const getStubSignature = async () => createDummyWebAuthnSignature(keyId);
return {
signMessage,
signTypedData,
getStubSignature
};
};
var resolveMultiSigSignatory = (config) => {
const resolvedSignatories = config.map((signatory) => {
let individualSignMessage;
let individualSignTypedData;
let address;
if ("walletClient" in signatory) {
const { signMessage: signMessage2, signTypedData: signTypedData2 } = resolveSignatoryFromWalletConfig(signatory);
individualSignMessage = signMessage2;
individualSignTypedData = signTypedData2;
address = signatory.walletClient.account.address;
} else {
const { signMessage: signMessage2, signTypedData: signTypedData2 } = resolveSignatoryFromAccountConfig(signatory);
if (!signMessage2) {
throw new Error("Account does not support signMessage");
}
if (!signTypedData2) {
throw new Error("Account does not support signTypedData");
}
individualSignMessage = signMessage2;
individualSignTypedData = signTypedData2;
address = signatory.account.address;
}
return {
address,
individualSignMessage,
individualSignTypedData
};
});
const signMessage = async (args) => {
const addressAndSignatures = resolvedSignatories.map(
async ({ individualSignMessage, address }) => ({
signature: await individualSignMessage(args),
signer: address,
type: "ECDSA"
})
);
const signatures = await Promise.all(addressAndSignatures);
return aggregateSignature({
signatures
});
};
const signTypedData = async (typedDataDefinition) => {
const addressAndSignatures = resolvedSignatories.map(
async ({ individualSignTypedData, address }) => ({
signature: await individualSignTypedData(typedDataDefinition),
signer: address,
type: "ECDSA"
})
);
const signatures = await Promise.all(addressAndSignatures);
return aggregateSignature({
signatures
});
};
const getStubSignature = async () => concat2(resolvedSignatories.map(() => EOA_STUB_SIGNATURE));
return {
signMessage,
signTypedData,
getStubSignature
};
};
var resolveStateless7702Signatory = (config) => {
if ("walletClient" in config) {
return resolveSignatoryFromWalletConfig(config);
} else if ("account" in config) {
const { signMessage, signTypedData, getStubSignature } = resolveSignatoryFromAccountConfig(config);
if (!signMessage) {
throw new Error("Account does not support signMessage");
}
if (!signTypedData) {
throw new Error("Account does not support signTypedData");
}
return {
signMessage,
signTypedData,
getStubSignature
};
}
throw new Error("Invalid signatory config");
};
var resolveSignatory = (config) => {
const { implementation } = config;
if (implementation === "Hybrid" /* Hybrid */) {
return resolveHybridSignatory(config.signatory);
} else if (implementation === "MultiSig" /* MultiSig */) {
return resolveMultiSigSignatory(
config.signatory
);
} else if (implementation === "Stateless7702" /* Stateless7702 */) {
return resolveStateless7702Signatory(
config.signatory
);
}
throw new Error(`Implementation type '${implementation}' not supported`);
};
// src/toMetaMaskSmartAccount.ts
var ENTRYPOINT_VERSION = "0.7";
async function toMetaMaskSmartAccount(params) {
const {
client,
client: { chain },
implementation
} = params;
if (!chain) {
throw new Error("Chain not specified");
}
const signatory = resolveSignatory({
implementation,
signatory: params.signatory
});
const environment = params.environment ?? getDeleGatorEnvironment(chain.id);
let address, factoryData;
if (params.address) {
factoryData = void 0;
address = params.address;
} else {
if (implementation === "Stateless7702" /* Stateless7702 */) {
throw new Error("Stateless7702 does not support counterfactual accounts");
}
const accountData = await getCounterfactualAccountData({
factory: environment.SimpleFactory,
implementations: environment.implementations,
implementation,
deployParams: params.deployParams,
deploySalt: params.deploySalt
});
address = accountData.address;
factoryData = accountData.factoryData;
}
const entryPoint = {
abi: entryPoint07Abi,
address: environment.EntryPoint,
version: ENTRYPOINT_VERSION
};
const { abi, contractName } = {
["Hybrid" /* Hybrid */]: {
contractName: "HybridDeleGator",
abi: HybridDeleGator.abi
},
["MultiSig" /* MultiSig */]: {
contractName: "MultiSigDeleGator",
abi: MultiSigDeleGator.abi
},
["Stateless7702" /* Stateless7702 */]: {
contractName: "EIP7702StatelessDeleGator",
abi: EIP7702StatelessDeleGator.abi
}
}[implementation];
const getFactoryArgs = async () => {
if (factoryData === void 0) {
throw new Error(
"Deploy params were not provided, so factory args cannot be inferred"
);
}
return {
factoryData,
factory: environment.SimpleFactory
};
};
const signDelegation2 = async (delegationParams) => {
const { delegation, chainId } = delegationParams;
const delegationStruct = toDelegationStruct({
...delegation,
signature: "0x"
});
const signature = signatory.signTypedData({
domain: {
chainId: chainId ?? chain.id,
name: "DelegationManager",
version: "1",
verifyingContract: environment.DelegationManager
},
types: SIGNABLE_DELEGATION_TYPED_DATA,
primaryType: "Delegation",
message: delegationStruct
});
return signature;
};
const signUserOperation2 = async (userOpParams) => {
const { chainId } = userOpParams;
const packedUserOp = toPackedUserOperation({
sender: address,
...userOpParams,
signature: "0x"
});
const signature = await signatory.signTypedData({
domain: {
chainId: chainId ?? chain.id,
name: contractName,
version: "1",
verifyingContract: address
},
types: SIGNABLE_USER_OP_TYPED_DATA,
primaryType: "PackedUserOperation",
message: { ...packedUserOp, entryPoint: entryPoint.address }
});
return signature;
};
const getAddress = async () => address;
const getNonce = async () => read({
client,
entryPoint: environment.EntryPoint,
contractAddress: address,
key: 0n
});
const encodeCalls = async (calls) => encodeCallsForCaller(address, calls);
const smartAccount = await toSmartAccount({
abi,
client,
entryPoint,
environment,
getAddress,
getFactoryArgs,
encodeCalls,
getNonce,
signUserOperation: signUserOperation2,
signDelegation: signDelegation2,
...signatory
});
if (implementation === "Stateless7702" /* Stateless7702 */) {
return {
...smartAccount,
isDeployed: async () => isValid7702Implementation({
client,
accountAddress: address,
environment
})
};
}
return smartAccount;
}
// src/actions/caveatEnforcerClient.ts
function createCaveatEnforcerClient({
client,
environment
}) {
return client.extend(caveatEnforcerActions({ environment }));
}
export {
ANY_BENEFICIARY,
BalanceChangeType,
ExecutionMode,
Implementation,
PREFERRED_VERSION,
ROOT_AUTHORITY,
actions_exports as actions,
aggregateSignature,
contracts_exports as contracts,
createCaveat,
createCaveatEnforcerClient,
createDelegation,
createExecution,
createOpenDelegation,
getDeleGatorEnvironment,
redeemDelegations,
signDelegation,
signUserOperation,
toMetaMaskSmartAccount
};
//# sourceMappingURL=index.mjs.map