foundry
foundry copied to clipboard
When sending EIP7702 tx , msg.sender is not equal to tx.origin
Component
Forge
Have you ensured that all of these are up to date?
- [x] Foundry
- [x] Foundryup
What version of Foundry are you on?
1.2.3-stable
What version of Foundryup are you on?
1.1.0
What command(s) is the bug in?
No response
Operating System
Linux
Describe the bug
I write a simple test for sending tx with EIP7702. when i add require(msg.sender == tx.origin, "Only EOA"); line tx's are getting reverting. It shouldnt.
when i do same test on remix ide it doenst reverting.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {Test, console} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";
contract SimpleDelegateContract {
event Executed(address indexed to, uint256 value, bytes data);
struct Call {
bytes data;
address to;
uint256 value;
}
function execute(Call[] memory calls) external payable {
for (uint256 i = 0; i < calls.length; i++) {
Call memory call = calls[i];
(bool success, bytes memory result) = call.to.call{
value: call.value
}(call.data);
require(success, string(result));
emit Executed(call.to, call.value, call.data);
}
}
receive() external payable {}
}
contract ERC20 {
address public minter;
mapping(address => uint256) private _balances;
constructor(address _minter) {
minter = _minter;
}
function mint(uint256 amount, address to) public {
_mint(to, amount);
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function _mint(address account, uint256 amount) internal {
require(msg.sender == tx.origin, "Only EOA");
require(msg.sender == minter, "ERC20: msg.sender is not minter");
require(account != address(0), "ERC20: mint to the zero address");
unchecked {
_balances[account] += amount;
}
}
}
contract SignDelegationTest is Test {
// Alice's address and private key (EOA with no initial contract code).
address payable ALICE_ADDRESS =
payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8);
uint256 constant ALICE_PK =
0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;
// Bob's address and private key (Bob will execute transactions on Alice's behalf).
address constant BOB_ADDRESS = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC;
uint256 constant BOB_PK =
0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a;
// The contract that Alice will delegate execution to.
SimpleDelegateContract public implementation;
// ERC-20 token contract for minting test tokens.
ERC20 public token;
function setUp() public {
// Deploy the delegation contract (Alice will delegate calls to this contract).
implementation = new SimpleDelegateContract();
// Deploy an ERC-20 token contract where Alice is the minter.
token = new ERC20(ALICE_ADDRESS);
}
function testSignDelegationAndThenAttachDelegation() public {
// Construct a single transaction call: Mint 100 tokens to Bob.
SimpleDelegateContract.Call[]
memory calls = new SimpleDelegateContract.Call[](1);
bytes memory data = abi.encodeCall(ERC20.mint, (100, BOB_ADDRESS));
calls[0] = SimpleDelegateContract.Call({
to: address(token),
data: data,
value: 0
});
// Alice signs a delegation allowing `implementation` to execute transactions on her behalf.
Vm.SignedDelegation memory signedDelegation = vm.signDelegation(
address(implementation),
ALICE_PK
);
// Bob attaches the signed delegation from Alice and broadcasts it.
vm.broadcast(BOB_PK);
vm.attachDelegation(signedDelegation);
// Verify that Alice's account now behaves as a smart contract.
bytes memory code = address(ALICE_ADDRESS).code;
require(code.length > 0, "no code written to Alice");
// As Bob, execute the transaction via Alice's assigned contract.
SimpleDelegateContract(ALICE_ADDRESS).execute(calls);
// Verify Bob successfully received 100 tokens.
assertEq(token.balanceOf(BOB_ADDRESS), 100);
}
function testSignAndAttachDelegation() public {
// Construct a single transaction call: Mint 100 tokens to Bob.
SimpleDelegateContract.Call[]
memory calls = new SimpleDelegateContract.Call[](1);
bytes memory data = abi.encodeCall(ERC20.mint, (100, BOB_ADDRESS));
calls[0] = SimpleDelegateContract.Call({
to: address(token),
data: data,
value: 0
});
// Alice signs and attaches the delegation in one step (eliminating the need for separate signing).
vm.signAndAttachDelegation(address(implementation), ALICE_PK);
// Verify that Alice's account now behaves as a smart contract.
bytes memory code = address(ALICE_ADDRESS).code;
require(code.length > 0, "no code written to Alice");
// As Bob, execute the transaction via Alice's assigned contract.
vm.broadcast(BOB_PK);
SimpleDelegateContract(ALICE_ADDRESS).execute(calls);
// Verify Bob successfully received 100 tokens.
assertEq(token.balanceOf(BOB_ADDRESS), 100);
}
}