Skip to content

Commit ef6bb0e

Browse files
committed
fix(forge): fix nonce for tx with 7702 auth
1 parent 292d248 commit ef6bb0e

File tree

5 files changed

+155
-10
lines changed

5 files changed

+155
-10
lines changed

crates/cheatcodes/src/inspector.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,9 @@ where {
11521152
(Some(auth_list), None) => {
11531153
tx_req.authorization_list = Some(vec![auth_list]);
11541154
tx_req.sidecar = None;
1155+
1156+
// Increment nonce to reflect the signed authorization.
1157+
account.info.nonce += 1;
11551158
}
11561159
(None, Some(blob_sidecar)) => {
11571160
tx_req.set_blob_sidecar(blob_sidecar);

crates/cheatcodes/src/script.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ fn sign_delegation(
9898
} else {
9999
let authority_acc =
100100
ccx.ecx.journaled_state.load_account(signer.address(), &mut ccx.ecx.db)?;
101-
authority_acc.data.info.nonce
101+
// If we don't have a nonce then use next auth account nonce.
102+
authority_acc.data.info.nonce + 1
102103
};
103104
let auth = Authorization {
104105
address: implementation,
@@ -125,12 +126,19 @@ fn sign_delegation(
125126
fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<()> {
126127
let authority = auth.recover_authority().map_err(|e| format!("{e}"))?;
127128
let authority_acc = ccx.ecx.journaled_state.load_account(authority, &mut ccx.ecx.db)?;
129+
130+
// Create and set bytecode with incremented nonce.
131+
authority_acc.data.info.nonce += 1;
128132
if authority_acc.data.info.nonce != auth.nonce {
129133
return Err("invalid nonce".into());
130134
}
131-
authority_acc.data.info.nonce += 1;
135+
132136
let bytecode = Bytecode::new_eip7702(*auth.address());
133137
ccx.ecx.journaled_state.set_code(authority, bytecode);
138+
139+
// Reset authority nonce.
140+
let authority_acc = ccx.ecx.journaled_state.load_account(authority, &mut ccx.ecx.db)?;
141+
authority_acc.data.info.nonce -= 1;
134142
Ok(())
135143
}
136144

crates/forge/tests/cli/script.rs

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::constants::TEMPLATE_CONTRACT;
44
use alloy_primitives::{address, hex, Address, Bytes};
5-
use anvil::{spawn, NodeConfig};
5+
use anvil::{spawn, EthereumHardfork, NodeConfig};
66
use forge_script_sequence::ScriptSequence;
77
use foundry_test_utils::{
88
rpc::{self, next_http_archive_rpc_url},
@@ -2720,3 +2720,140 @@ Warning: No transactions to broadcast.
27202720
"#
27212721
]);
27222722
});
2723+
2724+
// Tests EIP-7702 broadcast <https://github.com/foundry-rs/foundry/issues/10461>
2725+
forgetest_async!(can_broadcast_txes_with_signed_auth, |prj, cmd| {
2726+
foundry_test_utils::util::initialize(prj.root());
2727+
prj.add_script(
2728+
"EIP7702Script.s.sol",
2729+
r#"
2730+
import "forge-std/Script.sol";
2731+
import {Vm} from "forge-std/Vm.sol";
2732+
import {Counter} from "../src/Counter.sol";
2733+
contract EIP7702Script is Script {
2734+
uint256 constant PRIVATE_KEY = uint256(bytes32(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80));
2735+
address constant SENDER = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
2736+
function setUp() public {}
2737+
function run() public {
2738+
vm.startBroadcast(PRIVATE_KEY);
2739+
Counter counter = new Counter();
2740+
Counter counter1 = new Counter();
2741+
Counter counter2 = new Counter();
2742+
vm.signAndAttachDelegation(address(counter), PRIVATE_KEY);
2743+
Counter(SENDER).increment();
2744+
Counter(SENDER).increment();
2745+
vm.signAndAttachDelegation(address(counter1), PRIVATE_KEY);
2746+
Counter(SENDER).setNumber(0);
2747+
vm.signAndAttachDelegation(address(counter2), PRIVATE_KEY);
2748+
Counter(SENDER).setNumber(0);
2749+
vm.stopBroadcast();
2750+
}
2751+
}
2752+
"#,
2753+
)
2754+
.unwrap();
2755+
2756+
let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::PragueEOF.into()));
2757+
let (_api, handle) = spawn(node_config).await;
2758+
2759+
cmd.args([
2760+
"script",
2761+
"script/EIP7702Script.s.sol",
2762+
"--rpc-url",
2763+
&handle.http_endpoint(),
2764+
"-vvvvv",
2765+
"--non-interactive",
2766+
"--slow",
2767+
"--broadcast",
2768+
"--evm-version",
2769+
"prague",
2770+
])
2771+
.assert_success()
2772+
.stdout_eq(str![[r#"
2773+
[COMPILING_FILES] with [SOLC_VERSION]
2774+
[SOLC_VERSION] [ELAPSED]
2775+
Compiler run successful!
2776+
Traces:
2777+
[..] EIP7702Script::setUp()
2778+
└─ ← [Stop]
2779+
2780+
[..] EIP7702Script::run()
2781+
├─ [0] VM::startBroadcast(<pk>)
2782+
│ └─ ← [Return]
2783+
├─ [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3
2784+
│ └─ ← [Return] 481 bytes of code
2785+
├─ [..] → new Counter@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
2786+
│ └─ ← [Return] 481 bytes of code
2787+
├─ [..] → new Counter@0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
2788+
│ └─ ← [Return] 481 bytes of code
2789+
├─ [0] VM::signAndAttachDelegation(0x5FbDB2315678afecb367f032d93F642f64180aa3, "<pk>")
2790+
│ └─ ← [Return] (0, 0xd4301eb9f82f747137a5f2c3dc3a5c2d253917cf99ecdc0d49f7bb85313c3159, 0x786d354f0bbd456f44116ddd3aa50475e989d72d8396005e5b3a12cede83fb68, 4, 0x5FbDB2315678afecb367f032d93F642f64180aa3)
2791+
├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()
2792+
│ └─ ← [Stop]
2793+
├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()
2794+
│ └─ ← [Stop]
2795+
├─ [0] VM::signAndAttachDelegation(0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512, "<pk>")
2796+
│ └─ ← [Return] (0, 0xaba9128338f7ff036a0d2ecb96d4f4376389005cd565f87aba33b312570af962, 0x69acbe0831fb8ca95338bc4b908dcfebaf7b81b0f770a12c073ceb07b89fbdf3, 7, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512)
2797+
├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)
2798+
│ └─ ← [Stop]
2799+
├─ [0] VM::signAndAttachDelegation(0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0, "<pk>")
2800+
│ └─ ← [Return] (1, 0x3a3427b66e589338ce7ea06135650708f9152e93e257b4a5ec6eb86a3e09a2ce, 0x444651c354c89fd3312aafb05948e12c0a16220827a5e467705253ab4d8aa8d3, 9, 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0)
2801+
├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)
2802+
│ └─ ← [Stop]
2803+
├─ [0] VM::stopBroadcast()
2804+
│ └─ ← [Return]
2805+
└─ ← [Stop]
2806+
2807+
2808+
Script ran successfully.
2809+
2810+
## Setting up 1 EVM.
2811+
==========================
2812+
Simulated On-chain Traces:
2813+
2814+
[..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3
2815+
└─ ← [Return] 481 bytes of code
2816+
2817+
[..] → new Counter@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
2818+
└─ ← [Return] 481 bytes of code
2819+
2820+
[..] → new Counter@0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
2821+
└─ ← [Return] 481 bytes of code
2822+
2823+
[0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()
2824+
└─ ← [Stop]
2825+
2826+
[0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()
2827+
└─ ← [Stop]
2828+
2829+
[0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)
2830+
└─ ← [Stop]
2831+
2832+
[0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)
2833+
└─ ← [Stop]
2834+
2835+
2836+
==========================
2837+
2838+
Chain 31337
2839+
2840+
[ESTIMATED_GAS_PRICE]
2841+
2842+
[ESTIMATED_TOTAL_GAS_USED]
2843+
2844+
[ESTIMATED_AMOUNT_REQUIRED]
2845+
2846+
==========================
2847+
2848+
2849+
==========================
2850+
2851+
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
2852+
2853+
[SAVED_TRANSACTIONS]
2854+
2855+
[SAVED_SENSITIVE_VALUES]
2856+
2857+
2858+
"#]]);
2859+
});

crates/forge/tests/cli/test_cmd.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3308,9 +3308,9 @@ Traces:
33083308
├─ [0] VM::label(alice: [0x328809Bc894f92807417D2dAD6b7C998c1aFdac6], "alice")
33093309
│ └─ ← [Return]
33103310
├─ [0] VM::signDelegation(0x0000000000000000000000000000000000000000, "<pk>")
3311-
│ └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000)
3311+
│ └─ ← [Return] (0, 0x38db2a0ada75402af7cd5bdb8248a1a5b4fec65fdafea4f935084f00dc2ff3c5, 0x29ce7b1c82f9ceaec21f12d690ba8fe6ecba65869caf6ab2d85d79890dc42df2, 1, 0x0000000000000000000000000000000000000000)
33123312
├─ [0] VM::signAndAttachDelegation(0x0000000000000000000000000000000000000000, "<pk>")
3313-
│ └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000)
3313+
│ └─ ← [Return] (0, 0x38db2a0ada75402af7cd5bdb8248a1a5b4fec65fdafea4f935084f00dc2ff3c5, 0x29ce7b1c82f9ceaec21f12d690ba8fe6ecba65869caf6ab2d85d79890dc42df2, 1, 0x0000000000000000000000000000000000000000)
33143314
└─ ← [Stop]
33153315
...
33163316

testdata/default/cheats/AttachDelegation.t.sol

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ contract AttachDelegationTest is DSTest {
4646
vm._expectCheatcodeRevert("vm.attachDelegation: invalid nonce");
4747
vm.attachDelegation(signedDelegation);
4848

49-
signedDelegation = vm.signDelegation(address(implementation), alice_pk, 0);
50-
vm.attachDelegation(signedDelegation);
51-
signedDelegation = vm.signDelegation(address(implementation), alice_pk, 1);
49+
signedDelegation = vm.signDelegation(address(implementation), alice_pk, 2);
5250
vm.attachDelegation(signedDelegation);
5351
}
5452

@@ -145,8 +143,7 @@ contract AttachDelegationTest is DSTest {
145143
vm._expectCheatcodeRevert("vm.signAndAttachDelegation: invalid nonce");
146144
vm.signAndAttachDelegation(address(implementation), alice_pk, 11);
147145

148-
vm.signAndAttachDelegation(address(implementation), alice_pk, 0);
149-
vm.signAndAttachDelegation(address(implementation), alice_pk, 1);
146+
vm.signAndAttachDelegation(address(implementation), alice_pk, 2);
150147
}
151148
}
152149

0 commit comments

Comments
 (0)