const { sha3 } = require("./contract-util.js"); const { extensionsIdsMap } = require("./dao-ids-util"); export type ACLValue = { id: string; addr: string; flags: number; }; export type SelectedACLs = { dao: Array; extensions: Record>; }; export type ACLBuilder = ( contractAddress: string, acls: SelectedACLs ) => ACLValue; export const daoAccessFlagsMap: Record = { REPLACE_ADAPTER: "REPLACE_ADAPTER", SUBMIT_PROPOSAL: "SUBMIT_PROPOSAL", UPDATE_DELEGATE_KEY: "UPDATE_DELEGATE_KEY", SET_CONFIGURATION: "SET_CONFIGURATION", ADD_EXTENSION: "ADD_EXTENSION", REMOVE_EXTENSION: "REMOVE_EXTENSION", NEW_MEMBER: "NEW_MEMBER", JAIL_MEMBER: "JAIL_MEMBER" }; export const daoAccessFlags: Array = Object.values(daoAccessFlagsMap); export const bankExtensionAclFlagsMap: Record = { ADD_TO_BALANCE: "ADD_TO_BALANCE", SUB_FROM_BALANCE: "SUB_FROM_BALANCE", INTERNAL_TRANSFER: "INTERNAL_TRANSFER", WITHDRAW: "WITHDRAW", REGISTER_NEW_TOKEN: "REGISTER_NEW_TOKEN", REGISTER_NEW_INTERNAL_TOKEN: "REGISTER_NEW_INTERNAL_TOKEN", UPDATE_TOKEN: "UPDATE_TOKEN", }; export const bankExtensionAclFlags: Array = Object.values( bankExtensionAclFlagsMap ); export const erc20ExtensionAclFlagsMap: Record = {}; export const erc20ExtensionAclFlags: Array = Object.values( erc20ExtensionAclFlagsMap ); export const erc721ExtensionAclFlagsMap: Record = { WITHDRAW_NFT: "WITHDRAW_NFT", COLLECT_NFT: "COLLECT_NFT", INTERNAL_TRANSFER: "INTERNAL_TRANSFER", }; export const erc721ExtensionAclFlags: Array = Object.values( erc721ExtensionAclFlagsMap ); export const erc1155ExtensionAclFlagsMap: Record = { WITHDRAW_NFT: "WITHDRAW_NFT", COLLECT_NFT: "COLLECT_NFT", INTERNAL_TRANSFER: "INTERNAL_TRANSFER", }; export const erc1155ExtensionAclFlags: Array = Object.values( erc1155ExtensionAclFlagsMap ); export const erc1271ExtensionAclFlagsMap: Record = { SIGN: "SIGN", }; export const erc1271ExtensionAclFlags: Array = Object.values( erc1271ExtensionAclFlagsMap ); export const executorExtensionAclFlagsMap: Record = { EXECUTE: "EXECUTE", }; export const executorExtensionAclFlags: Array = Object.values( executorExtensionAclFlagsMap ); export const vestingExtensionAclFlagsMap: Record = { NEW_VESTING: "NEW_VESTING", REMOVE_VESTING: "REMOVE_VESTING", }; export const vestingExtensionAclFlags: Array = Object.values( vestingExtensionAclFlagsMap ); export const parseSelectedFlags = ( allAclFlags: Array, selectedFlags: Array, moduleName: string ): Record => { return selectedFlags .map((f) => f.toUpperCase()) .reduce((flags, flag) => { if (allAclFlags.includes(flag)) { return { ...flags, [flag]: true }; } throw Error(`Invalid ${moduleName} Access Flag: ${flag}`); }, {}); }; export const entryERC721 = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( erc721ExtensionAclFlags, extensionsIdsMap.ERC721_EXT, contractAddress, selectedAcls ); }; export const entryERC1155 = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( erc1155ExtensionAclFlags, extensionsIdsMap.ERC1155_EXT, contractAddress, selectedAcls ); }; export const entryERC20 = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( erc20ExtensionAclFlags, extensionsIdsMap.ERC20_EXT, contractAddress, selectedAcls ); }; export const entryBank = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( bankExtensionAclFlags, extensionsIdsMap.BANK_EXT, contractAddress, selectedAcls ); }; export const entryERC1271 = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( erc1271ExtensionAclFlags, extensionsIdsMap.ERC1271_EXT, contractAddress, selectedAcls ); }; export const entryExecutor = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( executorExtensionAclFlags, extensionsIdsMap.EXECUTOR_EXT, contractAddress, selectedAcls ); }; export const entryVesting = ( contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { return getEnabledExtensionFlags( vestingExtensionAclFlags, extensionsIdsMap.VESTING_EXT, contractAddress, selectedAcls ); }; export const entryDao = ( contractId: string, contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { const flags = daoAccessFlags.flatMap((flag) => { return selectedAcls.dao.some((f) => f === flag); }); return { id: sha3(contractId) as string, addr: contractAddress, flags: calculateFlagValue(flags), }; }; export const getEnabledExtensionFlags = ( acls: Array, extensionId: string, contractAddress: string, selectedAcls: SelectedACLs ): ACLValue => { const enabledFlags = acls.flatMap((flag: string) => { const extensionsAcls = selectedAcls.extensions; return ( extensionsAcls && Object.keys(extensionsAcls).length > 0 && extensionsAcls[extensionId].some((f) => f === flag) ); }); return { id: sha3(extensionId) as string, addr: contractAddress, flags: calculateFlagValue(enabledFlags), }; }; /** * Each position in the array represents a flag, if its true it means the flag is enabled, hence * the access should be granted. * To grant the access it calculates the integer value that represents that tag in the 2**68 space. * @param values An array of boolean which indicate the flags that are enabled. * @returns a value */ export const calculateFlagValue = (values: Array): number => { return values .map((v, idx) => (v === true ? 2 ** idx : 0)) .reduce((a, b) => a + b); };