viem
Version:
719 lines • 24.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.toCoinbaseSmartAccount = toCoinbaseSmartAccount;
exports.sign = sign;
exports.toReplaySafeHash = toReplaySafeHash;
exports.toWebAuthnSignature = toWebAuthnSignature;
exports.wrapSignature = wrapSignature;
const Signature = require("ox/Signature");
const readContract_js_1 = require("../../../actions/public/readContract.js");
const address_js_1 = require("../../../constants/address.js");
const base_js_1 = require("../../../errors/base.js");
const decodeFunctionData_js_1 = require("../../../utils/abi/decodeFunctionData.js");
const encodeAbiParameters_js_1 = require("../../../utils/abi/encodeAbiParameters.js");
const encodeFunctionData_js_1 = require("../../../utils/abi/encodeFunctionData.js");
const encodePacked_js_1 = require("../../../utils/abi/encodePacked.js");
const pad_js_1 = require("../../../utils/data/pad.js");
const size_js_1 = require("../../../utils/data/size.js");
const toHex_js_1 = require("../../../utils/encoding/toHex.js");
const hashMessage_js_1 = require("../../../utils/signature/hashMessage.js");
const hashTypedData_js_1 = require("../../../utils/signature/hashTypedData.js");
const parseSignature_js_1 = require("../../../utils/signature/parseSignature.js");
const abis_js_1 = require("../../constants/abis.js");
const getUserOperationHash_js_1 = require("../../utils/userOperation/getUserOperationHash.js");
const toSmartAccount_js_1 = require("../toSmartAccount.js");
async function toCoinbaseSmartAccount(parameters) {
const { client, ownerIndex = 0, owners, nonce = 0n } = parameters;
let address = parameters.address;
const entryPoint = {
abi: abis_js_1.entryPoint06Abi,
address: address_js_1.entryPoint06Address,
version: '0.6',
};
const factory = {
abi: factoryAbi,
address: '0x0ba5ed0c6aa8c49038f819e587e2633c4a9f428a',
};
const owners_bytes = owners.map((owner) => {
if (typeof owner === 'string')
return (0, pad_js_1.pad)(owner);
if (owner.type === 'webAuthn')
return owner.publicKey;
if (owner.type === 'local')
return (0, pad_js_1.pad)(owner.address);
throw new base_js_1.BaseError('invalid owner type');
});
const owner = (() => {
const owner = owners[ownerIndex] ?? owners[0];
if (typeof owner === 'string')
return { address: owner, type: 'address' };
return owner;
})();
return (0, toSmartAccount_js_1.toSmartAccount)({
client,
entryPoint,
extend: { abi, factory },
async decodeCalls(data) {
const result = (0, decodeFunctionData_js_1.decodeFunctionData)({
abi,
data,
});
if (result.functionName === 'execute')
return [
{ to: result.args[0], value: result.args[1], data: result.args[2] },
];
if (result.functionName === 'executeBatch')
return result.args[0].map((arg) => ({
to: arg.target,
value: arg.value,
data: arg.data,
}));
throw new base_js_1.BaseError(`unable to decode calls for "${result.functionName}"`);
},
async encodeCalls(calls) {
if (calls.length === 1)
return (0, encodeFunctionData_js_1.encodeFunctionData)({
abi,
functionName: 'execute',
args: [calls[0].to, calls[0].value ?? 0n, calls[0].data ?? '0x'],
});
return (0, encodeFunctionData_js_1.encodeFunctionData)({
abi,
functionName: 'executeBatch',
args: [
calls.map((call) => ({
data: call.data ?? '0x',
target: call.to,
value: call.value ?? 0n,
})),
],
});
},
async getAddress() {
address ??= await (0, readContract_js_1.readContract)(client, {
...factory,
functionName: 'getAddress',
args: [owners_bytes, nonce],
});
return address;
},
async getFactoryArgs() {
const factoryData = (0, encodeFunctionData_js_1.encodeFunctionData)({
abi: factory.abi,
functionName: 'createAccount',
args: [owners_bytes, nonce],
});
return { factory: factory.address, factoryData };
},
async getStubSignature() {
if (owner.type === 'webAuthn')
return '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000001949fc7c88032b9fcb5f6efc7a7b8c63668eae9871b765e23123bb473ff57aa831a7c0d9276168ebcc29f2875a0239cffdf2a9cd1c2007c5c77c071db9264df1d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273496a396e6164474850596759334b7156384f7a4a666c726275504b474f716d59576f4d57516869467773222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d00000000000000000000000000000000000000000000';
return wrapSignature({
ownerIndex,
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c',
});
},
async sign(parameters) {
const address = await this.getAddress();
const hash = toReplaySafeHash({
address,
chainId: client.chain.id,
hash: parameters.hash,
});
if (owner.type === 'address')
throw new Error('owner cannot sign');
const signature = await sign({ hash, owner });
return wrapSignature({
ownerIndex,
signature,
});
},
async signMessage(parameters) {
const { message } = parameters;
const address = await this.getAddress();
const hash = toReplaySafeHash({
address,
chainId: client.chain.id,
hash: (0, hashMessage_js_1.hashMessage)(message),
});
if (owner.type === 'address')
throw new Error('owner cannot sign');
const signature = await sign({ hash, owner });
return wrapSignature({
ownerIndex,
signature,
});
},
async signTypedData(parameters) {
const { domain, types, primaryType, message } = parameters;
const address = await this.getAddress();
const hash = toReplaySafeHash({
address,
chainId: client.chain.id,
hash: (0, hashTypedData_js_1.hashTypedData)({
domain,
message,
primaryType,
types,
}),
});
if (owner.type === 'address')
throw new Error('owner cannot sign');
const signature = await sign({ hash, owner });
return wrapSignature({
ownerIndex,
signature,
});
},
async signUserOperation(parameters) {
const { chainId = client.chain.id, ...userOperation } = parameters;
const address = await this.getAddress();
const hash = (0, getUserOperationHash_js_1.getUserOperationHash)({
chainId,
entryPointAddress: entryPoint.address,
entryPointVersion: entryPoint.version,
userOperation: {
...userOperation,
sender: address,
},
});
if (owner.type === 'address')
throw new Error('owner cannot sign');
const signature = await sign({ hash, owner });
return wrapSignature({
ownerIndex,
signature,
});
},
userOperation: {
async estimateGas(userOperation) {
if (owner.type !== 'webAuthn')
return;
return {
verificationGasLimit: BigInt(Math.max(Number(userOperation.verificationGasLimit ?? 0n), 800_000)),
};
},
},
});
}
async function sign({ hash, owner, }) {
if (owner.type === 'webAuthn') {
const { signature, webauthn } = await owner.sign({
hash,
});
return toWebAuthnSignature({ signature, webauthn });
}
if (owner.sign)
return owner.sign({ hash });
throw new base_js_1.BaseError('`owner` does not support raw sign.');
}
function toReplaySafeHash({ address, chainId, hash, }) {
return (0, hashTypedData_js_1.hashTypedData)({
domain: {
chainId,
name: 'Coinbase Smart Wallet',
verifyingContract: address,
version: '1',
},
types: {
CoinbaseSmartWalletMessage: [
{
name: 'hash',
type: 'bytes32',
},
],
},
primaryType: 'CoinbaseSmartWalletMessage',
message: {
hash,
},
});
}
function toWebAuthnSignature({ webauthn, signature, }) {
const { r, s } = Signature.fromHex(signature);
return (0, encodeAbiParameters_js_1.encodeAbiParameters)([
{
components: [
{
name: 'authenticatorData',
type: 'bytes',
},
{ name: 'clientDataJSON', type: 'bytes' },
{ name: 'challengeIndex', type: 'uint256' },
{ name: 'typeIndex', type: 'uint256' },
{
name: 'r',
type: 'uint256',
},
{
name: 's',
type: 'uint256',
},
],
type: 'tuple',
},
], [
{
authenticatorData: webauthn.authenticatorData,
clientDataJSON: (0, toHex_js_1.stringToHex)(webauthn.clientDataJSON),
challengeIndex: BigInt(webauthn.challengeIndex),
typeIndex: BigInt(webauthn.typeIndex),
r,
s,
},
]);
}
function wrapSignature(parameters) {
const { ownerIndex = 0 } = parameters;
const signatureData = (() => {
if ((0, size_js_1.size)(parameters.signature) !== 65)
return parameters.signature;
const signature = (0, parseSignature_js_1.parseSignature)(parameters.signature);
return (0, encodePacked_js_1.encodePacked)(['bytes32', 'bytes32', 'uint8'], [signature.r, signature.s, signature.yParity === 0 ? 27 : 28]);
})();
return (0, encodeAbiParameters_js_1.encodeAbiParameters)([
{
components: [
{
name: 'ownerIndex',
type: 'uint8',
},
{
name: 'signatureData',
type: 'bytes',
},
],
type: 'tuple',
},
], [
{
ownerIndex,
signatureData,
},
]);
}
const abi = [
{ inputs: [], stateMutability: 'nonpayable', type: 'constructor' },
{
inputs: [{ name: 'owner', type: 'bytes' }],
name: 'AlreadyOwner',
type: 'error',
},
{ inputs: [], name: 'Initialized', type: 'error' },
{
inputs: [{ name: 'owner', type: 'bytes' }],
name: 'InvalidEthereumAddressOwner',
type: 'error',
},
{
inputs: [{ name: 'key', type: 'uint256' }],
name: 'InvalidNonceKey',
type: 'error',
},
{
inputs: [{ name: 'owner', type: 'bytes' }],
name: 'InvalidOwnerBytesLength',
type: 'error',
},
{ inputs: [], name: 'LastOwner', type: 'error' },
{
inputs: [{ name: 'index', type: 'uint256' }],
name: 'NoOwnerAtIndex',
type: 'error',
},
{
inputs: [{ name: 'ownersRemaining', type: 'uint256' }],
name: 'NotLastOwner',
type: 'error',
},
{
inputs: [{ name: 'selector', type: 'bytes4' }],
name: 'SelectorNotAllowed',
type: 'error',
},
{ inputs: [], name: 'Unauthorized', type: 'error' },
{ inputs: [], name: 'UnauthorizedCallContext', type: 'error' },
{ inputs: [], name: 'UpgradeFailed', type: 'error' },
{
inputs: [
{ name: 'index', type: 'uint256' },
{ name: 'expectedOwner', type: 'bytes' },
{ name: 'actualOwner', type: 'bytes' },
],
name: 'WrongOwnerAtIndex',
type: 'error',
},
{
anonymous: false,
inputs: [
{
indexed: true,
name: 'index',
type: 'uint256',
},
{ indexed: false, name: 'owner', type: 'bytes' },
],
name: 'AddOwner',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: true,
name: 'index',
type: 'uint256',
},
{ indexed: false, name: 'owner', type: 'bytes' },
],
name: 'RemoveOwner',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: true,
name: 'implementation',
type: 'address',
},
],
name: 'Upgraded',
type: 'event',
},
{ stateMutability: 'payable', type: 'fallback' },
{
inputs: [],
name: 'REPLAYABLE_NONCE_KEY',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [{ name: 'owner', type: 'address' }],
name: 'addOwnerAddress',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [
{ name: 'x', type: 'bytes32' },
{ name: 'y', type: 'bytes32' },
],
name: 'addOwnerPublicKey',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [{ name: 'functionSelector', type: 'bytes4' }],
name: 'canSkipChainIdValidation',
outputs: [{ name: '', type: 'bool' }],
stateMutability: 'pure',
type: 'function',
},
{
inputs: [],
name: 'domainSeparator',
outputs: [{ name: '', type: 'bytes32' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'eip712Domain',
outputs: [
{ name: 'fields', type: 'bytes1' },
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
{ name: 'salt', type: 'bytes32' },
{ name: 'extensions', type: 'uint256[]' },
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'entryPoint',
outputs: [{ name: '', type: 'address' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ name: 'target', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'data', type: 'bytes' },
],
name: 'execute',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{
components: [
{ name: 'target', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'data', type: 'bytes' },
],
name: 'calls',
type: 'tuple[]',
},
],
name: 'executeBatch',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [{ name: 'calls', type: 'bytes[]' }],
name: 'executeWithoutChainIdValidation',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{
components: [
{ name: 'sender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'initCode', type: 'bytes' },
{ name: 'callData', type: 'bytes' },
{ name: 'callGasLimit', type: 'uint256' },
{
name: 'verificationGasLimit',
type: 'uint256',
},
{
name: 'preVerificationGas',
type: 'uint256',
},
{ name: 'maxFeePerGas', type: 'uint256' },
{
name: 'maxPriorityFeePerGas',
type: 'uint256',
},
{ name: 'paymasterAndData', type: 'bytes' },
{ name: 'signature', type: 'bytes' },
],
name: 'userOp',
type: 'tuple',
},
],
name: 'getUserOpHashWithoutChainId',
outputs: [{ name: '', type: 'bytes32' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'implementation',
outputs: [{ name: '$', type: 'address' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [{ name: 'owners', type: 'bytes[]' }],
name: 'initialize',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [{ name: 'account', type: 'address' }],
name: 'isOwnerAddress',
outputs: [{ name: '', type: 'bool' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [{ name: 'account', type: 'bytes' }],
name: 'isOwnerBytes',
outputs: [{ name: '', type: 'bool' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ name: 'x', type: 'bytes32' },
{ name: 'y', type: 'bytes32' },
],
name: 'isOwnerPublicKey',
outputs: [{ name: '', type: 'bool' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ name: 'hash', type: 'bytes32' },
{ name: 'signature', type: 'bytes' },
],
name: 'isValidSignature',
outputs: [{ name: 'result', type: 'bytes4' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'nextOwnerIndex',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [{ name: 'index', type: 'uint256' }],
name: 'ownerAtIndex',
outputs: [{ name: '', type: 'bytes' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'ownerCount',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'proxiableUUID',
outputs: [{ name: '', type: 'bytes32' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ name: 'index', type: 'uint256' },
{ name: 'owner', type: 'bytes' },
],
name: 'removeLastOwner',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [
{ name: 'index', type: 'uint256' },
{ name: 'owner', type: 'bytes' },
],
name: 'removeOwnerAtIndex',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [],
name: 'removedOwnersCount',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [{ name: 'hash', type: 'bytes32' }],
name: 'replaySafeHash',
outputs: [{ name: '', type: 'bytes32' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ name: 'newImplementation', type: 'address' },
{ name: 'data', type: 'bytes' },
],
name: 'upgradeToAndCall',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{
components: [
{ name: 'sender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'initCode', type: 'bytes' },
{ name: 'callData', type: 'bytes' },
{ name: 'callGasLimit', type: 'uint256' },
{
name: 'verificationGasLimit',
type: 'uint256',
},
{
name: 'preVerificationGas',
type: 'uint256',
},
{ name: 'maxFeePerGas', type: 'uint256' },
{
name: 'maxPriorityFeePerGas',
type: 'uint256',
},
{ name: 'paymasterAndData', type: 'bytes' },
{ name: 'signature', type: 'bytes' },
],
name: 'userOp',
type: 'tuple',
},
{ name: 'userOpHash', type: 'bytes32' },
{ name: 'missingAccountFunds', type: 'uint256' },
],
name: 'validateUserOp',
outputs: [{ name: 'validationData', type: 'uint256' }],
stateMutability: 'nonpayable',
type: 'function',
},
{ stateMutability: 'payable', type: 'receive' },
];
const factoryAbi = [
{
inputs: [{ name: 'implementation_', type: 'address' }],
stateMutability: 'payable',
type: 'constructor',
},
{ inputs: [], name: 'OwnerRequired', type: 'error' },
{
inputs: [
{ name: 'owners', type: 'bytes[]' },
{ name: 'nonce', type: 'uint256' },
],
name: 'createAccount',
outputs: [
{
name: 'account',
type: 'address',
},
],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{ name: 'owners', type: 'bytes[]' },
{ name: 'nonce', type: 'uint256' },
],
name: 'getAddress',
outputs: [{ name: '', type: 'address' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'implementation',
outputs: [{ name: '', type: 'address' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'initCodeHash',
outputs: [{ name: '', type: 'bytes32' }],
stateMutability: 'view',
type: 'function',
},
];
//# sourceMappingURL=toCoinbaseSmartAccount.js.map
;