Skip to content

Commit 8e03315

Browse files
committed
chore: adding signatures
1 parent 701a0d4 commit 8e03315

File tree

3 files changed

+127
-8
lines changed

3 files changed

+127
-8
lines changed

src/MGDCompanyL2Sync.sol

+37-6
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,56 @@
22
pragma solidity 0.8.18;
33

44
import {MintGoldDustCompany} from "mgd-v2-contracts/MintGoldDustCompany.sol";
5+
import {MGDL2SyncEIP712, ECDSAUpgradeable} from "./MGDL2SyncEIP712.sol";
6+
import {SafeAccountChecker, ISafe} from "./utils/SafeAccountChecker.sol";
57

68
/// @title MGDCompanyL2Sync
79
/// @notice An extension to {MintGoldDustCompany} containing functions that
810
/// syncs access levels management changes with a L2.
911
/// @author Mint Gold Dust LLC
1012
/// @custom:contact klvh@mintgolddust.io
11-
contract MGDCompanyL2Sync is MintGoldDustCompany {
13+
contract MGDCompanyL2Sync is MGDL2SyncEIP712, SafeAccountChecker, MintGoldDustCompany {
14+
/// Custom errors
15+
error MGDCompanyL2Sync_setValidatorWithL2Sync_longDeadline();
16+
error MGDCompanyL2Sync_setValidatorWithL2Sync_notValidSigner();
17+
18+
bytes32 private constant _SETVALIDATOR_TYPEHASH =
19+
keccak256("SetValidator(address account,bool state,uint256 deadline)");
20+
1221
function setValidatorWithL2Sync(
13-
address _address,
14-
bool _state,
22+
address account,
23+
bool state,
24+
uint256 deadline,
1525
uint8 v,
1626
bytes32 r,
1727
bytes32 s
1828
)
1929
external
2030
onlyOwner
21-
isZeroAddress(_address)
31+
isZeroAddress(account)
2232
{
23-
isAddressValidator[_address] = _state;
24-
emit ValidatorAdded(_address, _state);
33+
if (deadline > block.timestamp + 1 days) {
34+
revert MGDCompanyL2Sync_setValidatorWithL2Sync_longDeadline();
35+
}
36+
37+
bytes32 structHash = keccak256(abi.encode(_SETVALIDATOR_TYPEHASH, account, state, deadline));
38+
bytes32 digest = _hashTypedDataV4(structHash);
39+
address signer = ECDSAUpgradeable.recover(digest, v, r, s);
40+
41+
if (_isOwnerAContract() && isAddressASafe(owner())) {
42+
if (!isAccountOwnerInSafe(signer, owner())) {
43+
revert MGDCompanyL2Sync_setValidatorWithL2Sync_notValidSigner();
44+
}
45+
} else {}
46+
47+
if (block.chainid == 0x1) {
48+
isAddressValidator[account] = state;
49+
}
50+
51+
emit ValidatorAdded(account, state);
52+
}
53+
54+
function _isOwnerAContract() internal view returns (bool) {
55+
return address(owner()).code.length > 0;
2556
}
2657
}

src/MGDL2SyncEIP712.sol

+47-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,52 @@
11
// SPDX-License-Identifier: UNLICENSED
22
pragma solidity 0.8.18;
33

4+
import {ECDSAUpgradeable} from
5+
"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
6+
47
contract MGDL2SyncEIP712 {
5-
bytes32 private constant SETVALIDATOR_TYPEHASH =
6-
keccak256("SetValidator(address _address,bool _state)");
8+
bytes32 private constant _TYPE_HASH =
9+
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
10+
11+
string public constant NAME = "MGDL2SyncEIP712";
12+
string public constant VERSION = "v0.0.1";
13+
14+
uint256 private constant _MAINNET_CHAINID = 0x1;
15+
address private constant _MGD_COMPANY_ADDRESS = 0x2f00435f003d6568933586b4A272c6c6B481e0aD;
16+
17+
bytes32 private _cachedHashedName;
18+
bytes32 private _cachedHashedVersion;
19+
20+
/**
21+
* @dev Initializes the domain separator and parameter caches.
22+
*/
23+
function __EIP712_init() internal {
24+
_cachedHashedName = keccak256(bytes(NAME));
25+
_cachedHashedVersion = keccak256(bytes(VERSION));
26+
}
27+
28+
function _EIP712NameHash() internal view returns (bytes32) {
29+
return _cachedHashedName;
30+
}
31+
32+
function _EIP712VersionHash() internal view returns (bytes32) {
33+
return _cachedHashedVersion;
34+
}
35+
36+
/**
37+
* @dev Returns the domain separator for mainnet ONLY signed messages for the {MintGoldDustCompany}
38+
* contract address that relays admin changes to any L2.
39+
*
40+
*/
41+
function _domainSeparatorV4() internal view returns (bytes32) {
42+
return keccak256(
43+
abi.encode(
44+
_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), _MAINNET_CHAINID, _MGD_COMPANY_ADDRESS
45+
)
46+
);
47+
}
48+
49+
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
50+
return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);
51+
}
752
}

src/utils/SafeAccountChecker.sol

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity 0.8.18;
3+
4+
interface ISafe {
5+
function isOwner(address account) external view returns (bool);
6+
function getStorageAt(uint256 offset, uint256 length) external view returns (bytes memory);
7+
}
8+
9+
contract SafeAccountChecker {
10+
mapping(address => bool) private _implementations;
11+
12+
constructor() {
13+
_implementations[0x41675C099F32341bf84BFc5382aF534df5C7461a] = true; // v1.4.1
14+
_implementations[0x29fcB43b46531BcA003ddC8FCB67FFE91900C762] = true; // L2 v1.4.1
15+
_implementations[0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552] = true; // v1.3.0
16+
_implementations[0x69f4D1788e39c87893C980c06EdF4b7f686e2938] = true; // v1.3.0
17+
_implementations[0x3E5c63644E683549055b9Be8653de26E0B4CD36E] = true; // L2 v1.3.0
18+
_implementations[0xfb1bffC9d739B8D520DaF37dF666da4C687191EA] = true; // L2 v1.3.0
19+
_implementations[0x6851D6fDFAfD08c0295C392436245E5bc78B0185] = true; // v1.2.0
20+
_implementations[0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F] = true; // v1.1.0
21+
_implementations[0xb6029EA3B2c51D09a50B53CA8012FeEB05bDa35A] = true; // v1.0.0
22+
}
23+
24+
function isAddressASafe(address account) public view returns (bool) {
25+
try ISafe(account).getStorageAt(0, 1) returns (bytes memory response) {
26+
address implementation = _castBytesToAddress(response);
27+
return _implementations[implementation];
28+
} catch {
29+
return false;
30+
}
31+
}
32+
33+
function isAccountOwnerInSafe(address account, address safe) public view returns (bool) {
34+
return ISafe(safe).isOwner(account);
35+
}
36+
37+
function _castBytesToAddress(bytes memory data) private pure returns (address addr) {
38+
// solhint-disable-next-line no-inline-assembly
39+
assembly {
40+
addr := mload(add(data, 32))
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)