Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProcessPermissions tests #324

Merged
merged 4 commits into from
Feb 10, 2025
Merged
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
17 changes: 8 additions & 9 deletions packages/sdk/src/permissions/mergeFunctionPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@ import { coercePermission, targetId, isFunctionScoped } from "./utils"
*/
export const mergeFunctionPermissions = (permissions: Permission[]) =>
permissions.reduce((result, entry) => {
if (!isFunctionScoped(entry)) {
result.push({
...entry,
targetAddress: entry.targetAddress.toLowerCase() as `0x${string}`,
})
return result
entry = {
...entry,
targetAddress: entry.targetAddress.toLowerCase() as `0x${string}`,
}

const coercedEntry = coercePermission(entry)

const matchingEntry = result.find(
Expand All @@ -43,8 +39,11 @@ export const mergeFunctionPermissions = (permissions: Permission[]) =>
return result
}

// merge conditions into the entry we already have
matchingEntry.condition = mergeConditions(matchingEntry, coercedEntry)
if ("selector" in coercedEntry) {
// merge conditions into the entry we already have
matchingEntry.condition = mergeConditions(matchingEntry, coercedEntry)
}

return result
}, [] as PermissionCoerced[])

Expand Down
363 changes: 363 additions & 0 deletions packages/sdk/src/permissions/processPermissions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,363 @@
import { describe, expect, it, suite } from "vitest"
import { processPermissions } from "./processPermissions"
import {
Clearance,
ExecutionOptions,
Operator,
ParameterType,
} from "zodiac-roles-deployments"
import { encodeAbiParameters } from "../utils/encodeAbiParameters"
import { normalizeCondition } from "../conditions"

const DUMMY_COMP = (id: number) => ({
paramType: ParameterType.Static,
operator: Operator.Custom,
compValue: encodeAbiParameters(["uint256"], [id]),
})

suite("processPermissions()", () => {
/*
* nomenclature for these tests:
* allowed -> Clearance.Target, i.e., target fully allowed
* wildcarded -> Clearance.Function AND wildcarded == true AND condition == undefined
* conditional -> Clearance.Function AND wildcarded == false AND condition == defined
*/

const AddressOne = "0x0000000000000000000000000000000000000001"
const AddressTwo = "0x0000000000000000000000000000000000000002"

describe("allowed + allowed", () => {
it("processes for distinct targetAddresses ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne },
{ targetAddress: AddressTwo },
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Target,
executionOptions: ExecutionOptions.None,
functions: [],
},
{
address: AddressTwo,
clearance: Clearance.Target,
executionOptions: ExecutionOptions.None,
functions: [],
},
],
annotations: [],
})
})

it("filters out duplicate entry ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne },
{ targetAddress: AddressOne },
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Target,
executionOptions: ExecutionOptions.None,
functions: [],
},
],
annotations: [],
})
})

it("throws on out duplicate entry with incompatible execution options ❌", () => {
expect(() =>
processPermissions([
{ targetAddress: AddressOne, send: true },
{ targetAddress: AddressOne, delegatecall: true },
])
).toThrowError()
})
})

describe("allowed + wildcarded", () => {
it("processes distinct targetAddresses ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne },
{ targetAddress: AddressTwo, selector: "0x1" },
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Target,
executionOptions: ExecutionOptions.None,
functions: [],
},
{
address: AddressTwo,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: true,
condition: undefined,
},
],
},
],
annotations: [],
})
})
it("throws for same targetAddress ❌", () => {
expect(() => {
processPermissions([
{ targetAddress: AddressOne },
{ targetAddress: AddressOne, selector: "0x1" },
])
}).toThrowError(
"An address can either be fully allowed or scoped to selected functions. The following addresses are both: 0x0000000000000000000000000000000000000001"
)
})
})

describe("allowed + conditional", () => {
it("throws for same targetAddress ❌", () => {
expect(() => {
processPermissions([
{ targetAddress: AddressOne },
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(1),
},
])
}).toThrowError(
"An address can either be fully allowed or scoped to selected functions. The following addresses are both: 0x0000000000000000000000000000000000000001"
)
})
})

describe("wilcarded + wildcarded", () => {
it("processes distinct targetAddresses ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne, selector: "0x1" },
{ targetAddress: AddressTwo, selector: "0x1" },
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: true,
condition: undefined,
},
],
},
{
address: AddressTwo,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: true,
condition: undefined,
},
],
},
],
annotations: [],
})
})
it("filters out duplicate for same targetAddress ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne, selector: "0x1" },
{ targetAddress: AddressOne, selector: "0x1" },
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: true,
condition: undefined,
},
],
},
],
annotations: [],
})
})
it("throws on duplicate with incompatible execution options ❌", () => {
expect(() =>
processPermissions([
{ targetAddress: AddressOne, selector: "0x1", send: true },
{ targetAddress: AddressOne, selector: "0x1", delegatecall: true },
])
).toThrowError()
})
})

describe("wilcarded + conditional", () => {
it("processes for different targetAddresses ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne, selector: "0x1" },
{
targetAddress: AddressTwo,
selector: "0x2",
condition: DUMMY_COMP(1),
},
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: true,
condition: undefined,
},
],
},
{
address: AddressTwo,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x2",
executionOptions: ExecutionOptions.None,
wildcarded: false,
condition: normalizeCondition(DUMMY_COMP(1)),
},
],
},
],
annotations: [],
})
})
it("ignores conditional, fallbacks to wildcarded, for same targetAddress ✅", () => {
expect(
processPermissions([
{ targetAddress: AddressOne, selector: "0x1" },
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(1),
},
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: true,
condition: undefined,
},
],
},
],
annotations: [],
})
})
it("throws on incompatible execution options ❌", () => {
expect(() =>
processPermissions([
{ targetAddress: AddressOne, selector: "0x1", send: true },
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(1),
send: false,
},
])
).toThrowError()
})
})

describe("condtional + conditional", () => {
it("merges compatible conditional permissions for same targetAddress and selector, via OR ✅", () => {
expect(
processPermissions([
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(1),
},
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(2),
},
])
).to.deep.equal({
targets: [
{
address: AddressOne,
clearance: Clearance.Function,
executionOptions: ExecutionOptions.None,
functions: [
{
selector: "0x1",
executionOptions: ExecutionOptions.None,
wildcarded: false,
condition: normalizeCondition({
paramType: ParameterType.None,
operator: Operator.Or,
children: [DUMMY_COMP(1), DUMMY_COMP(2)],
}),
},
],
},
],
annotations: [],
})
})
it("throws for same targetAddress and selector, when incompatible execution options ❌", () => {
expect(() =>
processPermissions([
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(1),
send: false,
},
{
targetAddress: AddressOne,
selector: "0x1",
condition: DUMMY_COMP(2),
send: true,
},
])
).toThrowError()
})
})
})
Loading