@abstract-foundation/agw-client
Version:
Abstract Global Wallet Client SDK
151 lines • 6.79 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SessionKeyPolicyStatus = void 0;
exports.assertSessionKeyPolicies = assertSessionKeyPolicies;
const viem_1 = require("viem");
const chains_1 = require("viem/chains");
const utils_1 = require("viem/utils");
const SessionKeyPolicyRegistry_js_1 = require("./abis/SessionKeyPolicyRegistry.js");
const SessionKeyValidator_js_1 = require("./abis/SessionKeyValidator.js");
const constants_js_1 = require("./constants.js");
const constants_js_2 = require("./exports/constants.js");
const sessions_js_1 = require("./sessions.js");
const restrictedSelectors = new Set([
(0, viem_1.toFunctionSelector)('function setApprovalForAll(address, bool)'),
(0, viem_1.toFunctionSelector)('function approve(address, uint256)'),
(0, viem_1.toFunctionSelector)('function transfer(address, uint256)'),
]);
var SessionKeyPolicyStatus;
(function (SessionKeyPolicyStatus) {
SessionKeyPolicyStatus[SessionKeyPolicyStatus["Unset"] = 0] = "Unset";
SessionKeyPolicyStatus[SessionKeyPolicyStatus["Allowed"] = 1] = "Allowed";
SessionKeyPolicyStatus[SessionKeyPolicyStatus["Denied"] = 2] = "Denied";
})(SessionKeyPolicyStatus || (exports.SessionKeyPolicyStatus = SessionKeyPolicyStatus = {}));
async function assertSessionKeyPolicies(client, chainId, account, transaction) {
if (chainId !== chains_1.abstract.id) {
return;
}
const sessions = [];
if (transaction.to === account.address &&
transaction.data?.substring(0, 10) === constants_js_1.BATCH_CALL_SELECTOR) {
const batchCall = (0, utils_1.decodeFunctionData)({
abi: constants_js_2.AGWAccountAbi,
data: transaction.data,
});
if (batchCall.functionName === 'batchCall') {
for (const call of batchCall.args[0]) {
const subTransaction = {
...transaction,
to: call.target,
data: call.callData,
};
const session = getSessionFromTransaction(account, subTransaction);
if (session) {
sessions.push(session);
}
}
}
}
else {
const session = getSessionFromTransaction(account, transaction);
if (session) {
sessions.push(session);
}
}
if (sessions.length === 0) {
return;
}
for (const session of sessions) {
const callPolicies = session.callPolicies;
const transferPolicies = session.transferPolicies;
const checks = [];
for (const callPolicy of callPolicies) {
if (restrictedSelectors.has(callPolicy.selector)) {
const destinationConstraints = callPolicy.constraints.filter((c) => c.index === 0n && c.condition === sessions_js_1.ConstraintCondition.Equal);
if (destinationConstraints.length === 0) {
throw new viem_1.BaseError(`Unconstrained token approval/transfer destination in call policy. Selector: ${callPolicy.selector}; Target: ${callPolicy.target}`);
}
for (const constraint of destinationConstraints) {
const [target] = (0, utils_1.decodeAbiParameters)([
{
type: 'address',
},
], constraint.refValue);
checks.push({
target,
check: {
address: constants_js_1.SESSION_KEY_POLICY_REGISTRY_ADDRESS,
abi: SessionKeyPolicyRegistry_js_1.SessionKeyPolicyRegistryAbi,
functionName: 'getApprovalTargetStatus',
args: [
callPolicy.target,
target,
],
},
});
}
}
else {
checks.push({
target: callPolicy.target,
check: {
address: constants_js_1.SESSION_KEY_POLICY_REGISTRY_ADDRESS,
abi: SessionKeyPolicyRegistry_js_1.SessionKeyPolicyRegistryAbi,
functionName: 'getCallPolicyStatus',
args: [callPolicy.target, callPolicy.selector],
},
});
}
}
for (const transferPolicy of transferPolicies) {
checks.push({
target: transferPolicy.target,
check: {
address: constants_js_1.SESSION_KEY_POLICY_REGISTRY_ADDRESS,
abi: SessionKeyPolicyRegistry_js_1.SessionKeyPolicyRegistryAbi,
functionName: 'getTransferPolicyStatus',
args: [transferPolicy.target],
},
});
}
const results = await client.multicall({
contracts: checks.map((c) => c.check),
allowFailure: false,
});
for (let i = 0; i < checks.length; i++) {
const result = results[i];
const check = checks[i];
if (Number(result) !== SessionKeyPolicyStatus.Allowed) {
throw new viem_1.BaseError(`Session key policy violation. Target: ${check?.target}; Status: ${SessionKeyPolicyStatus[Number(result)]}`);
}
}
}
}
function getSessionFromTransaction(account, transaction) {
if (transaction.to === constants_js_1.SESSION_KEY_VALIDATOR_ADDRESS &&
transaction.data?.substring(0, 10) === constants_js_1.CREATE_SESSION_SELECTOR) {
const sessionSpec = (0, utils_1.decodeFunctionData)({
abi: SessionKeyValidator_js_1.SessionKeyValidatorAbi,
data: transaction.data,
});
if (sessionSpec.functionName === 'createSession') {
return sessionSpec.args[0];
}
}
if (transaction.to === account?.address &&
transaction.data?.substring(0, 10) === constants_js_1.ADD_MODULE_SELECTOR) {
const moduleAndData = (0, utils_1.decodeFunctionData)({
abi: constants_js_2.AGWAccountAbi,
data: transaction.data,
});
if (moduleAndData.functionName === 'addModule' &&
moduleAndData.args[0]
.toLowerCase()
.startsWith(constants_js_1.SESSION_KEY_VALIDATOR_ADDRESS.toLowerCase())) {
const sessionData = moduleAndData.args[0].substring(42);
return (0, utils_1.decodeAbiParameters)([(0, sessions_js_1.getSessionSpec)()], `0x${sessionData}`)[0];
}
}
return undefined;
}
//# sourceMappingURL=sessionValidator.js.map