Skip to content

Commit df3c7bb

Browse files
feat(contracts): make v0 contracts similar to v1
Ticket: BG-62483
1 parent 259c36b commit df3c7bb

4 files changed

Lines changed: 113 additions & 33 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity 0.8.10;
3+
4+
/**
5+
* Contract that exposes the needed erc20 token functions
6+
*/
7+
8+
abstract contract ERC20Interface {
9+
// Send _value amount of tokens to address _to
10+
function transfer(address _to, uint256 _value)
11+
public
12+
virtual
13+
returns (bool success);
14+
15+
// Get the account balance of another account with address _owner
16+
function balanceOf(address _owner)
17+
public
18+
virtual
19+
view
20+
returns (uint256 balance);
21+
}
Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,84 @@
11
pragma solidity 0.8.10;
2-
2+
import './TransferHelper.sol';
3+
import './ERC20Interface.sol';
34
/**
4-
* Basic singleSig contract designed to send funds controlled by signer.
5+
* Contract that will forward any incoming Ether to the creator of the contract
56
*/
67
contract RecoveryForwarder {
7-
// Address which can move funds from this contract
8-
address public signer;
8+
// Address to which any funds sent to this contract will be forwarded
9+
address public parentAddress;
910
/**
10-
* Initialize the signer
11+
* Initialize the parent
1112
*/
12-
function init(address _signer) external onlyUninitialized {
13-
signer = _signer;
13+
function init(address _parentAddress) external onlyUninitialized {
14+
parentAddress = _parentAddress;
1415
}
1516

16-
/**
17-
* Modifier that will execute internal code block only if the sender is an authorized signer on this wallet
18-
*/
19-
modifier onlySigner {
20-
require( signer == msg.sender, 'Non-signer in onlySigner method');
17+
/**
18+
* Modifier that will execute internal code block only if the sender is the parent address
19+
*/
20+
modifier onlyParent {
21+
require( parentAddress == msg.sender, 'Non-parent in onlyParent method');
2122
_;
2223
}
2324

2425
/**
2526
* Modifier that will execute internal code block only if the contract has not been initialized yet
2627
*/
2728
modifier onlyUninitialized {
28-
require(signer == address(0x0), 'Already initialized');
29+
require(parentAddress == address(0x0), 'Already initialized');
2930
_;
3031
}
3132

32-
/**
33-
* Default function; Gets called when Ether is deposited
34-
*/
35-
receive() external payable {
33+
/**
34+
* Default function; Gets called when Ether is deposited
35+
*/
36+
receive() external payable {
37+
flush();
3638
}
3739

3840
/**
3941
* Default function; Gets called when data is sent but does not match any other function
4042
*/
4143
fallback() external payable {
44+
flush();
45+
}
46+
47+
/**
48+
* Execute a token transfer of the full balance from the forwarder token to the parent address
49+
* @param tokenContractAddress the address of the erc20 token contract
50+
*/
51+
function flushTokens(address tokenContractAddress) external onlyParent {
52+
ERC20Interface instance = ERC20Interface(tokenContractAddress);
53+
address forwarderAddress = address(this);
54+
uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
55+
TransferHelper.safeTransfer(
56+
tokenContractAddress,
57+
parentAddress,
58+
forwarderBalance
59+
);
60+
}
61+
62+
/**
63+
* A fallback function which can used to transfer funds controlled by parent.
64+
*/
65+
function callFromParent(
66+
address target,
67+
uint256 value,
68+
bytes calldata data
69+
) external onlyParent {
70+
(bool success, ) = target.call{ value: value }(
71+
data
72+
);
73+
require(success, 'Parent call execution failed');
4274
}
4375

4476
/**
45-
* Execute a transaction from this contract using the signer.
46-
*
47-
* @param toAddress the destination address to send an outgoing transaction
48-
* @param value the amount in Wei to be sent
49-
* @param data the data to send to the toAddress when invoking the transaction
77+
* Flush the entire balance of the contract to the parent address.
5078
*/
51-
function sendFunds(
52-
address toAddress,
53-
uint256 value,
54-
bytes calldata data
55-
) external onlySigner {
56-
// Success, send the transaction
57-
(bool success, ) = toAddress.call{ value: value }(data);
58-
require(success, 'Call execution failed');
79+
function flush() public {
80+
uint256 value = address(this).balance;
81+
(bool success, ) = parentAddress.call{ value: value }('');
82+
require(success, 'Flush failed');
5983
}
6084
}

recovery-contracts/RecoveryWallet.sol

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,29 @@ contract RecoveryWallet is CloneFactory {
4141
/**
4242
* Creates new forwarder contract controlled by signer in batches
4343
*/
44-
function createRecoveryForwarder(uint8 value) external {
44+
function createRecoveryForwarder(uint8 value) external {
4545
require(value > 0 && value < 150 , 'value must be greater than 0 and less than 150');
4646
for ( uint8 i = 0; i < value; ++i) {
4747
address payable clone = createClone(forwarderImplementationAddress);
48-
RecoveryForwarder(clone).init(signer);
48+
RecoveryForwarder(clone).init(address(this));
4949
}
5050
}
5151

52+
/**
53+
* Execute a token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
54+
*
55+
* @param forwarderAddress the address of the forwarder address to flush the tokens from
56+
* @param tokenContractAddress the address of the erc20 token contract
57+
*/
58+
function flushForwarderTokens(
59+
address payable forwarderAddress,
60+
address tokenContractAddress
61+
) external {
62+
RecoveryForwarder forwarder = RecoveryForwarder(forwarderAddress);
63+
forwarder.flushTokens(tokenContractAddress);
64+
}
65+
66+
5267
/**
5368
* Execute a transaction from this wallet using the signer.
5469
*
@@ -66,5 +81,4 @@ function createRecoveryForwarder(uint8 value) external {
6681
(bool success, ) = toAddress.call{ value: value }(data);
6782
require(success, 'Call execution failed');
6883
}
69-
7084
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
// source: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/TransferHelper.sol
3+
pragma solidity 0.8.10;
4+
5+
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
6+
library TransferHelper {
7+
function safeTransfer(
8+
address token,
9+
address to,
10+
uint256 value
11+
) internal {
12+
// bytes4(keccak256(bytes('transfer(address,uint256)')));
13+
(bool success, bytes memory data) = token.call(
14+
abi.encodeWithSelector(0xa9059cbb, to, value)
15+
);
16+
require(
17+
success && (data.length == 0 || abi.decode(data, (bool))),
18+
'TransferHelper::safeTransfer: transfer failed'
19+
);
20+
}
21+
}

0 commit comments

Comments
 (0)