Skip to content

Commit

Permalink
Add upgradeExecutorFetchPrivilegedAccounts util to UpgradeExecutor file
Browse files Browse the repository at this point in the history
  • Loading branch information
TucksonDev committed Dec 21, 2023
1 parent 737175c commit d2c0ddc
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 3 deletions.
135 changes: 133 additions & 2 deletions src/upgradeExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { encodeFunctionData, EncodeFunctionDataParameters } from 'viem';

import { Address, encodeFunctionData, EncodeFunctionDataParameters, keccak256, PublicClient, toHex } from 'viem';
import { AbiEvent } from 'abitype'
import { upgradeExecutor } from './contracts';
import { GetFunctionName, Prettify } from './types/utils';

Expand Down Expand Up @@ -28,3 +28,134 @@ export function upgradeExecutorEncodeFunctionData<
args,
});
}

export type UpgradeExecutorFetchPrivilegedAccountsParams = {
upgradeExecutorAddress: Address;
publicClient: PublicClient;
};

export type UpgradeExecutorPrivilegedAccounts = {
// Key: account
// Value: array of roles
[key: `0x${string}`]: `0x${string}`[];
};

export const UPGRADE_EXECUTOR_ROLE_ADMIN = keccak256(toHex('ADMIN_ROLE'));
export const UPGRADE_EXECUTOR_ROLE_EXECUTOR = keccak256(toHex('EXECUTOR_ROLE'));

type RoleGrantedLogArgs = {
role: `0x${string}`;
account: `0x${string}`;
sender: `0x${string}`;
};
type RoleRevokedLogArgs = RoleGrantedLogArgs;

const RoleGrantedEventAbi: AbiEvent = {
inputs: [
{
indexed: true,
internalType: 'bytes32',
name: 'role',
type: 'bytes32',
},
{
indexed: true,
internalType: 'address',
name: 'account',
type: 'address',
},
{
indexed: true,
internalType: 'address',
name: 'sender',
type: 'address',
},
],
name: 'RoleGranted',
type: 'event',
};

const RoleRevokedEventAbi: AbiEvent = {
inputs: [
{
indexed: true,
internalType: 'bytes32',
name: 'role',
type: 'bytes32',
},
{
indexed: true,
internalType: 'address',
name: 'account',
type: 'address',
},
{
indexed: true,
internalType: 'address',
name: 'sender',
type: 'address',
},
],
name: 'RoleGranted',
type: 'event',
};

export async function upgradeExecutorFetchPrivilegedAccounts({
upgradeExecutorAddress,
publicClient,
}: UpgradeExecutorFetchPrivilegedAccountsParams) {
// 0. Initialize result object
const upgradeExecutorPrivilegedAccounts: UpgradeExecutorPrivilegedAccounts = {};

// 1. Find the RoleGranted events
const roleGrantedEvents = await publicClient.getLogs({
address: upgradeExecutorAddress,
event: RoleGrantedEventAbi,
fromBlock: 'earliest',
toBlock: 'latest',
});
if (!roleGrantedEvents || roleGrantedEvents.length <= 0) {
// No roles have been granted
return upgradeExecutorPrivilegedAccounts;
}

// 2. Add the privileged accounts to the result object
roleGrantedEvents.forEach((roleGrantedEvent) => {
const account = (roleGrantedEvent.args as RoleGrantedLogArgs).account;
const role = (roleGrantedEvent.args as RoleGrantedLogArgs).role;

if (!(account in upgradeExecutorPrivilegedAccounts)) {
upgradeExecutorPrivilegedAccounts[account] = [];
}
upgradeExecutorPrivilegedAccounts[account].push(role);
});

// 3. Find the RoleRevoked events
const roleRevokedEvents = await publicClient.getLogs({
address: upgradeExecutorAddress,
event: RoleRevokedEventAbi,
fromBlock: 'earliest',
toBlock: 'latest',
});
if (!roleRevokedEvents || roleRevokedEvents.length <= 0) {
return upgradeExecutorPrivilegedAccounts;
}

// 3. Remove the revoked roles from the result object
// (Note: if the same role has been added and revoked multiple times, it will be added and removed multiple times from upgradeExecutorPrivilegedAccounts[account] )
roleRevokedEvents.forEach((roleRevokedEvent) => {
const account = (roleRevokedEvent.args as RoleRevokedLogArgs).account;
const role = (roleRevokedEvent.args as RoleRevokedLogArgs).role;

const roleIndex = upgradeExecutorPrivilegedAccounts[account].findIndex((accRole) => accRole == role);
if (roleIndex >= 0) {
upgradeExecutorPrivilegedAccounts[account] = upgradeExecutorPrivilegedAccounts[account].splice(roleIndex, 1);
}
});

return upgradeExecutorPrivilegedAccounts;
}
function hex(arg0: string): `0x${string}` | Uint8Array {
throw new Error('Function not implemented.');
}

