Transaction Hash:
Block:
16869301 at Mar-20-2023 01:52:11 PM +UTC
Transaction Fee:
0.01399955311313988 ETH
$29.04
Gas Used:
560,505 Gas / 24.976678376 Gwei
Emitted Events:
| 119 |
0x7a5ce41c3511e4838f5dcefcf5533950ee1a8315.0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0( 0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0, 000000000000000000000000d0a7a69950f30de89906e79a713b97e9668433a6, 0000000000000000000000000000000000000000000000000186fb97ba37ac00, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 120 |
Forwarder.ForwarderDeposited( from=[Receiver] 0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43, value=110051870000000000, data=0x )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x075F63f0...1357f6dE4 | 0.000345235968176511 Eth | 0.00167145125 Eth | 0.001326215281823489 | ||
| 0x14Ad241B...d9e798502 | 0.000145352359062143 Eth | 0.001706033 Eth | 0.001560680640937857 | ||
| 0x158B74D3...Ac24f27c7 | 0.000418916209391063 Eth | 0.001706033 Eth | 0.001287116790608937 | ||
| 0x16fb2850...f4Ca8494d | 0.000331998736066038 Eth | 0.001706033 Eth | 0.001374034263933962 | ||
| 0x1fBE6A01...4b87c4f02 | 0 Eth | 0.05341972 Eth | 0.05341972 | ||
| 0x22d60D8C...0E7126f18 | 0.02102539 Eth | 0.04132561 Eth | 0.02030022 | ||
| 0x25734B96...cA99d657b | 0.000229167256479 Eth | 0.009304427256479 Eth | 0.00907526 | ||
| 0x2c2E4C79...74d89D339 | 0.005458202672470252 Eth | 0.144994772672470252 Eth | 0.13953657 | ||
| 0x31a81780...8DcC6f30c | 0.000857525701222347 Eth | 0.013553655701222347 Eth | 0.01269613 | ||
| 0x40BBbcFD...21521E7fe | (BingX Dep: 0x40BBbcFDfC6932600D9258fE6ff422821521E7fe) | 0.062617296025753148 Eth | 0.070723156025753148 Eth | 0.00810586 | |
| 0x464F939e...D605D9B2E | 0.000374497220903207 Eth | 0.00167145125 Eth | 0.001296954029096793 | ||
| 0x46F2874a...6eF6f60D9 | 0.000308379185935621 Eth | 0.001706033 Eth | 0.001397653814064379 | ||
| 0x55eb6C70...99f14379C | 0.16215529 Eth | 0.19595747 Eth | 0.03380218 | ||
| 0x5a10825F...B9c793dC2 | 0.000388449434450055 Eth | 0.00167188625 Eth | 0.001283436815549945 | ||
| 0x62b1eF13...b52F93e1c | 0.000382334089710181 Eth | 0.001706033 Eth | 0.001323698910289819 | ||
| 0x6351B685...2CBfdf59C | 0.000515996410539526 Eth | 0.057927176410539526 Eth | 0.05741118 | ||
| 0x647c1861...ae4167AAa | 0.002701566886400068 Eth | 0.015152366886400068 Eth | 0.0124508 | ||
| 0x688B1495...B260f7838 | 0.01038681241759347 Eth | 0.01517146241759347 Eth | 0.00478465 | ||
| 0x692B8E87...95ef66d97 | 0.000106705858731583 Eth | 0.001706033 Eth | 0.001599327141268417 | ||
| 0x6a72d034...AC6C6CF24 | 0.006667748922319196 Eth | 0.011210838922319196 Eth | 0.00454309 | ||
| 0x6aDe09f6...62925C56C | 0.00129627 Eth | 0.00695936 Eth | 0.00566309 | ||
| 0x6e928DCA...06f8FB5B8 | 0.000366877567963083 Eth | 0.001706033 Eth | 0.001339155432036917 | ||
| 0x70A8bE72...270f8be51 | 0.00026802402077449 Eth | 0.001706033 Eth | 0.00143800897922551 | ||
| 0x72F405ed...8271b4726 | 0.000364692171351451 Eth | 0.00167145125 Eth | 0.001306759078648549 | ||
| 0x73cEF42E...264197E8C | 0 Eth | 0.01459923 Eth | 0.01459923 | ||
| 0x74047B07...e139357B9 | 0.002399725925838294 Eth | 0.152399725925838294 Eth | 0.15 | ||
| 0x7830c87C...31FA86F43 | (Coinbase: Deposit) |
20.153755963144451713 Eth
Nonce: 648020
|
20.139756410031311833 Eth
Nonce: 648021
| 0.01399955311313988 | |
| 0x78AFC1D5...4D1b1e0a2 | 0.000436041067963083 Eth | 0.001706033 Eth | 0.001269991932036917 | ||
| 0x7a5ce41c...0eE1A8315 | 40.471579325790579012 Eth | 40.581631195790579012 Eth | 0.11005187 | ||
| 0x7Ef6E570...364B12602 | 0.003270729776726653 Eth | 0.023629839776726653 Eth | 0.02035911 | ||
| 0x85da7467...84D1b8dCE | 0.006267034803084252 Eth | 0.012341594803084252 Eth | 0.00607456 | ||
| 0x867731e6...92D14909c | 0.000278530991104551 Eth | 0.00167188625 Eth | 0.001393355258895449 | ||
| 0x8951A715...3D2005307 | 0.00041436722234356 Eth | 0.001706033 Eth | 0.00129166577765644 | ||
| 0x9954f7c2...917d3f108 | 0.000356168836317 Eth | 0.00188402125 Eth | 0.001527852413683 | ||
| 0x9b5AdEba...24A0FfF54 | 0.015464346642909796 Eth | 0.108457576642909796 Eth | 0.09299323 | ||
| 0xa138e6Dd...35E2bE582 | 0.000439503042692502 Eth | 0.001706033 Eth | 0.001266529957307498 | ||
| 0xa2D5572C...3547A78eF | 0.000089027419467342 Eth | 0.026095757419467342 Eth | 0.02600673 | ||
| 0xa94D6AEC...2fc072d4a | 0.000402441785965517 Eth | 0.00167188625 Eth | 0.001269444464034483 | ||
| 0xA9D1e08C...FB81d3E43 | (Coinbase 10) | 2,174.331659163498009147 Eth | 2,173.37262283030847138 Eth | 0.959036333189537767 | |
| 0xB04D264A...4d09F3cf9 | 0.026836992956962528 Eth | 0.047765692956962528 Eth | 0.0209287 | ||
| 0xb7483F2e...dea7c1414 | 0.002949397539035904 Eth | 0.029335227539035904 Eth | 0.02638583 | ||
| 0xb79AD82A...9B1E7823E | 0.14494686 Eth | 0.18197971 Eth | 0.03703285 | ||
| 0xb831579E...8E87eD605 | 0.0005004943 Eth | 0.0133327543 Eth | 0.01283226 | ||
| 0xd9545604...f884aF739 | 0.03011447 Eth | 0.06047711 Eth | 0.03036264 | ||
| 0xd9993E61...e94FcdCA0 | 0.000360223239859527 Eth | 0.00167145125 Eth | 0.001311228010140473 | ||
| 0xd9eD50a2...7F8c8DC81 | 0.000447715806366692 Eth | 0.001706033 Eth | 0.001258317193633308 | ||
|
0xDAFEA492...692c98Bc5
Miner
| (Flashbots: Builder) | 1.173765338562209121 Eth | 1.174325843562209121 Eth | 0.000560505 | |
| 0xe0B62209...7C18857B4 | 0.000328417221192017 Eth | 0.00167188625 Eth | 0.001343469028807983 | ||
| 0xE4761536...1058adF5c | 0.03862283 Eth | 0.05410867 Eth | 0.01548584 | ||
| 0xeb930447...5E789E560 | 0.000350387364418715 Eth | 0.001705589 Eth | 0.001355201635581285 | ||
| 0xF0Bd783C...c300629a0 | 0.000225335546703442 Eth | 0.00167188625 Eth | 0.001446550703296558 | ||
| 0xFe79F3E2...ed9e6c928 | 0.000189851084575658 Eth | 0.00167188625 Eth | 0.001482035165424342 | ||
| 0xfF15C2b3...36a7FF063 | 0.000285835778444543 Eth | 0.00167188625 Eth | 0.001386050471555457 |
Execution Trace
Coinbase 10.1a1da075( )
- ETH 0.001258317193633308
0xd9ed50a2b7401cf4cc2e06b7a85fa297f8c8dc81.CALL( ) - ETH 0.001266529957307498
0xa138e6dd962a9086fa855c6e2b7b5aa35e2be582.CALL( ) - ETH 0.001269444464034483
0xa94d6aec1f08625dfb8c0ede88a871f2fc072d4a.CALL( ) - ETH 0.001269991932036917
0x78afc1d58eb5a6a6ed7ac7ea95c44f34d1b1e0a2.CALL( ) - ETH 0.001283436815549945
0x5a10825f70cbb14d5ab73a16e0ff69db9c793dc2.CALL( ) - ETH 0.001287116790608937
0x158b74d3435e2ba28eda51fa27a572dac24f27c7.CALL( ) - ETH 0.00129166577765644
0x8951a7158d5f7f417a77128be241aa43d2005307.CALL( ) - ETH 0.001296954029096793
0x464f939e7dbf927873f6c0e03bc0576d605d9b2e.CALL( ) - ETH 0.001306759078648549
0x72f405ed763b277048b129abb7fdc058271b4726.CALL( ) - ETH 0.001311228010140473
0xd9993e61edc96f9610d171d1ed27d31e94fcdca0.CALL( ) - ETH 0.001323698910289819
0x62b1ef138eb00ef14b880ef89a28517b52f93e1c.CALL( ) - ETH 0.001326215281823489
0x075f63f07d0539409a8c6b13f0f28d51357f6de4.CALL( ) - ETH 0.001339155432036917
0x6e928dcace4cbe0cf84f92013d6fc4806f8fb5b8.CALL( ) - ETH 0.001343469028807983
0xe0b6220980af7ea3ffcd5d83c2fff457c18857b4.CALL( ) - ETH 0.001355201635581285
0xeb9304472a3c23ef98ebc925d5376615e789e560.CALL( ) - ETH 0.001374034263933962
0x16fb28504df51116a0db4af5132671ef4ca8494d.CALL( ) - ETH 0.001386050471555457
0xff15c2b36d45b5e34937023ec96a19136a7ff063.CALL( ) - ETH 0.001393355258895449
0x867731e64400f14584f75e5d216fc5d92d14909c.CALL( ) - ETH 0.001397653814064379
0x46f2874a1dfc02ba97efd194e51bfeb6ef6f60d9.CALL( ) - ETH 0.00143800897922551
0x70a8be7296e318c84ddaaa0854a8de9270f8be51.CALL( ) - ETH 0.001446550703296558
0xf0bd783c667b9d03e680fcc552501bec300629a0.CALL( ) - ETH 0.001482035165424342
0xfe79f3e21467a0a1082b1c15d13a9f7ed9e6c928.CALL( ) - ETH 0.001527852413683
0x9954f7c26e0288892e6bae9ef9373ae917d3f108.CALL( ) - ETH 0.001560680640937857
0x14ad241ba1937a43a904ccf0a4ffd54d9e798502.CALL( ) - ETH 0.001599327141268417
0x692b8e8708e1ee0692da34068c84d2795ef66d97.CALL( ) - ETH 0.00454309
0x6a72d03494cf3cde0d1b84d9614cc5bac6c6cf24.CALL( ) - ETH 0.00478465
0x688b1495959a57aa34280544ba31c59b260f7838.CALL( ) - ETH 0.00566309
0x6ade09f629073c0af7032f8c3f1168662925c56c.CALL( ) - ETH 0.00607456
0x85da746704d27bf483303746f9e31ac84d1b8dce.CALL( ) - ETH 0.00810586
BingX Dep: 0x40BBbcFDfC6932600D9258fE6ff422821521E7fe.CALL( ) - ETH 0.00907526
0x25734b968d7f5c1e027e48cdc6c070bca99d657b.CALL( ) - ETH 0.0124508
0x647c1861345d52f84ca1659f51d0485ae4167aaa.CALL( ) - ETH 0.01269613
0x31a817802ee183eb8b13167ffe24bd28dcc6f30c.CALL( ) - ETH 0.01283226
0xb831579e837824432d5d19ac10456728e87ed605.CALL( ) - ETH 0.01459923
0x73cef42eb480fa806af8077b27de323264197e8c.CALL( ) - ETH 0.01548584
0xe4761536144b9f4b46dda79834c88a91058adf5c.CALL( ) - ETH 0.02030022
0x22d60d8ca42b6d82cec33a4ed68f5950e7126f18.CALL( ) - ETH 0.02035911
0x7ef6e570ae8e977adcb4646b2d0befa364b12602.CALL( ) - ETH 0.0209287
0xb04d264a001b00c9e1791edb9944c274d09f3cf9.CALL( ) - ETH 0.02600673
0xa2d5572cf61c98ac0b8b542059356bb3547a78ef.CALL( ) - ETH 0.02638583
0xb7483f2e0d2c0b00c401a875e260b38dea7c1414.CALL( ) - ETH 0.03036264
0xd954560419a88223fff2ccde6efbae9f884af739.CALL( ) - ETH 0.03380218
0x55eb6c70eb1a87ffa3c3a2f4d5385d399f14379c.CALL( ) - ETH 0.03703285
0xb79ad82adf2985fe5d79271e948a8a29b1e7823e.CALL( ) - ETH 0.05341972
0x1fbe6a01183b39a8fcbcb358dd310264b87c4f02.CALL( ) - ETH 0.05741118
0x6351b68517bd899b44d0ee8301d14302cbfdf59c.CALL( ) - ETH 0.09299323
0x9b5adebad48cf33869ddc6a463839ba24a0fff54.CALL( ) ETH 0.11005187
Forwarder.CALL( )ETH 0.11005187
Forwarder.DELEGATECALL( )- ETH 0.11005187
0x7a5ce41c3511e4838f5dcefcf5533950ee1a8315.CALL( )
- ETH 0.11005187
- ETH 0.13953657
0x2c2e4c7993a11130f34a7eebe00364374d89d339.CALL( ) - ETH 0.15
0x74047b072d81b563a096c6d4d5ac2fae139357b9.CALL( )
File 1 of 2: Forwarder
File 2 of 2: Forwarder
pragma solidity 0.7.5;
/*
The MIT License (MIT)
Copyright (c) 2018 Murray Software, LLC.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//solhint-disable max-line-length
//solhint-disable no-inline-assembly
contract CloneFactory {
function createClone(address target, bytes32 salt)
internal
returns (address payable result)
{
bytes20 targetBytes = bytes20(target);
assembly {
// load the next free memory slot as a place to store the clone contract data
let clone := mload(0x40)
// The bytecode block below is responsible for contract initialization
// during deployment, it is worth noting the proxied contract constructor will not be called during
// the cloning procedure and that is why an initialization function needs to be called after the
// clone is created
mstore(
clone,
0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
)
// This stores the address location of the implementation contract
// so that the proxy knows where to delegate call logic to
mstore(add(clone, 0x14), targetBytes)
// The bytecode block is the actual code that is deployed for each clone created.
// It forwards all calls to the already deployed implementation via a delegatecall
mstore(
add(clone, 0x28),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
// deploy the contract using the CREATE2 opcode
// this deploys the minimal proxy defined above, which will proxy all
// calls to use the logic defined in the implementation contract `target`
result := create2(0, clone, 0x37, salt)
}
}
function isClone(address target, address query)
internal
view
returns (bool result)
{
bytes20 targetBytes = bytes20(target);
assembly {
// load the next free memory slot as a place to store the comparison clone
let clone := mload(0x40)
// The next three lines store the expected bytecode for a miniml proxy
// that targets `target` as its implementation contract
mstore(
clone,
0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000
)
mstore(add(clone, 0xa), targetBytes)
mstore(
add(clone, 0x1e),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
// the next two lines store the bytecode of the contract that we are checking in memory
let other := add(clone, 0x40)
extcodecopy(query, other, 0, 0x2d)
// Check if the expected bytecode equals the actual bytecode and return the result
result := and(
eq(mload(clone), mload(other)),
eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
)
}
}
}
/**
* Contract that exposes the needed erc20 token functions
*/
abstract contract ERC20Interface {
// Send _value amount of tokens to address _to
function transfer(address _to, uint256 _value)
public
virtual
returns (bool success);
// Get the account balance of another account with address _owner
function balanceOf(address _owner)
public
virtual
view
returns (uint256 balance);
}
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
/**
* Contract that will forward any incoming Ether to the creator of the contract
*
*/
contract Forwarder {
// Address to which any funds sent to this contract will be forwarded
address public parentAddress;
event ForwarderDeposited(address from, uint256 value, bytes data);
/**
* Initialize the contract, and sets the destination address to that of the creator
*/
function init(address _parentAddress) external onlyUninitialized {
parentAddress = _parentAddress;
uint256 value = address(this).balance;
if (value == 0) {
return;
}
(bool success, ) = parentAddress.call{ value: value }('');
require(success, 'Flush failed');
// NOTE: since we are forwarding on initialization,
// we don't have the context of the original sender.
// We still emit an event about the forwarding but set
// the sender to the forwarder itself
emit ForwarderDeposited(address(this), value, msg.data);
}
/**
* Modifier that will execute internal code block only if the sender is the parent address
*/
modifier onlyParent {
require(msg.sender == parentAddress, 'Only Parent');
_;
}
/**
* Modifier that will execute internal code block only if the contract has not been initialized yet
*/
modifier onlyUninitialized {
require(parentAddress == address(0x0), 'Already initialized');
_;
}
/**
* Default function; Gets called when data is sent but does not match any other function
*/
fallback() external payable {
flush();
}
/**
* Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
*/
receive() external payable {
flush();
}
/**
* Execute a token transfer of the full balance from the forwarder token to the parent address
* @param tokenContractAddress the address of the erc20 token contract
*/
function flushTokens(address tokenContractAddress) external onlyParent {
ERC20Interface instance = ERC20Interface(tokenContractAddress);
address forwarderAddress = address(this);
uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
if (forwarderBalance == 0) {
return;
}
TransferHelper.safeTransfer(
tokenContractAddress,
parentAddress,
forwarderBalance
);
}
/**
* Flush the entire balance of the contract to the parent address.
*/
function flush() public {
uint256 value = address(this).balance;
if (value == 0) {
return;
}
(bool success, ) = parentAddress.call{ value: value }('');
require(success, 'Flush failed');
emit ForwarderDeposited(msg.sender, value, msg.data);
}
}
contract ForwarderFactory is CloneFactory {
address public implementationAddress;
event ForwarderCreated(address newForwarderAddress, address parentAddress);
constructor(address _implementationAddress) {
implementationAddress = _implementationAddress;
}
function createForwarder(address parent, bytes32 salt) external {
// include the signers in the salt so any contract deployed to a given address must have the same signers
bytes32 finalSalt = keccak256(abi.encodePacked(parent, salt));
address payable clone = createClone(implementationAddress, finalSalt);
Forwarder(clone).init(parent);
emit ForwarderCreated(clone, parent);
}
}File 2 of 2: Forwarder
pragma solidity 0.7.5;
/*
The MIT License (MIT)
Copyright (c) 2018 Murray Software, LLC.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//solhint-disable max-line-length
//solhint-disable no-inline-assembly
contract CloneFactory {
function createClone(address target, bytes32 salt)
internal
returns (address payable result)
{
bytes20 targetBytes = bytes20(target);
assembly {
// load the next free memory slot as a place to store the clone contract data
let clone := mload(0x40)
// The bytecode block below is responsible for contract initialization
// during deployment, it is worth noting the proxied contract constructor will not be called during
// the cloning procedure and that is why an initialization function needs to be called after the
// clone is created
mstore(
clone,
0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
)
// This stores the address location of the implementation contract
// so that the proxy knows where to delegate call logic to
mstore(add(clone, 0x14), targetBytes)
// The bytecode block is the actual code that is deployed for each clone created.
// It forwards all calls to the already deployed implementation via a delegatecall
mstore(
add(clone, 0x28),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
// deploy the contract using the CREATE2 opcode
// this deploys the minimal proxy defined above, which will proxy all
// calls to use the logic defined in the implementation contract `target`
result := create2(0, clone, 0x37, salt)
}
}
function isClone(address target, address query)
internal
view
returns (bool result)
{
bytes20 targetBytes = bytes20(target);
assembly {
// load the next free memory slot as a place to store the comparison clone
let clone := mload(0x40)
// The next three lines store the expected bytecode for a miniml proxy
// that targets `target` as its implementation contract
mstore(
clone,
0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000
)
mstore(add(clone, 0xa), targetBytes)
mstore(
add(clone, 0x1e),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
// the next two lines store the bytecode of the contract that we are checking in memory
let other := add(clone, 0x40)
extcodecopy(query, other, 0, 0x2d)
// Check if the expected bytecode equals the actual bytecode and return the result
result := and(
eq(mload(clone), mload(other)),
eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
)
}
}
}
/**
* Contract that exposes the needed erc20 token functions
*/
abstract contract ERC20Interface {
// Send _value amount of tokens to address _to
function transfer(address _to, uint256 _value)
public
virtual
returns (bool success);
// Get the account balance of another account with address _owner
function balanceOf(address _owner)
public
virtual
view
returns (uint256 balance);
}
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
/**
* Contract that will forward any incoming Ether to the creator of the contract
*
*/
contract Forwarder {
// Address to which any funds sent to this contract will be forwarded
address public parentAddress;
event ForwarderDeposited(address from, uint256 value, bytes data);
/**
* Initialize the contract, and sets the destination address to that of the creator
*/
function init(address _parentAddress) external onlyUninitialized {
parentAddress = _parentAddress;
uint256 value = address(this).balance;
if (value == 0) {
return;
}
(bool success, ) = parentAddress.call{ value: value }('');
require(success, 'Flush failed');
// NOTE: since we are forwarding on initialization,
// we don't have the context of the original sender.
// We still emit an event about the forwarding but set
// the sender to the forwarder itself
emit ForwarderDeposited(address(this), value, msg.data);
}
/**
* Modifier that will execute internal code block only if the sender is the parent address
*/
modifier onlyParent {
require(msg.sender == parentAddress, 'Only Parent');
_;
}
/**
* Modifier that will execute internal code block only if the contract has not been initialized yet
*/
modifier onlyUninitialized {
require(parentAddress == address(0x0), 'Already initialized');
_;
}
/**
* Default function; Gets called when data is sent but does not match any other function
*/
fallback() external payable {
flush();
}
/**
* Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
*/
receive() external payable {
flush();
}
/**
* Execute a token transfer of the full balance from the forwarder token to the parent address
* @param tokenContractAddress the address of the erc20 token contract
*/
function flushTokens(address tokenContractAddress) external onlyParent {
ERC20Interface instance = ERC20Interface(tokenContractAddress);
address forwarderAddress = address(this);
uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
if (forwarderBalance == 0) {
return;
}
TransferHelper.safeTransfer(
tokenContractAddress,
parentAddress,
forwarderBalance
);
}
/**
* Flush the entire balance of the contract to the parent address.
*/
function flush() public {
uint256 value = address(this).balance;
if (value == 0) {
return;
}
(bool success, ) = parentAddress.call{ value: value }('');
require(success, 'Flush failed');
emit ForwarderDeposited(msg.sender, value, msg.data);
}
}
contract ForwarderFactory is CloneFactory {
address public implementationAddress;
event ForwarderCreated(address newForwarderAddress, address parentAddress);
constructor(address _implementationAddress) {
implementationAddress = _implementationAddress;
}
function createForwarder(address parent, bytes32 salt) external {
// include the signers in the salt so any contract deployed to a given address must have the same signers
bytes32 finalSalt = keccak256(abi.encodePacked(parent, salt));
address payable clone = createClone(implementationAddress, finalSalt);
Forwarder(clone).init(parent);
emit ForwarderCreated(clone, parent);
}
}