Skip to content

Commit ba6ab36

Browse files
August 2025 Audit fixes (#137)
1 parent b498253 commit ba6ab36

File tree

11 files changed

+87
-14
lines changed

11 files changed

+87
-14
lines changed

foundry.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
src = "src"
33
out = "out"
44
libs = ["lib"]
5+
solc_version = "0.8.26"
56
remappings = [
67
"@ensdomains/buffer/=lib/buffer",
78
"solady/=lib/solady/src/",

src/L2/resolver/AddrResolver.sol

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,21 @@ abstract contract AddrResolver is IAddrResolver, IAddressResolver, ResolverBase
2424
// keccak256(abi.encode(uint256(keccak256("addr.resolver.storage")) - 1)) & ~bytes32(uint256(0xff));
2525
bytes32 constant ADDR_RESOLVER_STORAGE = 0x1871a91a9a944f867849820431bb11c2d1625edae573523bceb5b38b8b8a7500;
2626

27+
/// @notice Ethereum chain id.
28+
uint32 constant CHAIN_ID_ETH = 1;
29+
2730
/// @notice Ethereum mainnet network-as-cointype.
2831
uint256 private constant COIN_TYPE_ETH = 60;
2932

33+
/// @notice EVM default cointype per ENSIP-19.
34+
uint256 constant COIN_TYPE_DEFAULT = 1 << 31; // 0x8000_0000
35+
3036
/// @notice Thrown when an invalid bytes length is detected.
3137
error InvalidBytesLength();
3238

39+
/// @notice Thrown when setting an invalid EVM address for a valid EVM cointype.
40+
error InvalidEVMAddress(bytes a);
41+
3342
/// @notice Sets the address associated with an ENS node.
3443
///
3544
/// @dev May only be called by the owner of that node in the ENS registry.
@@ -46,9 +55,12 @@ abstract contract AddrResolver is IAddrResolver, IAddressResolver, ResolverBase
4655
/// @param coinType The coinType for this address.
4756
/// @param a The network-agnostic bytes of the address.
4857
function setAddr(bytes32 node, uint256 coinType, bytes memory a) public virtual authorized(node) {
58+
if (a.length != 0 && a.length != 20 && isEVMCoinType(coinType)) {
59+
revert InvalidEVMAddress(a);
60+
}
4961
emit AddressChanged(node, coinType, a);
5062
if (coinType == COIN_TYPE_ETH) {
51-
emit AddrChanged(node, bytesToAddress(a));
63+
emit AddrChanged(node, address(bytes20(a)));
5264
}
5365
_getAddrResolverStorage().versionable_addresses[_getResolverBaseStorage().recordVersions[node]][node][coinType]
5466
= a;
@@ -71,14 +83,20 @@ abstract contract AddrResolver is IAddrResolver, IAddressResolver, ResolverBase
7183

7284
/// @notice Returns the address of the `node` for a specified `coinType`.
7385
///
74-
/// @dev Complies with ENSIP-9 and ENSIP-11.
86+
/// @dev Complies with ENSIP-9, ENSIP-11 and ENSIP-19.
87+
/// Will return `default` address if there is no address set for a specific EVM cointype.
7588
///
7689
/// @param node The ENS node to update.
7790
/// @param coinType The coinType to fetch.
7891
///
79-
/// @return The address of the specified `node` for the specified `coinType`.
80-
function addr(bytes32 node, uint256 coinType) public view virtual override returns (bytes memory) {
81-
return _getAddrResolverStorage().versionable_addresses[_getResolverBaseStorage().recordVersions[node]][node][coinType];
92+
/// @return addressBytes The address of the specified `node` for the specified `coinType`.
93+
function addr(bytes32 node, uint256 coinType) public view virtual override returns (bytes memory addressBytes) {
94+
mapping(uint256 coinType => bytes addr) storage addrs =
95+
_getAddrResolverStorage().versionable_addresses[_getResolverBaseStorage().recordVersions[node]][node];
96+
addressBytes = addrs[coinType];
97+
if (addressBytes.length == 0 && chainFromCoinType(coinType) > 0) {
98+
addressBytes = addrs[COIN_TYPE_DEFAULT];
99+
}
82100
}
83101

84102
/// @notice ERC-165 compliance.
@@ -103,6 +121,28 @@ abstract contract AddrResolver is IAddrResolver, IAddressResolver, ResolverBase
103121
}
104122
}
105123

124+
/// @notice Fetch the uint32 coinType from an EVM coinType.
125+
///
126+
/// @dev Extract Chain ID from `coinType`.
127+
///
128+
/// @param coinType The coin type.
129+
///
130+
/// @return The Chain ID or 0 if non-EVM Chain.
131+
function chainFromCoinType(uint256 coinType) internal pure returns (uint32) {
132+
if (coinType == COIN_TYPE_ETH) return CHAIN_ID_ETH;
133+
coinType ^= COIN_TYPE_DEFAULT;
134+
return uint32(coinType < COIN_TYPE_DEFAULT ? coinType : 0);
135+
}
136+
137+
/// @notice Determine if `coinType` is for an EVM address.
138+
///
139+
/// @param coinType The network as a coinType.
140+
///
141+
/// @return `true` if coinType represents an EVM address, else `false`.
142+
function isEVMCoinType(uint256 coinType) internal pure returns (bool) {
143+
return coinType == COIN_TYPE_DEFAULT || chainFromCoinType(coinType) > 0;
144+
}
145+
106146
/// @notice EIP-7201 storage pointer fetch helper.
107147
function _getAddrResolverStorage() internal pure returns (AddrResolverStorage storage $) {
108148
assembly {

src/lib/SignatureVerifier.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {ECDSA} from "solady/utils/ECDSA.sol";
55

test/L1Resolver/AdminMethods.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {Test, console} from "forge-std/Test.sol";
55
import {L1ResolverTestBase} from "./L1ResolverBase.t.sol";

test/L1Resolver/Fallback.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {Test, console} from "forge-std/Test.sol";
55
import {L1ResolverTestBase} from "./L1ResolverBase.t.sol";

test/L1Resolver/MakeSignatureHash.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {Test, console} from "forge-std/Test.sol";
55
import {L1ResolverTestBase} from "./L1ResolverBase.t.sol";

test/L1Resolver/Resolve.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {Test, console} from "forge-std/Test.sol";
55
import {L1ResolverTestBase} from "./L1ResolverBase.t.sol";

test/L1Resolver/ResolveWithProof.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {Test, console} from "forge-std/Test.sol";
55
import {L1ResolverTestBase} from "./L1ResolverBase.t.sol";

test/L1Resolver/SupportsInterface.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.23;
2+
pragma solidity ^0.8.23;
33

44
import {Test, console} from "forge-std/Test.sol";
55
import {L1ResolverTestBase} from "./L1ResolverBase.t.sol";

test/UpgradeableL2Resolver/SetAddr.t.sol

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ contract SetAddr is UpgradeableL2ResolverBase {
99
uint256 BTC_COINTYPE = 0;
1010
uint256 ETH_COINTYPE = 60;
1111
uint256 BASE_COINTYPE = 2147492101;
12+
uint256 COIN_TYPE_DEFAULT = 1 << 31; // 0x8000_0000
1213

1314
function test_reverts_forUnauthorizedUser() public {
1415
vm.expectRevert(abi.encodeWithSelector(ResolverBase.NotAuthorized.selector, node, notUser));
@@ -19,7 +20,14 @@ contract SetAddr is UpgradeableL2ResolverBase {
1920
function test_reverts_for_invalidAddress() public {
2021
vm.prank(user);
2122
vm.expectRevert();
22-
resolver.setAddr(node, 60, "");
23+
resolver.setAddr(node, 60, "badadd");
24+
}
25+
26+
function test_reverts_whenInvalidEVMAddress() public {
27+
bytes memory badAddr = bytes("1234");
28+
vm.expectRevert(abi.encodeWithSelector(AddrResolver.InvalidEVMAddress.selector, badAddr));
29+
vm.prank(user);
30+
resolver.setAddr(node, BASE_COINTYPE, badAddr);
2331
}
2432

2533
function test_setsAnETHAddress_byDefault(address a) public {
@@ -36,12 +44,36 @@ contract SetAddr is UpgradeableL2ResolverBase {
3644
assertEq(bytesToAddress(resolver.addr(node, ETH_COINTYPE)), a);
3745
}
3846

47+
function test_letsAUserSetZeroAddress_forEthCointype() public {
48+
vm.prank(user);
49+
resolver.setAddr(node, address(0));
50+
assertEq(resolver.addr(node), address(0));
51+
}
52+
53+
function test_letsAUserSetZeroAddress_forEthCointypeWithExplicitCointype() public {
54+
vm.prank(user);
55+
resolver.setAddr(node, ETH_COINTYPE, bytes(""));
56+
assertEq(resolver.addr(node), address(0));
57+
}
58+
3959
function test_setsABaseAddress(address a) public {
4060
vm.prank(user);
4161
resolver.setAddr(node, BASE_COINTYPE, addressToBytes(a));
4262
assertEq(bytesToAddress(resolver.addr(node, BASE_COINTYPE)), a);
4363
}
4464

65+
function test_setsADefaultAddress(address a) public {
66+
vm.prank(user);
67+
resolver.setAddr(node, COIN_TYPE_DEFAULT, addressToBytes(a));
68+
assertEq(bytesToAddress(resolver.addr(node, COIN_TYPE_DEFAULT)), a);
69+
}
70+
71+
function test_fetchesDefaultForBaseCointype(address a) public {
72+
vm.prank(user);
73+
resolver.setAddr(node, COIN_TYPE_DEFAULT, addressToBytes(a));
74+
assertEq(bytesToAddress(resolver.addr(node, BASE_COINTYPE)), a);
75+
}
76+
4577
function test_setsABtcAddress() public {
4678
bytes memory satoshi = hex"76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac";
4779
vm.prank(user);

0 commit comments

Comments
 (0)