23 changes: 22 additions & 1 deletion src/upgradeExecutor.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { it, expect } from 'vitest';
import { upgradeExecutorEncodeFunctionData, upgradeExecutorFetchPrivilegedAccounts, UPGRADE_EXECUTOR_ROLE_ADMIN, UPGRADE_EXECUTOR_ROLE_EXECUTOR } from './upgradeExecutor';
import { createPublicClient, http } from 'viem';
import { arbitrum } from 'viem/chains';

import { upgradeExecutorEncodeFunctionData } from './upgradeExecutor';
const publicClient = createPublicClient({
chain: arbitrum,
transport: http(),
});

// taken from https://arbiscan.io/tx/0xc7e6188415d5572b305219c9b01d773693bc5b07cd1a8ab3e1278107275016e5
it('upgradeExecutorEncodeFunctionData', () => {
Expand All @@ -16,3 +22,18 @@ it('upgradeExecutorEncodeFunctionData', () => {
'0x1cff79cd0000000000000000000000009bf7b8884fa381a45f8cb2525905fb36c996297a00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000204536d8944000000000000000000000000add68bcb0f66878ab9d37a447c7b9067c5dfa94100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000003bd8e2ac65ad6f0f094ba6766cbd9484ab49ef23000000000000000000000000f8e1492255d9428c2fc20a98a1deb1215c8ffefd000000000000000000000000b07dc9103328a51128bc6cc1049d1137035f5e280000000000000000000000003e286452b1c66abb08eb5494c3894f40ab5a59af000000000000000000000000b71ca4ffbb7b58d75ba29891ab45e9dc12b444ed0000000000000000000000008f10e3413586c4a8dcfce19d009872b19e9cd8e3000000000000000000000000566a07c3c932ae6af74d77c29e5c30d8b18537100000000000000000000000005280406912eb8ec677df66c326be48f938dc2e440000000000000000000000000275b3d54a5ddbf8205a75984796efe8b7357bae0000000000000000000000005a1fd562271aac2dadb51baab7760b949d9d81df000000000000000000000000f6b6f07862a02c85628b3a9688beae07fea9c863000000000000000000000000475816ca2a31d601b4e336f5c2418a67978abf0900000000000000000000000000000000000000000000000000000000'
);
});

// Temporary test with https://arbiscan.io/address/0x0611b78A42903a537BE7a2f9a8783BE39AC63cD9#events
it ('it fetches the right privileged accounts from an UpgradeExecutor', async () => {
const upgradeExecutorAddress = '0x0611b78A42903a537BE7a2f9a8783BE39AC63cD9';
const chainOwner = '0xD1C955A1544cF449F4a8463E9fE2AC4Ff0798E05';

const privilegedAccounts = await upgradeExecutorFetchPrivilegedAccounts({
upgradeExecutorAddress,
publicClient,
});

expect(Object.keys(privilegedAccounts).length).toEqual(2);
expect(privilegedAccounts[upgradeExecutorAddress]).toEqual([UPGRADE_EXECUTOR_ROLE_ADMIN]);
expect(privilegedAccounts[chainOwner]).toEqual([UPGRADE_EXECUTOR_ROLE_EXECUTOR]);
});

0 comments on commit d2c0ddc

Please sign in to comment.