@perfect-abstractions/compose/token/ERC20/Approve/ERC20ApproveMod.solHelper functions for setting ERC-20 allowances and accessing ERC-20 storage
STORAGE_POSITIONbytes32keccak256("erc20"))Returns a pointer to the ERC20Storage struct.
Returns:
sERC20Storage storageSets how many of the caller's tokens _spender may move. The stored allowance becomes exactly _value, overwriting any previous allowance for that spender.
Inside a diamond, your facet runs through delegatecall, so msg.sender here is the account that called the diamond, not the diamond itself.
Parameters:
_spenderaddressaddress(0)._valueuint2560 revokes it. type(uint256).max grants an unlimited allowance that is never decremented.Returns:
-booltrue. Failures revert instead of returning false.Reverts:
ERC20InvalidSpendererror_spender is address(0).Emitted on every successful approve, including when _value is 0 or unchanged.
_owneraddressmsg.sender._spenderaddress_valueuint256Thrown by approve when _spender is the zero address.
_spenderaddressaddress(0).approve when your facet sets an allowance on behalf of whoever is calling it, for example a wrapper that approves and then performs a second action in one transaction.STORAGE_POSITION and ERC20Storage layout as the other ERC-20 modules. Do not introduce a second allowance mapping.0 first. Compose has no increaseAllowance or decreaseAllowance, so an N to M change can be front-run by a spender who uses N first.Import the module under a namespace and call it from your facet:
approve cannot set an allowance for any owner other than msg.sender. If your facet authorizes an owner some other way, such as a signature, write getStorage().allowance[_owner][_spender] directly and emit Approval yourself. ERC20PermitFacet does exactly this.
ERC20Storage lives at keccak256("erc20") inside the diamond. That is the same slot ERC20DataFacet, ERC20TransferFacet, and the other ERC-20 contracts use, so an allowance set here is what allowance() returns and what transferFrom spends.