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
30 changes: 0 additions & 30 deletions test/harnesses/token/ERC20/ERC20/ERC20TransferFacetHarness.sol

This file was deleted.

2 changes: 1 addition & 1 deletion test/token/ERC20/ERC20/ERC20BurnFacet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pragma solidity >=0.8.30;

import {Test} from "forge-std/Test.sol";
import {ERC20BurnFacet} from "src/token/ERC20/ERC20/ERC20BurnFacet.sol";
import {ERC20BurnFacetHarness} from "test/harnesses/token/ERC20/ERC20/ERC20BurnFacetHarness.sol";
import {ERC20BurnFacetHarness} from "./harnesses/ERC20BurnFacetHarness.sol";

contract ERC20BurnFacetTest is Test {
ERC20BurnFacetHarness public token;
Expand Down
2 changes: 1 addition & 1 deletion test/token/ERC20/ERC20/ERC20PermitFacet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pragma solidity >=0.8.30;

import {Test} from "forge-std/Test.sol";
import {ERC20PermitFacet} from "src/token/ERC20/ERC20Permit/ERC20PermitFacet.sol";
import {ERC20PermitFacetHarness} from "test/harnesses/token/ERC20/ERC20/ERC20PermitFacetHarness.sol";
import {ERC20PermitFacetHarness} from "./harnesses/ERC20PermitFacetHarness.sol";

contract ERC20BurnFacetTest is Test {
ERC20PermitFacetHarness public token;
Expand Down
79 changes: 79 additions & 0 deletions test/utils/storage/ERC20StorageUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.30;

/* Compose
* https://compose.diamonds
*/

import {Vm} from "forge-std/Vm.sol";

/**
* @title ERC20StorageUtils
* @notice Storage manipulation utilities for ERC20 token testing
* @dev Uses vm.load and vm.store to directly manipulate storage slots
*/
library ERC20StorageUtils {
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

bytes32 internal constant ERC20_TRANSFER_STORAGE_POSITION = keccak256("compose.erc20.transfer");

/*//////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////*/

/*
* @notice ERC-20 Transfer storage layout (ERC-8042 standard)
* @custom:storage-location erc8042:compose.erc20.transfer
*
* Slot 0: mapping(address owner => uint256 balance) balanceOf
* Slot 1: uint256 totalSupply
* Slot 2: mapping(address owner => mapping(address spender => uint256)) allowance
*/

function balanceOf(address target, address owner) internal view returns (uint256) {
bytes32 slot = keccak256(abi.encode(owner, uint256(ERC20_TRANSFER_STORAGE_POSITION)));
return uint256(vm.load(target, slot));
}

function totalSupply(address target) internal view returns (uint256) {
bytes32 slot = bytes32(uint256(ERC20_TRANSFER_STORAGE_POSITION) + 1);
return uint256(vm.load(target, slot));
}

function allowance(address target, address owner, address spender) internal view returns (uint256) {
bytes32 ownerSlot = keccak256(abi.encode(owner, uint256(ERC20_TRANSFER_STORAGE_POSITION) + 2));
bytes32 slot = keccak256(abi.encode(spender, ownerSlot));
return uint256(vm.load(target, slot));
}

/*//////////////////////////////////////////////////////////////
SETTERS
//////////////////////////////////////////////////////////////*/

function setBalance(address target, address owner, uint256 balance) internal {
bytes32 slot = keccak256(abi.encode(owner, uint256(ERC20_TRANSFER_STORAGE_POSITION)));
vm.store(target, slot, bytes32(balance));
}

function setTotalSupply(address target, uint256 supply) internal {
bytes32 slot = bytes32(uint256(ERC20_TRANSFER_STORAGE_POSITION) + 1);
vm.store(target, slot, bytes32(supply));
}

function setAllowance(address target, address owner, address spender, uint256 amount) internal {
bytes32 ownerSlot = keccak256(abi.encode(owner, uint256(ERC20_TRANSFER_STORAGE_POSITION) + 2));
bytes32 slot = keccak256(abi.encode(spender, ownerSlot));
vm.store(target, slot, bytes32(amount));
}

/**
* @notice Mint tokens by updating balance and totalSupply
*/
function mint(address target, address to, uint256 amount) internal {
uint256 currentBalance = balanceOf(target, to);
uint256 currentSupply = totalSupply(target);

setBalance(target, to, currentBalance + amount);
setTotalSupply(target, currentSupply + amount);
}
}