Description
Component
Forge
Describe the feature you would like
Proposal
Add cheatcodes signDelegationWithNonce
and signAndAttachDelegationWithNonce
to support delegation signing with a specified nonce.
Motivation
Currently, signDelegation
and signAndAttachDelegation
consume the current nonce of the EOA and increment it when attaching the delegation to a transaction.
This approach only works when the transaction initiator is not the same EOA that signs the delegation. For example, if Alice wants to delegate execution to a contract, she must rely on Bob to send the transaction under Foundry’s current implementation—she cannot send it herself.
This issue can be demonstrated with the following Forge script:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Script, console} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
contract Impl {
uint public number;
function test() public returns (uint){
return number++;
}
}
contract TestScript is Script {
Impl impl;
// anvil test
address alice = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
uint alice_PK = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;
address bob = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;
uint bob_PK = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;
function setUp() public {
vm.startBroadcast(alice_PK);
impl = new Impl();
vm.stopBroadcast();
}
function run() public {
vm.startBroadcast(alice_PK);
vm.signAndAttachDelegation(address(impl), alice_PK);
Impl(alice).test();
console.log("alice.number", Impl(alice).number());
}
}
When run against Anvil
, the script executes successfully in a local simulation but fails when broadcasted on-chain. This is due to an incorrect nonce ordering between the transaction signing and authorization list signing. Ideally, transaction[nonce]
should be 0x1
and transaction[authorizationList][0][nonce]
should be 0x2
, but the current implementation swaps them.
{
"hash": "0xebe57d35b56870787bd1585d37f85bc45d721efa7300b1d71a540dee969dfcf0",
"transactionType": "CALL",
"contractName": null,
"contractAddress": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"function": "test()",
"arguments": [],
"transaction": {
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"gas": "0xf889",
"value": "0x0",
"input": "0xf8a8fd6d",
"nonce": "0x2",
"chainId": "0x7a69",
"authorizationList": [
{
"chainId": "0x7a69",
"address": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
"nonce": "0x1",
"yParity": "0x1",
"r": "0xb479f2c7d70a98008f27bbf4fb5e67daa0764459ed4c3337cdd906e53ac8b427",
"s": "0x34d77ad2562e633a90f2a3c9d84098b4b6e6a9e8ad04d8484fe7d8d205f41483"
}
]
},
"additionalContracts": [],
"isFixedGasLimit": false
}
The root cause is due to:
vm.signDelegation
andvm.signAndAttachDelegation
does not support signing with a specified nonce.- The attachDelegation process always occurs before the actual transaction, incrementing the nonce prematurely.
To partially resolve this, we propose adding signDelegationWithNonce
and signAndAttachDelegationWithNonce
cheatcodes to allow delegation signing with an explicit nonce.
Spec
- Add
vm.signDelegationWithNonce
cheatcode - Add
vm.signAndAttachDelegationWithNonce
cheatcode
Additional context
No response
Metadata
Metadata
Assignees
Type
Projects
Status