Skip to content

Commit 3915915

Browse files
authored
fix(CLI): add --nonce to propose_from_simulation (#105)
* fix(CLI): add `--nonce` to `propose_from_simulation` * fix(CLI): forgot to pass-through new argument `nonce` * docs(Userguides): update `production` userguide to clarify some things
1 parent c8bba65 commit 3915915

File tree

3 files changed

+57
-28
lines changed

3 files changed

+57
-28
lines changed

ape_safe/_cli/pending.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ def ensure(cli_ctx, ecosystem, network, submitter, safe):
478478
f"Running queue script for nonce {nonce} ('{script_path}'):\n\n {cmd.help}\n"
479479
)
480480
# NOTE: This matches signature from `ape_safe.cli:propose_batch`
481-
cmd.callback.__wrapped__.func(cli_ctx, network, submitter, safe)
481+
cmd.callback.__wrapped__.func(cli_ctx, network, submitter, nonce, safe)
482482

483483
if not network.is_fork:
484484
cli_ctx.logger.success(f"Queue for {safe.address} up-to-date!")

ape_safe/cli.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import inspect
2-
from typing import TYPE_CHECKING, Callable
2+
from typing import TYPE_CHECKING, Callable, Optional
33

44
import click
55
from ape.api.accounts import ImpersonatedAccount
@@ -84,11 +84,19 @@ def decorator(
8484
"--submitter",
8585
prompt="Select an account to submit or propose transaction(s)",
8686
)
87+
@click.option(
88+
"--nonce",
89+
type=int,
90+
default=None,
91+
help="Set value of `nonce` for txn."
92+
" Will parse integer value of end of script name to automatically set.",
93+
)
8794
@safe_argument
8895
def new_cmd(
8996
cli_ctx: ApeCliContextObject,
9097
network: "NetworkAPI",
9198
submitter: "AccountAPI",
99+
nonce: Optional[int],
92100
safe: "SafeAccount",
93101
):
94102
if "safe" in args:
@@ -100,6 +108,14 @@ def new_cmd(
100108
batch = safe.create_batch()
101109
total_gas_used = 0
102110

111+
if nonce is None:
112+
# NOTE: Saves an on-chain call (and also works with `pending ensure`)
113+
if (mod_name := cmd.__module__.split(".")[-1]).startswith("nonce"):
114+
nonce = int(mod_name.replace("nonce", ""))
115+
116+
else:
117+
nonce = safe.next_nonce
118+
103119
with (
104120
cli_ctx.chain_manager.isolate()
105121
if network.is_fork
@@ -142,7 +158,10 @@ def new_cmd(
142158
cli_ctx.logger.info("Only 1 call found, calling directly instead of MultiSend")
143159
txn = batch.calls[0]
144160
safe_tx = safe.create_safe_tx(
145-
to=txn["target"], value=txn["value"], data=txn["callData"]
161+
to=txn["target"],
162+
value=txn["value"],
163+
data=txn["callData"],
164+
nonce=nonce,
146165
)
147166

148167
if network.is_fork: # Testing, execute as a simulation (don't set nonce)

docs/userguides/production.md

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,23 @@ When co-managing a Safe with a larger team, ape-safe brings extra tools to the t
44

55
## Queue Scripts
66

7-
You can define "queue scripts" which are scripts under your project's `scripts/` folder that follow
8-
a naming convention (either `scripts/nonce<N>.py` or `scripts/<ecosystem>_<network>_nonce<N>.py`),
9-
and then use the [`propose_from_simulation`](../../methoddocs/cli) decorator.
7+
You can define "queue scripts" which are scripts under your project's `scripts/` folder that use
8+
the [`propose_from_simulation`](../methoddocs/cli) decorator in your script.
109

11-
```{note}
12-
The value of the nonce `N` must correspond to a specific nonce above the current on-chain
13-
value of `nonce` from the safe, or it will not be recognized by our other queue management command.
10+
```{important}
11+
These scripts should follow a recommended naming convention by naming them either
12+
`scripts/nonce<N>.py` or `scripts/<ecosystem>_<network>_nonce<N>.py`).
13+
This will automatically registry with the [queue management](#queue-management)
14+
subcommand that ships with ape-safe.
15+
16+
The value of the nonce `N` must correspond to a specific nonce above the current on-chain contract
17+
value of `nonce` from the Safe, or it will not be collected by the queue management command.
1418
```
1519

1620
An example:
1721

1822
```py
23+
# scripts/nonce<N>.py
1924
from ape_safe.cli import propose_from_simulation
2025

2126

@@ -26,7 +31,7 @@ def cli():
2631
# Use normal Ape features
2732
my_contract = Contract("<address>")
2833

29-
# Any transaction is performed as if `sender=safe.address`
34+
# Any transaction is performed as if `sender=safe.address` (using Ape's default sender support)
3035
my_contract.mutableMethod(...)
3136

3237
# You can make assertions that will cause your simulation to fail if tripped
@@ -35,18 +40,26 @@ def cli():
3540
# You can also add conditional calls
3641
if my_contract.viewMethod() < some_number:
3742
my_contract.mutableMethod()
43+
```
3844

39-
# Once you are done with your transactions, the simulation will complete after exiting
45+
```{warning}
46+
The callback function **MUST** be named `cli` or it won't work with Ape's script runner.
4047
```
4148

4249
Once the simulation is complete, the decorator will collect all receipts it finds from the `safe`'s
4350
history during that session, and collect them into a single SafeTx to propose to a public network.
4451

45-
```{important}
46-
The name of the decorated function in your queue script **must** be `cli` for it to work.
52+
```{note}
53+
If only one transaction is detected, it will "condense" that as a direct call,
54+
instead of using `MultiSend` (which is used for >1 detected transactions).
4755
```
4856

49-
The decorated function may have `safe` or `submitter` args in it, in order to access their values.
57+
The decorated function may have `safe` or `submitter` args in it,
58+
in order to access their values within your simulation.
59+
60+
```{note}
61+
If `submitter` is needed, `safe` must also be present in the args.
62+
```
5063

5164
```py
5265
@propose_from_simulation()
@@ -59,29 +72,26 @@ def cli(safe, submitter):
5972
assert token.balanceOf(submitter) == bal_before + amount
6073
```
6174

62-
You can run the script directly using the following command, and it will dry-run the transaction:
75+
You can run the script directly using the following command, and it will "dry-run" the `SafeTx`:
6376

6477
```sh
6578
$ ape run nonce<N> your-safe --network ethereum:mainnet-fork --submitter TEST::0
6679
```
6780

81+
## Queue Management
82+
6883
We also provide a command [`ape safe pending ensure`](../../commands/pending#ape-safe-pending-ensure)
69-
that allows you to execute all matching nonce commands up to the latest you have defined in sequence.
70-
This allows you to check for side-effects of commands in the queue, helping to reduce human error.
84+
that allows you to execute **all** matching queue scripts you have defined in `scripts/`.
85+
This allows you to check side-effects from running all commands in the queue,
86+
helping to reduce human error.
7187

72-
To execute a dry-run of all matching queue scripts for your safe, execute the following:
88+
To execute a dry-run of all matching queue scripts for your Safe, execute the following:
7389

7490
```sh
7591
$ ape safe pending ensure --safe your-safe --network ethereum:mainnet-fork --submitter TEST::0
7692
```
7793

78-
Once you are ready, you can "propose" your queue script to the Safe API via the following:
79-
80-
```sh
81-
$ ape run nonce<N> your-safe --network ethereum:mainnet --submitter local-wallet
82-
```
83-
84-
You can also propose all of your queue scripts (if there are discrepencies) to the Safe API via:
94+
Once you are ready, you can "push" your queue scripts to the Safe API via the following:
8595

8696
```sh
8797
$ ape safe pending ensure --safe your-safe --network ethereum:mainnet --submitter local-wallet
@@ -93,10 +103,10 @@ by the Safe API as a delegate for another signer, otherwise it will fail to prop
93103
```
94104

95105
```{note}
96-
It is recommended to use our ensure command in a secure context, such as Github Actions, where all
106+
It is recommended to use our `ensure` command in a secure context, such as Github Actions, where all
97107
scripts can be reviewed by signers, and access is controlled behind Github's access control system.
98108
```
99109

100-
<!-- TODO: Add Github Action? -->
110+
<!-- TODO: Add Github Action for `pending ensure` command? -->
101111

102-
<!-- TODO: Add self-hosted API? -->
112+
<!-- TODO: Add self-hosting the Safe API w/ `ape safe host`? -->

0 commit comments

Comments
 (0)