Skip to content

Commit

Permalink
refactor: rename cli scripts folder
Browse files Browse the repository at this point in the history
  • Loading branch information
oddaf committed Aug 16, 2024
1 parent 56872ae commit c409944
Show file tree
Hide file tree
Showing 6 changed files with 893 additions and 0 deletions.
12 changes: 12 additions & 0 deletions cli/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# project
.env*

# node
node_modules/
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
64 changes: 64 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Protego Cli Scripts

## Usage

### 1. Install dependencies

```
npm i
```

### 2. Run scripts

List plans in `MCD_PAUSE` since block 16420000
```
npm run list 16420000
```

Pending plans in `MCD_PAUSE` since block 19420069
```
npm run list-pending 19420069
```

If no block number is passed, the script will fetch all plans since block 0.

## Output

```
╔═══════════════════════╤═══════════════════════════════════╤═══════════════════════╤═══════════════════════════════════╤════════════╤════════════╤════════════╗
║ SPELL │ HASH │ USR │ TAG │ FAX │ ETA │ STATUS ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0xc25A71BDF956229a035 │ 0x76167df75647db1661a3a49b83e589e │ 0xb1F78B20B3aAfdF061b │ 0xd5b5512ac3872a37517151f280f9b9f │ 0x61461954 │ 1723728263 │ EXECUTED ║
║ e35e8038d3FeE4aBa101C │ 9daaff46af3337552e15eb80ea8acf79f │ 0E85f2D3009c436764294 │ 3f37191196b05620d19af0f3c24f55b2e │ │ │ ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0x8c7F12C7cE07916f631 │ 0x1e4a20372c4647e9428efabca662d47 │ 0x46DD85e91Eab604ca15 │ 0x54561a83a0e6eb1959742ac526aeaa0 │ 0x61461954 │ 1722371399 │ EXECUTED ║
║ B25ce148e419FeFf19d46 │ 59f996f1353d2dcb05d52ed50def420f0 │ 0c26853a947617e7Ab322 │ 2e1d074fbbb8e26294b2a46a508c3ccf3 │ │ │ ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0x452a39C34f9539E0d50 │ 0x11e3af57c6821e4b4b45559c92f5c9d │ 0xA13D7e21643bD46E2cC │ 0x041f68b86ef5961f3d578a7192a09f1 │ 0x61461954 │ 1721070179 │ EXECUTED ║
║ C9e33Ad423a15C6f45df4 │ a681f2b7d2d232f91d7b64aa14d317f6a │ 09E87cFB91c5B951Bd955 │ 980b42bcefa8fecb810816369420c1e0c │ │ │ ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0x0c0B4DA7e02960F98c2 │ 0xb8f4b59cbfe45ba425eb9c10c8a50bd │ 0x0871e28D09c29C41966 │ 0xc8dec11fc102e8810674c4db724fb12 │ 0x61461954 │ 1720383443 │ EXECUTED ║
║ AFf2778F6f3E37321B5Dd │ 1eb919325eefdf095c44369098fd21e59 │ 9D82901d53d60A649B36D │ 9a790f93767cf54b691cbe3d2d33dd3d8 │ │ │ ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0x7fbC867dE58D6e47E43 │ 0x9ca00512f5e87da33fa1fa1e4834581 │ 0x261da1Cdbd788642034 │ 0x5e8fe783452994a42bbbe3b0edde5b9 │ 0x61461954 │ 1719777527 │ EXECUTED ║
║ 0eB257B50481F6E878f65 │ c8684ebd9091c7883355ea0ca959a78f2 │ 288B6574d749198FDf75b │ 901ff6bd7561b680b42af92293206bb32 │ │ │ ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0x622Ad624491a01a2a6b │ 0xd37c72ea00f67c76b6cda8dc0dda0b1 │ 0x6481e7443D321fFF02A │ 0xf218b00aeb30403e97dbedd8542caf1 │ 0x61461954 │ 1718481719 │ EXECUTED ║
║ eAD916C3Ca3B90BcA0854 │ b6f825145079e9acd23bdbcfe00259a3e │ 9A7ae883DCd13FAb64Ef7 │ a879c0e15796a20b5836cfadfe9a69b43 │ │ │ ║
╟───────────────────────┼───────────────────────────────────┼───────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────╢
║ 0x7B55617f7F04F7B45eE │ 0x2eb42ca4e054352eaa8ef09705925b3 │ 0x612938f231DFcd7F921 │ 0x25f5bbaef576d0cf62af933ec55a6bd │ 0x61461954 │ 1717623383 │ EXECUTED ║
║ 865fF9066469Fbe28a632 │ c12b4c0d1a59a050a20baa2b9d44396a8 │ 81F11C9E0B575E7ed2Ec1 │ 468b65fa9902387040283da6bf88ea4a9 │ │ │ ║
╚═══════════════════════╧═══════════════════════════════════╧═══════════════════════╧═══════════════════════════════════╧════════════╧════════════╧════════════╝
```

