@lit-protocol/access-control-conditions
Version:
A comprehensive toolkit for managing access control conditions within the Lit Protocol ecosystem. This package provides functionalities for formatting, validating, and securing access control rules.
484 lines • 19.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.humanizeAccessControlConditions = exports.humanizeUnifiedAccessControlConditions = exports.humanizeCosmosConditions = exports.humanizeSolRpcConditions = exports.humanizeEvmContractConditions = exports.humanizeEvmBasicAccessControlConditions = exports.humanizeComparator = exports.formatAtom = exports.formatSol = void 0;
const utils_1 = require("ethers/lib/utils");
const constants_1 = require("@lit-protocol/constants");
const misc_1 = require("@lit-protocol/misc");
/**
*
* Format SOL number using Ether Units
*
* @param { number } amount
*
* @returns { string } formatted unit
*
*/
const formatSol = (amount) => {
return (0, utils_1.formatUnits)(amount, 9);
};
exports.formatSol = formatSol;
/**
*
* Format Atom number using Ether Units
*
* @param { number } amount
*
* @returns { string } formatted unit
*
*/
const formatAtom = (amount) => {
return (0, utils_1.formatUnits)(amount, 6);
};
exports.formatAtom = formatAtom;
/**
*
* Comparator translator
*
* @param { string } comparator
*
* @returns { string } humanized version of the comparator
*/
const humanizeComparator = (comparator) => {
const list = {
'>': 'more than',
'>=': 'at least',
'=': 'exactly',
'<': 'less than',
'<=': 'at most',
contains: 'contains',
};
const selected = list[comparator];
if (!selected) {
(0, misc_1.log)(`Unregonized comparator ${comparator}`);
return;
}
return selected;
};
exports.humanizeComparator = humanizeComparator;
/**
*
* Humanize EVM basic access control conditions
*
* @property { Array<AccsDefaultParams | any> } accessControlConditions
* @property { Array<any | string> } tokenList
* @property { string } myWalletAddress
*
* @returns
*/
const humanizeEvmBasicAccessControlConditions = async ({ accessControlConditions, tokenList, myWalletAddress, }) => {
(0, misc_1.log)('humanizing evm basic access control conditions');
(0, misc_1.log)('myWalletAddress', myWalletAddress);
(0, misc_1.log)('accessControlConditions', accessControlConditions);
let fixedConditions = accessControlConditions;
// inject and operator if needed
// this is done because before we supported operators,
// we let users specify an entire array of conditions
// that would be "AND"ed together. this injects those ANDs
if (accessControlConditions.length > 1) {
let containsOperator = false;
for (let i = 0; i < accessControlConditions.length; i++) {
if ('operator' in accessControlConditions[i]) {
containsOperator = true;
}
}
if (!containsOperator) {
fixedConditions = [];
// insert ANDs between conditions
for (let i = 0; i < accessControlConditions.length; i++) {
fixedConditions.push(accessControlConditions[i]);
if (i < accessControlConditions.length - 1) {
fixedConditions.push({
operator: 'and',
});
}
}
}
}
// -- execute
const promises = await Promise.all(fixedConditions.map(async (acc) => {
if (Array.isArray(acc)) {
// this is a group. recurse.
const group = await (0, exports.humanizeEvmBasicAccessControlConditions)({
accessControlConditions: acc,
tokenList,
myWalletAddress,
});
return `( ${group} )`;
}
if (acc.operator) {
if (acc.operator.toLowerCase() === 'and') {
return ' and ';
}
else if (acc.operator.toLowerCase() === 'or') {
return ' or ';
}
}
if (acc.standardContractType === 'timestamp' &&
acc.method === 'eth_getBlockByNumber') {
return `Latest mined block must be past the unix timestamp ${acc.returnValueTest.value}`;
}
else if (acc.standardContractType === 'MolochDAOv2.1' &&
acc.method === 'members') {
// molochDAOv2.1 membership
return `Is a member of the DAO at ${acc.contractAddress}`;
}
else if (acc.standardContractType === 'ERC1155' &&
acc.method === 'balanceOf') {
// erc1155 owns an amount of specific tokens
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${acc.returnValueTest.value} of ${acc.contractAddress} tokens with token id ${acc.parameters[1]}`;
}
else if (acc.standardContractType === 'ERC1155' &&
acc.method === 'balanceOfBatch') {
// erc1155 owns an amount of specific tokens from a batch of token ids
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${acc.returnValueTest.value} of ${acc.contractAddress} tokens with token id ${acc.parameters[1]
.split(',')
.join(' or ')}`;
}
else if (acc.standardContractType === 'ERC721' &&
acc.method === 'ownerOf') {
// specific erc721
return `Owner of tokenId ${acc.parameters[0]} from ${acc.contractAddress}`;
}
else if (acc.standardContractType === 'ERC721' &&
acc.method === 'balanceOf' &&
acc.contractAddress === '0x22C1f6050E56d2876009903609a2cC3fEf83B415' &&
acc.returnValueTest.comparator === '>' &&
acc.returnValueTest.value === '0') {
// for POAP main contract where the user owns at least 1 poap
return `Owns any POAP`;
}
else if (acc.standardContractType === 'POAP' &&
acc.method === 'tokenURI') {
// owns a POAP
return `Owner of a ${acc.returnValueTest.value} POAP on ${acc.chain}`;
}
else if (acc.standardContractType === 'POAP' &&
acc.method === 'eventId') {
// owns a POAP
return `Owner of a POAP from event ID ${acc.returnValueTest.value} on ${acc.chain}`;
}
else if (acc.standardContractType === 'CASK' &&
acc.method === 'getActiveSubscriptionCount') {
// Cask powered subscription
return `Cask subscriber to provider ${acc.parameters[1]} for plan ${acc.parameters[2]} on ${acc.chain}`;
}
else if (acc.standardContractType === 'ERC721' &&
acc.method === 'balanceOf') {
// any erc721 in collection
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${acc.returnValueTest.value} of ${acc.contractAddress} tokens`;
}
else if (acc.standardContractType === 'ERC20' &&
acc.method === 'balanceOf') {
let tokenFromList;
if (tokenList) {
tokenFromList = tokenList.find((t) => t.address === acc.contractAddress);
}
let decimals, name;
if (tokenFromList) {
decimals = tokenFromList.decimals;
name = tokenFromList.symbol;
}
else {
try {
decimals = await (0, misc_1.decimalPlaces)({
contractAddress: acc.contractAddress,
chain: acc.chain,
});
}
catch (e) {
console.log(`Failed to get decimals for ${acc.contractAddress}`);
}
}
(0, misc_1.log)('decimals', decimals);
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${(0, utils_1.formatUnits)(acc.returnValueTest.value, decimals)} of ${name || acc.contractAddress} tokens`;
}
else if (acc.standardContractType === '' &&
acc.method === 'eth_getBalance') {
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${(0, utils_1.formatEther)(acc.returnValueTest.value)} ETH`;
}
else if (acc.standardContractType === '' && acc.method === '') {
if (myWalletAddress &&
acc.returnValueTest.value.toLowerCase() ===
myWalletAddress.toLowerCase()) {
return `Controls your wallet (${myWalletAddress})`;
}
else {
return `Controls wallet with address ${acc.returnValueTest.value}`;
}
}
return 'Oops. something went wrong!';
}));
return promises.join('');
};
exports.humanizeEvmBasicAccessControlConditions = humanizeEvmBasicAccessControlConditions;
/**
*
* Humanize EVM contract conditions
*
* @property { Array<AccsEVMParams> } evmContractConditions
* @property { Array<any | string> } tokenList
* @property { string } myWalletAddress
*
* @returns { Promise<string> } A promise containing a human readable description of the access control conditions
*
*/
const humanizeEvmContractConditions = async ({ evmContractConditions, tokenList, myWalletAddress, }) => {
(0, misc_1.log)('humanizing evm contract conditions');
(0, misc_1.log)('myWalletAddress', myWalletAddress);
(0, misc_1.log)('evmContractConditions', evmContractConditions);
const promises = await Promise.all(evmContractConditions.map(async (acc) => {
if (Array.isArray(acc)) {
// this is a group. recurse.
const group = await (0, exports.humanizeEvmContractConditions)({
evmContractConditions: acc,
tokenList,
myWalletAddress,
});
return `( ${group} )`;
}
if (acc.operator) {
if (acc.operator.toLowerCase() === 'and') {
return ' and ';
}
else if (acc.operator.toLowerCase() === 'or') {
return ' or ';
}
}
let msg = `${acc.functionName}(${acc.functionParams.join(', ')}) on contract address ${acc.contractAddress} should have a result of ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${acc.returnValueTest.value}`;
if (acc.returnValueTest.key !== '') {
msg += ` for key ${acc.returnValueTest.key}`;
}
return msg;
}));
return promises.join('');
};
exports.humanizeEvmContractConditions = humanizeEvmContractConditions;
/**
*
* Humanize SOL RPC Conditions
*
* @property { Array<AccsSOLV2Params> } solRpcConditions
* @property { Array<any | string> } tokenList
* @property { string } myWalletAddress
*
* @returns { Promise<string> } A promise containing a human readable description of the access control conditions
*
*/
const humanizeSolRpcConditions = async ({ solRpcConditions, tokenList, myWalletAddress, }) => {
(0, misc_1.log)('humanizing sol rpc conditions');
(0, misc_1.log)('myWalletAddress', myWalletAddress);
(0, misc_1.log)('solRpcConditions', solRpcConditions);
const promises = await Promise.all(solRpcConditions.map(async (acc) => {
if (Array.isArray(acc)) {
// this is a group. recurse.
const group = await (0, exports.humanizeSolRpcConditions)({
solRpcConditions: acc,
tokenList,
myWalletAddress,
});
return `( ${group} )`;
}
if (acc.operator) {
if (acc.operator.toLowerCase() === 'and') {
return ' and ';
}
else if (acc.operator.toLowerCase() === 'or') {
return ' or ';
}
}
if (acc.method === 'getBalance') {
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${(0, exports.formatSol)(acc.returnValueTest.value)} SOL`;
}
else if (acc.method === '') {
if (myWalletAddress &&
acc.returnValueTest.value.toLowerCase() ===
myWalletAddress.toLowerCase()) {
return `Controls your wallet (${myWalletAddress})`;
}
else {
return `Controls wallet with address ${acc.returnValueTest.value}`;
}
}
else {
let msg = `Solana RPC method ${acc.method}(${acc.params.join(', ')}) should have a result of ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${acc.returnValueTest.value}`;
if (acc.returnValueTest.key !== '') {
msg += ` for key ${acc.returnValueTest.key}`;
}
return msg;
}
}));
return promises.join('');
};
exports.humanizeSolRpcConditions = humanizeSolRpcConditions;
/**
*
* Humanize Cosmos Conditions
*
* @property { Array<AccsCOSMOSParams> } cosmosConditions
* @property { Array<any | string> } tokenList
* @property { string } myWalletAddress
*
* @returns { Promise<string> } A promise containing a human readable description of the access control conditions
*
*/
const humanizeCosmosConditions = async ({ cosmosConditions, tokenList, myWalletAddress, }) => {
(0, misc_1.log)('humanizing cosmos conditions');
(0, misc_1.log)('myWalletAddress', myWalletAddress);
(0, misc_1.log)('cosmosConditions', cosmosConditions);
const promises = await Promise.all(cosmosConditions.map(async (acc) => {
if (Array.isArray(acc)) {
// this is a group. recurse.
const group = await (0, exports.humanizeCosmosConditions)({
cosmosConditions: acc,
tokenList,
myWalletAddress,
});
return `( ${group} )`;
}
if (acc.operator) {
if (acc.operator.toLowerCase() === 'and') {
return ' and ';
}
else if (acc.operator.toLowerCase() === 'or') {
return ' or ';
}
}
if (acc.path === '/cosmos/bank/v1beta1/balances/:userAddress') {
return `Owns ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${(0, exports.formatAtom)(acc.returnValueTest.value)} ATOM`;
}
else if (acc.path === ':userAddress') {
if (myWalletAddress &&
acc.returnValueTest.value.toLowerCase() ===
myWalletAddress.toLowerCase()) {
return `Controls your wallet (${myWalletAddress})`;
}
else {
return `Controls wallet with address ${acc.returnValueTest.value}`;
}
}
else if (acc.chain === 'kyve' &&
acc.path === '/kyve/registry/v1beta1/funders_list/0') {
return `Is a current KYVE funder`;
}
else {
let msg = `Cosmos RPC request for ${acc.path} should have a result of ${(0, exports.humanizeComparator)(acc.returnValueTest.comparator)} ${acc.returnValueTest.value}`;
if (acc.returnValueTest.key !== '') {
msg += ` for key ${acc.returnValueTest.key}`;
}
return msg;
}
}));
return promises.join('');
};
exports.humanizeCosmosConditions = humanizeCosmosConditions;
/**
*
* Humanize unified access control conditions
*
* @property { Array<UnifiedAccessControlConditions> } unifiedAccessControlConditions
* @property { Array<any | string> } tokenList
* @property { string } myWalletAddress
*
* @returns { Promise<string> } A promise containing a human readable description of the access control conditions
*/
const humanizeUnifiedAccessControlConditions = async ({ unifiedAccessControlConditions, tokenList, myWalletAddress, }) => {
const promises = await Promise.all(unifiedAccessControlConditions.map(async (acc) => {
if (Array.isArray(acc)) {
// this is a group. recurse.
const group = await (0, exports.humanizeUnifiedAccessControlConditions)({
unifiedAccessControlConditions: acc,
tokenList,
myWalletAddress,
});
return `( ${group} )`;
}
if (acc.operator) {
if (acc.operator.toLowerCase() === 'and') {
return ' and ';
}
else if (acc.operator.toLowerCase() === 'or') {
return ' or ';
}
}
if (acc.conditionType === 'evmBasic') {
return (0, exports.humanizeEvmBasicAccessControlConditions)({
accessControlConditions: [acc],
tokenList,
myWalletAddress,
});
}
else if (acc.conditionType === 'evmContract') {
return (0, exports.humanizeEvmContractConditions)({
evmContractConditions: [acc],
tokenList,
myWalletAddress,
});
}
else if (acc.conditionType === 'solRpc') {
return (0, exports.humanizeSolRpcConditions)({
solRpcConditions: [acc],
tokenList,
myWalletAddress,
});
}
else if (acc.conditionType === 'cosmos') {
return (0, exports.humanizeCosmosConditions)({
cosmosConditions: [acc],
tokenList,
myWalletAddress,
});
}
else {
throw new constants_1.InvalidUnifiedConditionType({
info: {
acc,
},
}, 'Unrecognized condition type: %s', acc.conditionType);
}
}));
return promises.join('');
};
exports.humanizeUnifiedAccessControlConditions = humanizeUnifiedAccessControlConditions;
/**
*
* The human readable name for an access control condition
*
* @param { HumanizedAccsProps } params
*
* @returns { Promise<string> } A promise containing a human readable description of the access control conditions
*/
const humanizeAccessControlConditions = async ({ accessControlConditions, evmContractConditions, solRpcConditions, unifiedAccessControlConditions, tokenList, myWalletAddress, }) => {
// -- check if each condition exists in linear
if (accessControlConditions) {
return (0, exports.humanizeEvmBasicAccessControlConditions)({
accessControlConditions,
tokenList,
myWalletAddress,
});
}
else if (evmContractConditions) {
return (0, exports.humanizeEvmContractConditions)({
evmContractConditions,
tokenList,
myWalletAddress,
});
}
else if (solRpcConditions) {
return (0, exports.humanizeSolRpcConditions)({
solRpcConditions,
tokenList,
myWalletAddress,
});
}
else if (unifiedAccessControlConditions) {
return (0, exports.humanizeUnifiedAccessControlConditions)({
unifiedAccessControlConditions,
tokenList,
myWalletAddress,
});
}
// -- undefined
return;
};
exports.humanizeAccessControlConditions = humanizeAccessControlConditions;
//# sourceMappingURL=humanizer.js.map
;