Skip to content
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

Added hardfork support + deterministic state to reference implementation #31

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/examples/simple/ERC6551Account.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface IERC6551Account {
view
returns (uint256 chainId, address tokenContract, uint256 tokenId);

function state() external view returns (uint256);
function state() external view returns (bytes32);

function isValidSigner(address signer, bytes calldata context)
external
Expand All @@ -30,7 +30,9 @@ interface IERC6551Executable {
}

contract ERC6551Account is IERC165, IERC1271, IERC6551Account, IERC6551Executable {
uint256 public state;
uint256 immutable deploymentChainId = block.chainid;

bytes32 public state;

receive() external payable {}

Expand All @@ -43,7 +45,7 @@ contract ERC6551Account is IERC165, IERC1271, IERC6551Account, IERC6551Executabl
require(_isValidSigner(msg.sender), "Invalid signer");
require(operation == 0, "Only call operations are supported");

++state;
state = keccak256(abi.encode(state, msg.data));

bool success;
(success, result) = to.call{value: value}(data);
Expand Down Expand Up @@ -96,7 +98,7 @@ contract ERC6551Account is IERC165, IERC1271, IERC6551Account, IERC6551Executabl

function owner() public view virtual returns (address) {
(uint256 chainId, address tokenContract, uint256 tokenId) = token();
if (chainId != block.chainid) return address(0);
if (chainId != block.chainid && block.chainid == deploymentChainId) return address(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be chainId != block.chainid && chainid != deploymentChainId?


return IERC721(tokenContract).ownerOf(tokenId);
}
Expand Down
6 changes: 3 additions & 3 deletions src/examples/upgradeable/ERC6551AccountUpgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ contract ERC6551AccountUpgradeable is
bytes32 internal constant _IMPLEMENTATION_SLOT =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

uint256 public state;
bytes32 public state;

receive() external payable {}

Expand All @@ -51,7 +51,7 @@ contract ERC6551AccountUpgradeable is
{
require(_isValidSigner(msg.sender), "Caller is not owner");
require(_operation == 0, "Only call operations are supported");
++state;
state = keccak256(abi.encode(state, msg.data));
bool success;
// solhint-disable-next-line avoid-low-level-calls
(success, _result) = _target.call{value: _value}(_data);
Expand All @@ -65,7 +65,7 @@ contract ERC6551AccountUpgradeable is
function upgrade(address implementation_) external virtual {
require(_isValidSigner(msg.sender), "Caller is not owner");
require(implementation_ != address(0), "Invalid implementation address");
++state;
state = keccak256(abi.encode(state, msg.data));
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = implementation_;
}

Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IERC6551Account.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ interface IERC6551Account {
*
* @return The current account state
*/
function state() external view returns (uint256);
function state() external view returns (bytes32);

/**
* @dev Returns a magic value indicating whether a given signer is authorized to act on behalf
Expand Down
11 changes: 10 additions & 1 deletion test/examples/simple/ERC6551Account.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,20 @@ contract AccountTest is Test {

vm.deal(account, 1 ether);

bytes32 expectedState = keccak256(
abi.encode(
bytes32(0),
abi.encodeWithSignature(
"execute(address,uint256,bytes,uint8)", vm.addr(2), 0.5 ether, "", 0
)
)
);

vm.prank(vm.addr(1));
executableAccountInstance.execute(payable(vm.addr(2)), 0.5 ether, "", 0);

assertEq(account.balance, 0.5 ether);
assertEq(vm.addr(2).balance, 0.5 ether);
assertEq(accountInstance.state(), 1);
assertEq(accountInstance.state(), expectedState);
}
}
14 changes: 11 additions & 3 deletions test/examples/upgradeable/ERC6551AccountUpgradeable.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ contract AccountProxyTest is Test {
IERC6551Account accountInstance = IERC6551Account(payable(account));
IERC6551Executable executableAccountInstance = IERC6551Executable(account);

bytes32 expectedState = keccak256(
abi.encode(
bytes32(0),
abi.encodeWithSignature(
"execute(address,uint256,bytes,uint8)", vm.addr(2), 0.5 ether, "", 0
)
)
);

vm.prank(vm.addr(3));
vm.expectRevert("Caller is not owner");
executableAccountInstance.execute(payable(vm.addr(2)), 0.5 ether, "", 0);
Expand All @@ -103,7 +112,7 @@ contract AccountProxyTest is Test {

assertEq(account.balance, 0.5 ether);
assertEq(vm.addr(2).balance, 0.5 ether);
assertEq(accountInstance.state(), 1);
assertEq(accountInstance.state(), expectedState);
}

function testCannotOwnSelf() public {
Expand Down Expand Up @@ -287,14 +296,13 @@ contract AccountProxyTest is Test {
assertEq(address(uint160(uint256(rawImplementation))), address(0));

// Send ETH to initialize.
(bool success, ) = payable(account).call{value: 0}("");
(bool success,) = payable(account).call{value: 0}("");
assertTrue(success);

rawImplementation =
vm.load(account, 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);

assertEq(address(uint160(uint256(rawImplementation))), address(implementation));

}

function testERC721Receive() public {
Expand Down
2 changes: 1 addition & 1 deletion test/mocks/MockERC6551Account.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "../../src/interfaces/IERC6551Executable.sol";
import "../../src/lib/ERC6551AccountLib.sol";

contract MockERC6551Account is IERC165, IERC6551Account, IERC6551Executable {
uint256 public state;
bytes32 public state;
bool private _initialized;

receive() external payable {}
Expand Down