-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathVirtualAccount.sol
75 lines (58 loc) · 2.66 KB
/
VirtualAccount.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {ERC721} from "solmate/tokens/ERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IVirtualAccount, Call} from "./interfaces/IVirtualAccount.sol";
import {IRootPort} from "./interfaces/IRootPort.sol";
/// @title VirtualAccount - Contract for managing a virtual user account on the Root Chain
contract VirtualAccount is IVirtualAccount {
using SafeTransferLib for address;
/// @inheritdoc IVirtualAccount
address public immutable userAddress;
/// @inheritdoc IVirtualAccount
address public localPortAddress;
constructor(address _userAddress, address _localPortAddress) {
userAddress = _userAddress;
localPortAddress = _localPortAddress;
}
/// @inheritdoc IVirtualAccount
function withdrawERC20(address _token, uint256 _amount) external requiresApprovedCaller {
_token.safeTransfer(msg.sender, _amount);
}
/// @inheritdoc IVirtualAccount
function withdrawERC721(address _token, uint256 _tokenId) external requiresApprovedCaller {
ERC721(_token).transferFrom(address(this), msg.sender, _tokenId);
}
/// @inheritdoc IVirtualAccount
function call(Call[] calldata calls)
external
requiresApprovedCaller
returns (uint256 blockNumber, bytes[] memory returnData)
{
blockNumber = block.number;
returnData = new bytes[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
(bool success, bytes memory data) = calls[i].target.call(calls[i].callData);
if (!success) revert CallFailed();
returnData[i] = data;
}
}
/*//////////////////////////////////////////////////////////////
EXTERNAL HOOKS
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IERC721Receiver
function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
return this.onERC721Received.selector;
}
/*///////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/// @notice Modifier that verifies msg sender is the approved to use the virtual account. Either the owner or an approved router.
modifier requiresApprovedCaller() {
if ((!IRootPort(localPortAddress).isRouterApproved(this, msg.sender)) && (msg.sender != userAddress)) {
revert UnauthorizedCaller();
}
_;
}
}