Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions modules/baalStakingEligibility.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
212 changes: 211 additions & 1 deletion modules/multiClaimsHatter.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
116 changes: 113 additions & 3 deletions test/schemaValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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`,
);
}
}
}
}
});
});