-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
893 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
Oops, something went wrong.