Skip to content

Commit facca7c

Browse files
authored
Merge pull request #20 from zerodevapp/fix/callPolicy-custom-bytes-storage
done
2 parents cfb72bb + d4855f5 commit facca7c

File tree

2 files changed

+67
-6
lines changed

2 files changed

+67
-6
lines changed

policies/call-policy/src/CallPolicy.sol

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,39 @@ contract CallPolicy is PolicyBase {
4242

4343
mapping(address => uint256) public usedIds;
4444
mapping(bytes32 id => mapping(address => Status)) public status;
45-
mapping(bytes32 id => mapping(bytes32 permissionHash => mapping(address => bytes))) public encodedPermissions;
45+
//mapping(bytes32 id => mapping(bytes32 permissionHash => mapping(address => bytes))) public encodedPermissions;
4646

4747
function isInitialized(address wallet) external view override returns (bool) {
4848
return usedIds[wallet] > 0;
4949
}
5050

51+
function setPermission(bytes32 _id, bytes32 _permissionHash, address _owner, bytes memory _permission) internal {
52+
bytes32 slot = keccak256(bytes.concat(bytes32(uint256(uint160(_owner))), keccak256(bytes.concat(_id,_permissionHash))));
53+
54+
uint256 length = _permission.length;
55+
assembly {
56+
// store length on first slot, as usual
57+
sstore(slot, length)
58+
for { let cursor := 0x20 } lt(cursor, add(length, 0x20)) { cursor := add(cursor, 0x20) } {
59+
sstore(add(slot, div(cursor, 0x20)), mload(add(_permission, cursor))) // slot + cursor/32
60+
}
61+
}
62+
}
63+
64+
function encodedPermissions(bytes32 _id, bytes32 _permissionHash, address _owner) public view returns(bytes memory encoded) {
65+
bytes32 slot = keccak256(bytes.concat(bytes32(uint256(uint160(_owner))), keccak256(bytes.concat(_id,_permissionHash))));
66+
uint256 length;
67+
assembly {
68+
encoded := mload(0x40)
69+
length := sload(slot)
70+
mstore(encoded, length)
71+
for { let cursor := 0x20 } lt(cursor, add(length, 0x20)) { cursor := add(cursor, 0x20) } {
72+
mstore(add(encoded, cursor), sload(add(slot, div(cursor, 0x20))))
73+
}
74+
mstore(0x40, add(encoded, add(length, 0x20)))
75+
}
76+
}
77+
5178
function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp)
5279
external
5380
payable
@@ -100,13 +127,13 @@ contract CallPolicy is PolicyBase {
100127
) internal returns (bool) {
101128
bytes4 _data = data.length == 0 ? bytes4(0x0) : bytes4(data[0:4]);
102129
bytes32 permissionHash = keccak256(abi.encodePacked(callType, target, _data));
103-
bytes memory encodedPermission = encodedPermissions[id][permissionHash][wallet];
130+
bytes memory encodedPermission = encodedPermissions(id, permissionHash, wallet);
104131

105132
// try to find the permission with zero address which means ANY target address
106133
// e.g. allow to call `approve` function of `ANY` ERC20 token contracts
107134
if (encodedPermission.length == 0) {
108135
bytes32 permissionHashWithZeroAddress = keccak256(abi.encodePacked(callType, address(0), _data));
109-
encodedPermission = encodedPermissions[id][permissionHashWithZeroAddress][wallet];
136+
encodedPermission = encodedPermissions(id,permissionHashWithZeroAddress,wallet);
110137
}
111138

112139
// if still no permission found, then the call is not allowed
@@ -175,7 +202,7 @@ contract CallPolicy is PolicyBase {
175202
// check if the permissionHash is unique
176203
bytes32 permissionHash =
177204
keccak256(abi.encodePacked(permissions[i].callType, permissions[i].target, permissions[i].selector));
178-
require(encodedPermissions[id][permissionHash][msg.sender].length == 0, "duplicate permissionHash");
205+
require(encodedPermissions(id, permissionHash, msg.sender).length == 0, "duplicate permissionHash");
179206

180207
// check if the params length is correct
181208
for (uint256 j = 0; j < permissions[i].rules.length; j++) {
@@ -184,8 +211,10 @@ contract CallPolicy is PolicyBase {
184211
}
185212
}
186213

187-
encodedPermissions[id][permissionHash][msg.sender] =
188-
abi.encode(permissions[i].valueLimit, permissions[i].rules);
214+
setPermission(
215+
id,permissionHash,msg.sender,
216+
abi.encode(permissions[i].valueLimit, permissions[i].rules)
217+
);
189218
}
190219
status[id][msg.sender] = Status.Live;
191220
usedIds[msg.sender]++;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
pragma solidity ^0.8.0;
2+
3+
import {Test} from "forge-std/Test.sol";
4+
import "forge-std/console.sol";
5+
6+
import "src/CallPolicy.sol";
7+
8+
contract MockCallPolicy is CallPolicy {
9+
10+
function sudoSetPolicy(bytes32 _id, bytes32 _permissionHash, address _owner, bytes memory _permission) external {
11+
setPermission(_id, _permissionHash, _owner, _permission);
12+
}
13+
}
14+
15+
contract TestEncoding is Test {
16+
17+
MockCallPolicy mock;
18+
19+
function setUp() external {
20+
mock = new MockCallPolicy();
21+
}
22+
23+
function testEncoding(bytes memory tb) external {
24+
address owner = makeAddr("Owner");
25+
26+
mock.sudoSetPolicy(bytes32(uint256(0x12345678)), bytes32(uint256(0x987654321)), owner, tb);
27+
28+
bytes memory result = mock.encodedPermissions(bytes32(uint256(0x12345678)), bytes32(uint256(0x987654321)), owner);
29+
30+
assertEq(keccak256(result), keccak256(tb));
31+
}
32+
}

0 commit comments

Comments
 (0)