-
Notifications
You must be signed in to change notification settings - Fork 4
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
feature: scripts for fetching plan execution statuses #5
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good overall, I thought it would be way more complex than this due to LibNote
.
I pointed a couple of issues with the data fetching strategy, and also we might need to figure out a way to reference the spell address itself, other than usr
. A conforming spell uses the associated action
as usr
, however users (devs included), often refer to the spell main address.
scripts/list-pause-plans.js
Outdated
let tableData = prepareTableData(events, pause); | ||
|
||
if (!argv.all && !argv.pending) { | ||
tableData = tableData.length > 21 ? [tableData[0], ...tableData.slice(-20)] : tableData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the suggestion about data sorting by newest values first is applied, this can be simplified as:
tableData = tableData.length > 21 ? [tableData[0], ...tableData.slice(-20)] : tableData; | |
tableData = tableData.length > 21 ? tableData.slice(0, 21) : tableData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic was removed in favor of the fromBlock parameter: f6e02c3
scripts/list-pause-plans.js
Outdated
if (!argv.all && !argv.pending) { | ||
tableData = tableData.length > 21 ? [tableData[0], ...tableData.slice(-20)] : tableData; | ||
} else if (argv.pending) { | ||
tableData = tableData.filter(row => row[6] === "pending" || row[0] === "HASH"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comparison will fail because of mismatching cases:
tableData = tableData.filter(row => row[6] === "pending" || row[0] === "HASH"); | |
tableData = tableData.filter(row => row[6] === "PENDING" || row[0] === "HASH"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also in general, I would prefer to keep the presentation layer as simple as possible and do all filtering when data is being fetched.
This allows that part of the script to be reused by a front-end, which would not need to re-implement this sort of logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scripts/README.md
Outdated
|
||
### 2. Run scripts | ||
|
||
List the 20 most recent plans in `MCD_PAUSE` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that instead of fixing an arbitrary number of events to return, we could maybe let the user specify how many blocks they want to go in the past.
However, that introduces one edge case: events for the same [usr, tag, fax, eta]
might be missing because of the from
block. It's usually fine, as we can consider any subsequent exec
or drop
to have been preceded by a plan
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in f6e02c3
scripts/README.md
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As commented in the README, usr
usually refers to the DssSpellAction
for conforming spells, not to the spell itself.
I believe the script should somehow return the associated spell address. I'm not entirely sure how to get that information, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[...] I'm not entirely sure how to get that information, though.
Oh, I just noticed that msg.sender
is logged as topic 1:
https://vscode.blockscan.com/ethereum/0xbe286431454714f511008713973d3b053a2d38f3#L43
For conforming spells, this can be used to obtain the spell address.
Since it's not guaranteed, maybe the column should be named SENDER
and the documentation should explain that this COULD be the spell address 🤷🏻♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 5843d92
Oh, I just noticed that there are both a |
Co-authored-by: amusingaxl <[email protected]>
Co-authored-by: amusingaxl <[email protected]>
…to feat/scripts
I renamed the folder |
cli/list-pause-plans.js
Outdated
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."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this also be a CLI parameter? Like --eth-rpc-url
?
It could default to the env var if it's set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in a683b60
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made some additional suggestions
|
||
Pending plans in `MCD_PAUSE` since block 19420069 | ||
``` | ||
node list-pause-plans -pending --from-block 19420069 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
node list-pause-plans -pending --from-block 19420069 | |
node list-pause-plans --pending --from-block 19420069 |
alias: 'e', | ||
type: 'string', | ||
description: 'Rpc URL - Falls back to ETH_RPC_URL env var, then to a public provider', | ||
default: 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're being faithful to the description above, we should handle that here:
default: 0 | |
default: process.env.ETH_RPC_URL || 'mainnet' |
.option('eth-rpc-url', { | ||
alias: 'e', | ||
type: 'string', | ||
description: 'Rpc URL - Falls back to ETH_RPC_URL env var, then to a public provider', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
description: 'Rpc URL - Falls back to ETH_RPC_URL env var, then to a public provider', | |
description: 'RPC URL - Falls back to `ETH_RPC_URL` env var, then to a public provider', |
.option('eth-rpc-url', { | ||
alias: 'e', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function getProvider() { | ||
const url = argv.ethRpcUrl || process.env.ETH_RPC_URL || "mainnet"; | ||
if (url == "mainnet") { | ||
console.warn("Falling back to a public provider. For best experience set a custom RPC URL."); | ||
} | ||
return ethers.getDefaultProvider(url); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the suggestion above is applied, then this whole function becomes superfluous:
function getProvider() { | |
const url = argv.ethRpcUrl || process.env.ETH_RPC_URL || "mainnet"; | |
if (url == "mainnet") { | |
console.warn("Falling back to a public provider. For best experience set a custom RPC URL."); | |
} | |
return ethers.getDefaultProvider(url); | |
} | |
if (argv.rpcUrl == "mainnet") { | |
console.warn("Falling back to a public provider. For best experience set a custom RPC URL."); | |
} |
const provider = getProvider(); | ||
const pause = new ethers.Contract(MCD_PAUSE, pauseABI, provider); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const provider = getProvider(); | |
const pause = new ethers.Contract(MCD_PAUSE, pauseABI, provider); | |
const provider = getProvider(); | |
const pause = new ethers.Contract(MCD_PAUSE, pauseABI, ethers.getDefaultProvider(argv.rpcUrl)); |
.alias('help', 'h') | ||
.argv; | ||
|
||
const MCD_PAUSE = "0xbE286431454714F511008713973d3B053A2d38f3"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This most likely belongs in the pause-plan-data.js
file.
}; | ||
} | ||
|
||
export function prepareData(events, contract, filter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function conflates data processing with data viewing.
prepareData
should return an array of objects instead and let the table-formatting to the upper level.
You can and should enrich the data here, (i.e.: figuring out the status), as this part of the data logic, however it should return the data in the most agnostic way possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should probably be a façade function that hides all implementation details and returns plain data in this file.
From an information ownership perspective, it should also take care of instantiating the Pause
contract.
All configurable options should be passed in as an options object:
const MCD_PAUSE = "0xbE286431454714F511008713973d3B053A2d38f3";
export const PlanStatus = {
ALL: 'ALL',
PENDING: 'PENDING',
DROPPED: 'DROPPED',
EXECUTED: 'EXECUTED',
}
// Considering 1 block every 12.5 secs
const FROM_1_YEAR_AGO = -2522880;
export async function getPausePlans(
provider,
{ fromBlock = FROM_1_YEAR_AGO, status = PlanStatus.ALL } = {},
) {
const pause = new ethers.Contract(MCD_PAUSE, pauseABI, provider);
const events = await getFilteredEvents(pause, fromBlock);
const filter = status === PlanStatus.ALL ? undefined : status;
return prepareData(events, pause, filter);
}
This way it can be more easily consumed by different clients, being it the CLI in the other script or a 3rd party UI.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of importing prepareData
, there should be a function in this file that will turn the enriched raw data into a table structure.
Oh, please remove the top-level |
Resolves #3