diff --git a/modules/baalStakingEligibility.json b/modules/baalStakingEligibility.json index 340392f..fa9a5f0 100644 --- a/modules/baalStakingEligibility.json +++ b/modules/baalStakingEligibility.json @@ -103,6 +103,34 @@ } ], "writeFunctions": [ + { + "roles": ["public"], + "functionName": "claim", + "label": "Claim", + "description": "Claim the hat", + "args": [ + { + "name": "Claims Hatter", + "description": "A Multi Claims Hatter instance with which to perform claiming", + "type": "address", + "displayType": "default" + } + ] + }, + { + "roles": ["public"], + "functionName": "slash", + "label": "Slash", + "description": "Slashes a member's stake for a role, if they are in bad standing", + "args": [ + { + "name": "Member", + "description": "The member to slash", + "type": "address", + "displayType": "default" + } + ] + }, { "roles": ["public"], "functionName": "stakeAndClaim", diff --git a/modules/multiClaimsHatter.json b/modules/multiClaimsHatter.json index 5037a22..ae97376 100644 --- a/modules/multiClaimsHatter.json +++ b/modules/multiClaimsHatter.json @@ -82,7 +82,217 @@ ] }, "customRoles": [], - "writeFunctions": [], + "writeFunctions": [ + { + "roles": ["hatAdmins"], + "functionName": "setHatClaimability", + "label": "Set Claimability", + "description": "Change the claimability status of a hat", + "primary": true, + "args": [ + { + "name": "Hat", + "description": "The ID of the hat to set claimability for", + "type": "uint256", + "displayType": "hat" + }, + { + "name": "Claimability Type", + "description": "New claimability type for the hat (0 - not claimable, 1 - claimable by wearer, 2 - claimable by wearer and on behalf of)", + "type": "uint8", + "displayType": "default" + } + ] + }, + { + "roles": ["hatAdmins"], + "functionName": "setHatsClaimability", + "label": "Set Claimabilities", + "description": "Change the claimability status of multiple hats", + "args": [ + { + "name": "Hats", + "description": "The IDs of the hats to set claimability for", + "type": "uint256[]", + "displayType": "default" + }, + { + "name": "Claimability Types", + "description": "New claimability types for the hats (0 - not claimable, 1 - claimable by wearer, 2 - claimable by wearer and on behalf of)", + "type": "uint8[]", + "displayType": "default" + } + ] + }, + { + "roles": ["hatAdmins"], + "functionName": "setHatClaimabilityAndCreateModule", + "label": "Set Claimability and Create Module", + "description": "Wrapper around a HatsModuleFactory. Deploys a new HatsModule instance and sets a hat's claimability type", + "args": [ + { + "name": "Factory", + "description": "The HatsModuleFactory instance that will deploy the module", + "type": "address", + "displayType": "default" + }, + { + "name": "Implementation", + "description": "The address of the implementation contract of which to deploy a clone", + "type": "address", + "displayType": "default" + }, + { + "name": "Target Hat", + "description": "The hat for which to deploy a module", + "type": "uint256", + "displayType": "hat" + }, + { + "name": "Immutable Args", + "description": "the immutable args to pass to the clone as immutable storage", + "type": "bytes", + "displayType": "default" + }, + { + "name": "Init Data", + "description": "The encoded data to pass to the `setUp` function of the new HatsModule instance", + "type": "bytes", + "displayType": "default" + }, + { + "name": "Hat", + "description": "The ID of the hat to set claimability for", + "type": "uint256", + "displayType": "hat" + }, + { + "name": "Claimability Type", + "description": "New claimability type for the hat (0 - not claimable, 1 - claimable by wearer, 2 - claimable by wearer and on behalf of)", + "type": "uint8", + "displayType": "default" + } + ] + }, + { + "roles": ["hatAdmins"], + "functionName": "setHatsClaimabilityAndCreateModules", + "label": "Set Claimability and Create Module for Multiple Hats", + "description": "Wrapper around a HatsModuleFactory. Deploys new HatsModule instancse and sets the claimability type of multiple hats", + "args": [ + { + "name": "Factory", + "description": "The HatsModuleFactory instance that will deploy the module", + "type": "address", + "displayType": "default" + }, + { + "name": "Implementations", + "description": "The addresses of the implementation contracts of which to deploy a clone", + "type": "address[]", + "displayType": "default" + }, + { + "name": "Target Hats", + "description": "The hats for which to deploy a module", + "type": "uint256[]", + "displayType": "default" + }, + { + "name": "Immutable Args", + "description": "the immutable args to pass to the clones as immutable storage", + "type": "bytes[]", + "displayType": "default" + }, + { + "name": "Init Datas", + "description": "The encoded data to pass to the `setUp` functions of the new HatsModule instances", + "type": "bytes[]", + "displayType": "default" + }, + { + "name": "Hats", + "description": "The IDs of the hats to set claimability for", + "type": "uint256[]", + "displayType": "default" + }, + { + "name": "Claimability Types", + "description": "New claimability types for the hats (0 - not claimable, 1 - claimable by wearer, 2 - claimable by wearer and on behalf of)", + "type": "uint8[]", + "displayType": "default" + } + ] + }, + { + "roles": ["public"], + "functionName": "claimHat", + "label": "Claim Hat", + "description": "Claim a hat", + "args": [ + { + "name": "Hat", + "description": "The ID of the hat to claim", + "type": "uint256", + "displayType": "hat" + } + ] + }, + { + "roles": ["public"], + "functionName": "claimHats", + "label": "Claim Multiple Hats", + "description": "Claim Multiple Hats", + "args": [ + { + "name": "Hats", + "description": "The IDs of the hats to claim", + "type": "uint256[]", + "displayType": "default" + } + ] + }, + { + "roles": ["public"], + "functionName": "claimHatFor", + "label": "Claim Hat For", + "description": "Claim a hat on behalf of an account", + "args": [ + { + "name": "Hat", + "description": "The ID of the hat to claim for", + "type": "uint256", + "displayType": "hat" + }, + { + "name": "Account", + "description": "The account for which to claim for", + "type": "address", + "displayType": "default" + } + ] + }, + { + "roles": ["public"], + "functionName": "claimHatsFor", + "label": "Claim Hats For", + "description": "Claim hats on behalf of accounts", + "args": [ + { + "name": "Hats", + "description": "The IDs of the hats to claim for", + "type": "uint256[]", + "displayType": "default" + }, + { + "name": "Accounts", + "description": "The accounts for which to claim for", + "type": "address[]", + "displayType": "default" + } + ] + } + ], "abi": [ { "inputs": [ diff --git a/test/schemaValidation.test.ts b/test/schemaValidation.test.ts index ec0d38d..84bbaec 100644 --- a/test/schemaValidation.test.ts +++ b/test/schemaValidation.test.ts @@ -64,9 +64,14 @@ describe("Schema Validation Tests", () => { throw new Error(`Module ${module.name} implementation is not verified`); } - expect(JSON.stringify(module.abi)).toBe( - JSON.stringify(JSON.parse(etherscanAbi.result)), - ); + if ( + JSON.stringify(module.abi) !== + JSON.stringify(JSON.parse(etherscanAbi.result)) + ) { + throw new Error( + `Module ${module.name} ABI does not match the verified ABI`, + ); + } } }, 30000); @@ -79,4 +84,109 @@ describe("Schema Validation Tests", () => { } } }); + + test("Test module roles", () => { + for (const [id, module] of Object.entries(modules)) { + const customRoles = module.customRoles; + const abi = module.abi; + for (let i = 0; i < customRoles.length; i++) { + const roleCreteria = customRoles[i].criteria; + const criteriaExists = abi.find((item) => { + if (item.type === "function" && item.name === roleCreteria) { + return true; + } else { + return false; + } + }); + + if (!criteriaExists) { + throw new Error( + `Error: module ${module.name} role criteria ${roleCreteria} does not exist in the ABI`, + ); + } + } + } + }, 30000); + + test("Test module write functions", () => { + for (const [id, module] of Object.entries(modules)) { + const moduleWriteFucntions = module.writeFunctions; + const abi = module.abi; + + // check that each write function in the module object exists in the ABI + for (let i = 0; i < moduleWriteFucntions.length; i++) { + const writeFunction = moduleWriteFucntions[i]; + const functionExists = abi.some((item) => { + if ( + item.type === "function" && + item.name === writeFunction.functionName && + item.inputs.length === writeFunction.args.length + ) { + for ( + let inputIndex = 0; + inputIndex < item.inputs.length; + inputIndex++ + ) { + if ( + item.inputs[inputIndex].type !== + writeFunction.args[inputIndex].type + ) { + return false; + } + } + return true; + } else { + return false; + } + }); + + if (!functionExists) { + throw new Error( + `Error: module ${module.name} write function ${writeFunction.functionName} does not exist in the ABI`, + ); + } + } + + // check that each write function in the ABI exists in the module object + const abiWriteFunctions = abi.filter( + (item) => + item.type === "function" && + item.stateMutability !== "view" && + item.stateMutability !== "pure", + ); + for (let i = 0; i < abiWriteFunctions.length; i++) { + const writeFunction = abiWriteFunctions[i]; + if (writeFunction.type === "function") { + const functionExists = moduleWriteFucntions.some((item) => { + if ( + writeFunction.type === "function" && + writeFunction.name === item.functionName && + writeFunction.inputs.length === item.args.length + ) { + for ( + let inputIndex = 0; + inputIndex < item.args.length; + inputIndex++ + ) { + if ( + item.args[inputIndex].type !== + writeFunction.inputs[inputIndex].type + ) { + return false; + } + } + return true; + } else { + return false; + } + }); + if (!functionExists && writeFunction.name !== "setUp") { + throw new Error( + `Error: module ${module.name} abi function ${writeFunction.name} does not exist in the module object`, + ); + } + } + } + } + }); });