Created
February 16, 2022 11:28
-
-
Save k06a/0ea02ecd824bd3d44c760825b62bc264 to your computer and use it in GitHub Desktop.
ERC20 extension with create2-based factory for arbitrary calls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/utils/Address.sol"; | |
import "@openzeppelin/contracts/utils/Create2.sol"; | |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | |
import "github.com/1inch/solidity-utils/contracts/libraries/AddressArray.sol"; | |
contract Caller { | |
address public immutable immutableOwner = msg.sender; | |
function makeCall(address to, bytes memory data) public { | |
require(msg.sender == immutableOwner, "Caller: access denied"); | |
(bool success,) = to.call(data); | |
require(success); | |
} | |
} | |
abstract contract ERC20WithFactory is ERC20 { | |
using AddressArray for AddressArray.Data; | |
AddressArray.Data private _callers; | |
bytes32 public immutable callerHash; | |
constructor() { | |
callerHash = keccak256(type(Caller).creationCode); | |
} | |
function approveAndCall(address to, uint256 amount, bytes memory data) public returns(bool) { | |
approve(to, amount); | |
_callers.push(msg.sender); | |
bytes32 salt = bytes32(bytes20(msg.sender)); | |
address caller = Create2.computeAddress(salt, callerHash); | |
if (caller.code.length == 0) { | |
Create2.deploy(0, salt, type(Caller).creationCode); | |
} | |
Caller(caller).makeCall(to, data); | |
_callers.pop(); | |
return true; | |
} | |
function transferFrom(address from, address to, uint256 amount) public virtual override returns(bool) { | |
address[] memory callers = _callers.get(); | |
for (uint256 i = 0; i < callers.length; i++) { | |
bytes32 salt = bytes32(bytes20(callers[i])); | |
address caller = Create2.computeAddress(salt, callerHash); | |
if (msg.sender == caller) { | |
return super.transferFrom(callers[i], to, amount); | |
} | |
} | |
return super.transferFrom(from, to, amount); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment