Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions .changeset/v4-get-tokenization-spoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aave-dao/aave-helpers-js': minor
---

Add `_getTokenizationSpoke`, the reverting counterpart of `_findTokenizationSpoke`, and make `ERC1967_ADMIN_SLOT` private
12 changes: 11 additions & 1 deletion src/dependencies/v4/Helpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract contract Helpers is Actions {
uint256 internal constant WAD = 1e18;

/// @notice ERC-1967 admin storage slot, holding the ProxyAdmin of a transparent proxy.
bytes32 internal constant ERC1967_ADMIN_SLOT =
bytes32 private constant ERC1967_ADMIN_SLOT =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

/// @notice Multiply `value` by WAD (1e18).
Expand Down Expand Up @@ -82,6 +82,16 @@ abstract contract Helpers is Actions {
return address(0);
}

/// @notice Find the TokenizationSpoke registered on `hub` for `underlying`, reverting when the
/// asset has none.
/// @dev For tests asserting over a wrapper they expect to exist; `_findTokenizationSpoke` is the
/// one to use to assert an asset has no wrapper.
function _getTokenizationSpoke(IHub hub, address underlying) internal view returns (address) {
address spoke = _findTokenizationSpoke(hub, underlying);
require(spoke != address(0), 'TOKENIZATION_SPOKE_NOT_FOUND');
return spoke;
}

/// @notice Return the owner of the ProxyAdmin governing a transparent proxy.
function _proxyAdminOwner(address proxy) internal view returns (address) {
address proxyAdmin = address(uint160(uint256(vm.load(proxy, ERC1967_ADMIN_SLOT))));
Expand Down
33 changes: 27 additions & 6 deletions tests/dependencies/v4/Helpers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import {Helpers} from 'src/dependencies/v4/Helpers.sol';
import {MockHub, MockSpoke, MockTokenizationSpoke, MockOwnable, MockERC20Symbol} from 'tests/mocks/v4/V4Mocks.sol';

contract HelpersTest is Test, Helpers {
/// @dev The slot `_proxyAdminOwner` reads, from the ERC-1967 spec: keccak256('eip1967.proxy.admin') - 1.
bytes32 internal constant ADMIN_SLOT = bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1);

MockHub internal hub;
MockERC20Symbol internal underlying;

Expand Down Expand Up @@ -53,20 +56,38 @@ contract HelpersTest is Test, Helpers {
assertEq(_findTokenizationSpoke(IHub(address(hub)), address(underlying)), newest);
}

function test_getTokenizationSpoke() public {
address tokenizationSpoke = address(new MockTokenizationSpoke(address(underlying)));
_registerSpoke(tokenizationSpoke);

assertEq(_getTokenizationSpoke(IHub(address(hub)), address(underlying)), tokenizationSpoke);
}

function test_getTokenizationSpoke_revertsWhenNoneRegistered() public {
_registerSpoke(address(new MockSpoke()));

vm.expectRevert(bytes('TOKENIZATION_SPOKE_NOT_FOUND'));
this.getTokenizationSpoke(IHub(address(hub)), address(underlying));
}

/// @dev External entrypoint, so `vm.expectRevert` applies to the reverting call frame.
function getTokenizationSpoke(
IHub targetHub,
address targetUnderlying
) external view returns (address) {
return _getTokenizationSpoke(targetHub, targetUnderlying);
}

/// @dev Stores at the spec-derived slot, so it also pins the slot `_proxyAdminOwner` reads.
function test_proxyAdminOwner() public {
address expectedOwner = makeAddr('PROXY_ADMIN_OWNER');
address proxyAdmin = address(new MockOwnable(expectedOwner));
address proxy = makeAddr('PROXY');
vm.store(proxy, ERC1967_ADMIN_SLOT, bytes32(uint256(uint160(proxyAdmin))));
vm.store(proxy, ADMIN_SLOT, bytes32(uint256(uint160(proxyAdmin))));

assertEq(_proxyAdminOwner(proxy), expectedOwner);
}

/// @dev Pins the slot against the ERC-1967 spec value: keccak256('eip1967.proxy.admin') - 1.
function test_erc1967AdminSlot() public pure {
assertEq(ERC1967_ADMIN_SLOT, bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
}

function _addAsset(address assetUnderlying) internal {
IHub.Asset memory asset;
asset.underlying = assetUnderlying;
Expand Down
Loading