viem
Version:
579 lines • 22.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.authorize = authorize;
exports.authorizeSync = authorizeSync;
exports.burnWitness = burnWitness;
exports.burnWitnessSync = burnWitnessSync;
exports.getMetadata = getMetadata;
exports.getRemainingLimit = getRemainingLimit;
exports.isAdmin = isAdmin;
exports.isWitnessBurned = isWitnessBurned;
exports.revoke = revoke;
exports.revokeSync = revokeSync;
exports.prepareAuthorization = prepareAuthorization;
exports.signAuthorization = signAuthorization;
exports.updateLimit = updateLimit;
exports.updateLimitSync = updateLimitSync;
exports.watchAdminAuthorized = watchAdminAuthorized;
exports.watchWitness = watchWitness;
exports.watchWitnessBurned = watchWitnessBurned;
exports.verifyHash = verifyHash;
const tempo_1 = require("ox/tempo");
const parseAccount_js_1 = require("../../accounts/utils/parseAccount.js");
const readContract_js_1 = require("../../actions/public/readContract.js");
const watchContractEvent_js_1 = require("../../actions/public/watchContractEvent.js");
const sendTransaction_js_1 = require("../../actions/wallet/sendTransaction.js");
const sendTransactionSync_js_1 = require("../../actions/wallet/sendTransactionSync.js");
const writeContract_js_1 = require("../../actions/wallet/writeContract.js");
const writeContractSync_js_1 = require("../../actions/wallet/writeContractSync.js");
const parseEventLogs_js_1 = require("../../utils/abi/parseEventLogs.js");
const isAddressEqual_js_1 = require("../../utils/address/isAddressEqual.js");
const Abis = require("../Abis.js");
const Account_js_1 = require("../Account.js");
const Addresses = require("../Addresses.js");
const Hardfork = require("../Hardfork.js");
const utils_js_1 = require("../internal/utils.js");
const Signature_js_1 = require("../multisig/Signature.js");
const multisig_js_1 = require("./multisig.js");
const signatureTypes = {
0: 'secp256k1',
1: 'p256',
2: 'webAuthn',
};
const spendPolicies = {
true: 'limited',
false: 'unlimited',
};
async function authorize(client, parameters) {
return authorize.inner(sendTransaction_js_1.sendTransaction, client, parameters);
}
(function (authorize) {
async function inner(action, client, parameters) {
const { accessKey, admin, chainId = client.chain?.id, expiry, limits, scopes, witness, ...rest } = parameters;
const account_ = rest.account ?? client.account;
if (!account_)
throw new Error('account is required.');
if (!chainId)
throw new Error('chainId is required.');
const keyAuthorization = await signAuthorization(client, {
account: account_,
accessKey,
chainId,
admin,
expiry,
limits,
scopes,
witness,
});
return (await action(client, {
...rest,
keyAuthorization,
}));
}
authorize.inner = inner;
function extractEvent(logs) {
const [log] = (0, parseEventLogs_js_1.parseEventLogs)({
abi: Abis.accountKeychain,
logs,
eventName: 'KeyAuthorized',
strict: true,
});
if (!log)
throw new Error('`KeyAuthorized` event not found.');
return log;
}
authorize.extractEvent = extractEvent;
})(authorize || (exports.authorize = authorize = {}));
async function authorizeSync(client, parameters) {
const { throwOnReceiptRevert = true, ...rest } = parameters;
const receipt = await authorize.inner(sendTransactionSync_js_1.sendTransactionSync, client, {
...rest,
throwOnReceiptRevert,
});
if (receipt.status === 'pending')
return { receipt };
const { args } = authorize.extractEvent(receipt.logs);
return {
...args,
receipt,
};
}
async function burnWitness(client, parameters) {
return burnWitness.inner(writeContract_js_1.writeContract, client, parameters);
}
(function (burnWitness) {
async function inner(action, client, parameters) {
const { witness, ...rest } = parameters;
const call = burnWitness.call({ witness });
return (await action(client, {
...rest,
...call,
}));
}
burnWitness.inner = inner;
function call(args) {
const { witness } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'burnKeyAuthorizationWitness',
args: [witness],
});
}
burnWitness.call = call;
function extractEvent(logs) {
const [log] = (0, parseEventLogs_js_1.parseEventLogs)({
abi: Abis.accountKeychain,
logs,
eventName: 'KeyAuthorizationWitnessBurned',
strict: true,
});
if (!log)
throw new Error('`KeyAuthorizationWitnessBurned` event not found.');
return log;
}
burnWitness.extractEvent = extractEvent;
})(burnWitness || (exports.burnWitness = burnWitness = {}));
async function burnWitnessSync(client, parameters) {
const { throwOnReceiptRevert = true, ...rest } = parameters;
const receipt = await burnWitness.inner(writeContractSync_js_1.writeContractSync, client, {
...rest,
throwOnReceiptRevert,
});
if (receipt.status === 'pending')
return { receipt };
const { args } = burnWitness.extractEvent(receipt.logs);
return {
...args,
receipt,
};
}
async function getMetadata(client, parameters) {
const { account: account_ = client.account, accessKey, ...rest } = parameters;
if (!account_)
throw new Error('account is required.');
const account = (0, parseAccount_js_1.parseAccount)(account_);
const result = await (0, readContract_js_1.readContract)(client, {
...rest,
account: null,
...getMetadata.call({ account: account.address, accessKey }),
});
return {
address: result.keyId,
keyType: signatureTypes[result.signatureType] ??
'secp256k1',
expiry: result.expiry,
spendPolicy: spendPolicies[`${result.enforceLimits}`],
isRevoked: result.isRevoked,
};
}
(function (getMetadata) {
function call(args) {
const { account, accessKey } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'getKey',
args: [account, resolveAccessKeyAddress(accessKey)],
});
}
getMetadata.call = call;
})(getMetadata || (exports.getMetadata = getMetadata = {}));
async function getRemainingLimit(client, parameters) {
const { account: account_ = client.account, accessKey, token, ...rest } = parameters;
if (!account_)
throw new Error('account is required.');
const account = (0, parseAccount_js_1.parseAccount)(account_);
const hardfork = client.chain?.hardfork;
if (hardfork && Hardfork.lt(hardfork, 't3')) {
const remaining = await (0, readContract_js_1.readContract)(client, {
...rest,
...getRemainingLimit.call({ account: account.address, accessKey, token }),
});
return { remaining, periodEnd: undefined };
}
const [remaining, periodEnd] = await (0, readContract_js_1.readContract)(client, {
...rest,
...getRemainingLimit.callWithPeriod({
account: account.address,
accessKey,
token,
}),
});
return { remaining, periodEnd };
}
(function (getRemainingLimit) {
function call(args) {
const { account, accessKey, token } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'getRemainingLimit',
args: [account, resolveAccessKeyAddress(accessKey), token],
});
}
getRemainingLimit.call = call;
function callWithPeriod(args) {
const { account, accessKey, token } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'getRemainingLimitWithPeriod',
args: [account, resolveAccessKeyAddress(accessKey), token],
});
}
getRemainingLimit.callWithPeriod = callWithPeriod;
})(getRemainingLimit || (exports.getRemainingLimit = getRemainingLimit = {}));
async function isAdmin(client, parameters) {
const { account: account_ = client.account, accessKey, ...rest } = parameters;
if (!account_)
throw new Error('account is required.');
const account = (0, parseAccount_js_1.parseAccount)(account_);
return (0, readContract_js_1.readContract)(client, {
...rest,
account: null,
...isAdmin.call({ account: account.address, accessKey }),
});
}
(function (isAdmin) {
function call(args) {
const { account, accessKey } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'isAdminKey',
args: [account, resolveAccessKeyAddress(accessKey)],
});
}
isAdmin.call = call;
})(isAdmin || (exports.isAdmin = isAdmin = {}));
async function isWitnessBurned(client, parameters) {
const { account: account_ = client.account, witness, ...rest } = parameters;
if (!account_)
throw new Error('account is required.');
const account = (0, parseAccount_js_1.parseAccount)(account_);
return (0, readContract_js_1.readContract)(client, {
...rest,
account: null,
...isWitnessBurned.call({ account: account.address, witness }),
});
}
(function (isWitnessBurned) {
function call(args) {
const { account, witness } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'isKeyAuthorizationWitnessBurned',
args: [account, witness],
});
}
isWitnessBurned.call = call;
})(isWitnessBurned || (exports.isWitnessBurned = isWitnessBurned = {}));
async function revoke(client, parameters) {
return revoke.inner(writeContract_js_1.writeContract, client, parameters);
}
(function (revoke) {
async function inner(action, client, parameters) {
const { accessKey, ...rest } = parameters;
const call = revoke.call({ accessKey });
return (await action(client, {
...rest,
...call,
}));
}
revoke.inner = inner;
function call(args) {
const { accessKey } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'revokeKey',
args: [resolveAccessKeyAddress(accessKey)],
});
}
revoke.call = call;
function extractEvent(logs) {
const [log] = (0, parseEventLogs_js_1.parseEventLogs)({
abi: Abis.accountKeychain,
logs,
eventName: 'KeyRevoked',
strict: true,
});
if (!log)
throw new Error('`KeyRevoked` event not found.');
return log;
}
revoke.extractEvent = extractEvent;
})(revoke || (exports.revoke = revoke = {}));
async function revokeSync(client, parameters) {
const { throwOnReceiptRevert = true, ...rest } = parameters;
const receipt = await revoke.inner(writeContractSync_js_1.writeContractSync, client, {
...rest,
throwOnReceiptRevert,
});
if (receipt.status === 'pending')
return { receipt };
const { args } = revoke.extractEvent(receipt.logs);
return {
...args,
receipt,
};
}
async function prepareAuthorization(client, parameters) {
const { chainId = client.chain?.id } = parameters;
const account_ = parameters.account ?? client.account;
if (!account_)
throw new Error('account is required.');
if (!chainId)
throw new Error('chainId is required.');
const parsed = (0, parseAccount_js_1.parseAccount)(account_);
const multisigState = await (async () => {
if ('multisig' in parameters)
return parameters.multisig;
if (parsed.source !== 'multisig')
return undefined;
const account = parsed;
if (!account.config)
throw new Error('A multisig config is required to prepare a key authorization.');
return { config: account.config };
})();
const authorizationSignPayload = (0, Account_js_1.getKeyAuthorizationSignPayload)(parsed, {
...parameters,
chainId: BigInt(chainId),
key: parameters.accessKey,
});
const signPayload = parsed.source === 'multisig' && multisigState
? tempo_1.MultisigConfig.getSignPayload({
account: parsed.address,
config: multisigState.config,
payload: authorizationSignPayload,
})
: authorizationSignPayload;
return {
...parameters,
account: parsed,
chainId,
multisig: multisigState,
signPayload,
};
}
async function signAuthorization(client, parameters) {
const coordinated = ('hash' in parameters && parameters.hash) ||
('owner' in parameters && parameters.owner);
if (coordinated) {
const parameters_ = parameters;
const owner_ = parameters_.owner;
if (!owner_ || typeof owner_ === 'string')
throw new Error('A local owner account is required to approve a multisig key authorization.');
const owner = (0, parseAccount_js_1.parseAccount)(owner_);
const sign = owner.sign;
if (!sign)
throw new Error('A local owner account is required to approve a multisig key authorization.');
const request = await (async () => {
if ('hash' in parameters_ && parameters_.hash) {
const signature = tempo_1.SignatureEnvelope.serialize(tempo_1.SignatureEnvelope.from(await sign({ hash: parameters_.hash })));
return { hash: parameters_.hash, signature };
}
const { account: account_, owner: _, ...authorization } = parameters_;
const address = typeof account_ === 'string' ? account_ : account_.address;
const config = await (async () => {
if (typeof account_ !== 'string' && account_.config)
return account_.config;
const config = await (0, multisig_js_1.getConfig)(client, { address });
if (config)
return config;
throw new Error(`No current multisig config is cached for account ${address}. Provide the current config.`);
})();
const account = (() => {
if (config.version !== 0n)
return (0, Account_js_1.fromMultisig)({ address, ...config });
const { version: _, ...initialConfig } = config;
return (0, Account_js_1.fromMultisig)({ address: 'infer', ...initialConfig });
})();
if (!(0, isAddressEqual_js_1.isAddressEqual)(account.address, address))
throw new Error('Initial multisig config does not match the account.');
const prepared = await prepareAuthorization(client, {
...authorization,
account,
});
const signature = tempo_1.SignatureEnvelope.serialize(tempo_1.SignatureEnvelope.from(await sign({ hash: prepared.signPayload })));
const { accessKey, admin, chainId, expiry, limits, scopes, witness } = prepared;
const { accessKeyAddress, keyType: type } = (0, Account_js_1.resolveAccessKey)(accessKey);
const keyAuthorization = tempo_1.KeyAuthorization.from({
account: account.address,
address: accessKeyAddress,
chainId: BigInt(chainId),
signature: tempo_1.SignatureEnvelope.from({
account: account.address,
config,
signatures: [(0, Signature_js_1.parseApproval)(signature)],
}),
type,
...(witness ? { witness } : {}),
...(admin ? { isAdmin: true } : { expiry, limits, scopes }),
});
return { keyAuthorization: tempo_1.KeyAuthorization.toRpc(keyAuthorization) };
})();
const operation = await client.request({
method: 'multisig_approveKeyAuthorization',
params: [request],
});
const multisig = tempo_1.MultisigOperation.fromRpc(operation);
const keyAuthorization = tempo_1.KeyAuthorization.deserialize(await (async () => {
if (multisig.status === 'success')
return multisig.keyAuthorization;
const approvals = await tempo_1.MultisigOperation.selectApprovals({
account: multisig.account,
approvals: multisig.approvals,
config: multisig.config,
hash: multisig.hash,
});
return tempo_1.MultisigOperation.serializeKeyAuthorization(multisig.keyAuthorization, {
account: multisig.account,
approvals: approvals.selectedApprovals.length > 0
? approvals.selectedApprovals
: approvals.approvals.slice(0, 1),
config: multisig.config,
});
})());
if (!keyAuthorization.signature)
throw new Error('Expected a signed multisig key authorization.');
return {
...keyAuthorization,
hash: multisig.hash,
multisig,
status: multisig.status,
};
}
const prepared = ('signPayload' in parameters
? parameters
: await prepareAuthorization(client, parameters));
const { accessKey, account: account_, chainId, multisig: multisigState, signPayload: _, ...rest } = prepared;
return (0, Account_js_1.signKeyAuthorization)(account_, {
chainId: BigInt(chainId),
key: accessKey,
multisig: multisigState,
...rest,
});
}
async function updateLimit(client, parameters) {
return updateLimit.inner(writeContract_js_1.writeContract, client, parameters);
}
(function (updateLimit) {
async function inner(action, client, parameters) {
const { accessKey, token, limit, ...rest } = parameters;
const call = updateLimit.call({ accessKey, token, limit });
return (await action(client, {
...rest,
...call,
}));
}
updateLimit.inner = inner;
function call(args) {
const { accessKey, token, limit } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
functionName: 'updateSpendingLimit',
args: [resolveAccessKeyAddress(accessKey), token, limit],
});
}
updateLimit.call = call;
function extractEvent(logs) {
const [log] = (0, parseEventLogs_js_1.parseEventLogs)({
abi: Abis.accountKeychain,
logs,
eventName: 'SpendingLimitUpdated',
strict: true,
});
if (!log)
throw new Error('`SpendingLimitUpdated` event not found.');
return log;
}
updateLimit.extractEvent = extractEvent;
})(updateLimit || (exports.updateLimit = updateLimit = {}));
async function updateLimitSync(client, parameters) {
const { throwOnReceiptRevert = true, ...rest } = parameters;
const receipt = await updateLimit.inner(writeContractSync_js_1.writeContractSync, client, {
...rest,
throwOnReceiptRevert,
});
if (receipt.status === 'pending')
return { receipt };
const { args } = updateLimit.extractEvent(receipt.logs);
return {
account: args.account,
publicKey: args.publicKey,
token: args.token,
limit: args.newLimit,
receipt,
};
}
function watchAdminAuthorized(client, parameters) {
const { onAuthorized, ...rest } = parameters;
return (0, watchContractEvent_js_1.watchContractEvent)(client, {
...rest,
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
eventName: 'AdminKeyAuthorized',
onLogs: (logs) => {
for (const log of logs)
onAuthorized(log.args, log);
},
strict: true,
});
}
function watchWitness(client, parameters) {
const { onWitness, ...rest } = parameters;
return (0, watchContractEvent_js_1.watchContractEvent)(client, {
...rest,
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
eventName: 'KeyAuthorizationWitness',
onLogs: (logs) => {
for (const log of logs)
onWitness(log.args, log);
},
strict: true,
});
}
function watchWitnessBurned(client, parameters) {
const { onBurned, ...rest } = parameters;
return (0, watchContractEvent_js_1.watchContractEvent)(client, {
...rest,
address: Addresses.accountKeychain,
abi: Abis.accountKeychain,
eventName: 'KeyAuthorizationWitnessBurned',
onLogs: (logs) => {
for (const log of logs)
onBurned(log.args, log);
},
strict: true,
});
}
async function verifyHash(client, parameters) {
const { account, admin, hash, signature, ...rest } = parameters;
return (0, readContract_js_1.readContract)(client, {
...rest,
...verifyHash.call({ account, admin, hash, signature }),
});
}
(function (verifyHash) {
function call(args) {
const { account, admin = true, hash, signature } = args;
return (0, utils_js_1.defineCall)({
address: Addresses.signatureVerifier,
abi: Abis.signatureVerifier,
functionName: admin ? 'verifyKeychainAdmin' : 'verifyKeychain',
args: [account, hash, signature],
});
}
verifyHash.call = call;
})(verifyHash || (exports.verifyHash = verifyHash = {}));
function resolveAccessKeyAddress(accessKey) {
if (typeof accessKey === 'string')
return accessKey;
return accessKey.accessKeyAddress;
}
//# sourceMappingURL=accessKey.js.map