The script outputs a table with the plans' details:
- SPELL: Address of the spell (keep in mind this only works for compliant Spells, this field lists the plan scheduler address, which is the Spell on compliant spells, if non-compliant this field should be ignored)
- HASH: Hash of the plan
- USR: Address of the `DssSpellAction` related to the Spell
- TAG: `extcodehash` from the address of `DssSpellAction`
- FAX: `callcode` to be used when calling the Spell
- ETA: Timestamp of earliest execution time
- STATUS: Status of the plan:
- PENDING: The plan has been plotted (scheduled) on Pause, and is pending execution
- EXECUTED: The plan has already been executed
- DROPPED: The plan was scheduled and subsequently dropped
144 changes: 144 additions & 0 deletions cli/list-pause-plans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { ethers } from 'ethers';
import { table } from 'table';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import pauseABI from './pause_abi.json' with { type: 'json' };

const argv = yargs(hideBin(process.argv))
.option('pending', {
alias: 'p',
type: 'boolean',
description: 'Show only pending plans',
default: false
})
.option('fromBlock', {
alias: 'b',
type: 'number',
description: 'Display spells from a given block',
default: 0
})
.help()
.alias('help', 'h')
.argv;

const PLOT_TOPIC = "0x46d2fbbb00000000000000000000000000000000000000000000000000000000";
const EXEC_TOPIC = "0x168ccd6700000000000000000000000000000000000000000000000000000000";
const DROP_TOPIC = "0x162c7de300000000000000000000000000000000000000000000000000000000";
const MCD_PAUSE = "0xbE286431454714F511008713973d3B053A2d38f3";

const tableConfig = {
columns: {
0: { width: 21, wrapWord: true },
1: { width: 33, wrapWord: true },
2: { width: 21, wrapWord: true },
3: { width: 33, wrapWord: true },
4: { width: 10, wrapWord: true },
5: { width: 10, wrapWord: true },
6: { width: 10, wrapWord: true }
}
};

function getProvider() {
const url = process.env.ETH_RPC_URL || "mainnet";
if (!process.env.ETH_RPC_URL) {
console.warn("ETH_RPC_URL not set, falling back to a public RPC provider. For improved results set ETH_RPC_URL to a trusted node.");
}
return ethers.getDefaultProvider(url);
}

function decodeLogNote(log, contract) {
const eventFragment = contract.interface.getEvent('LogNote');
return contract.interface.decodeEventLog(eventFragment, log.data, log.topics).toObject();
}

function decodeCallParams(sig, fax, contract) {
const functionFragment = contract.interface.getFunction(sig);
return contract.interface.decodeFunctionData(functionFragment, fax).toObject();
}

function hash(params) {
const abiCoder = new ethers.AbiCoder();
const types = ["address", "bytes32", "bytes", "uint256"];
const encoded = abiCoder.encode(types, [params.usr, params.tag, params.fax, params.eta]);
return ethers.keccak256(encoded);
}

async function getFilteredEvents(contract, fromBlock) {
try {
return await contract.queryFilter([[PLOT_TOPIC, EXEC_TOPIC, DROP_TOPIC]], fromBlock);
} catch (error) {
console.error("Error fetching filtered events:", error);
throw error;
}
}

function processEvent(event, contract) {
const decoded = decodeLogNote(event, contract);
const decodedCall = decodeCallParams(event.topics[0].slice(0, 10), decoded.fax, contract);
return {
...event,
decoded,
decodedCall,
planHash: hash(decodedCall)
};
}

function prepareData(events, contract, filter) {
const decodedEvents = events.map(event => processEvent(event, contract));

const tableData = [];
const hashMap = new Map();

decodedEvents.forEach(event => {
const planHash = event.planHash;

if (event.topics[0] === PLOT_TOPIC) {
const row = [event.decoded.guy, planHash, event.decodedCall.usr, event.decodedCall.tag, event.decodedCall.fax.trim(), event.decodedCall.eta, "PENDING"];
tableData.push(row);
hashMap.set(planHash, row);
} else if (event.topics[0] === EXEC_TOPIC) {
const row = hashMap.get(planHash);
if (row) {
row[6] = "EXECUTED";
}
} else if (event.topics[0] === DROP_TOPIC) {
const row = hashMap.get(planHash);
if (row) {
row[6] = "DROPPED";
}
}
});

tableData.sort((a, b) => {
const etaA = BigInt(a[5]);
const etaB = BigInt(b[5]);
return etaB > etaA ? 1 : etaB < etaA ? -1 : 0;
});

if (filter)
return tableData.filter(row => row[6] === filter);
else
return tableData;
}

async function main() {
try {
const provider = getProvider();
const pause = new ethers.Contract(MCD_PAUSE, pauseABI, provider);

const events = await getFilteredEvents(pause, argv.fromBlock);
let tableData = prepareData(events, pause, argv.pending ? "PENDING" : null);

tableData.unshift(["SPELL", "HASH", "USR", "TAG", "FAX", "ETA", "STATUS"]);

if (tableData.length === 1) {
console.log("No records to display.");
} else {
console.log(table(tableData, tableConfig));
}
} catch (error) {
console.error("An error occurred:", error);
}
}

main();
Loading

0 comments on commit c409944

Please sign in to comment.