-
Notifications
You must be signed in to change notification settings - Fork 261
Expand file tree
/
Copy pathSuperUpgrader.sol
More file actions
121 lines (108 loc) · 4.11 KB
/
SuperUpgrader.sol
File metadata and controls
121 lines (108 loc) · 4.11 KB
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
import { AccessControlEnumerable } from "@openzeppelin-v5/contracts/access/extensions/AccessControlEnumerable.sol";
import { SafeERC20 } from "@openzeppelin-v5/contracts/token/ERC20/utils/SafeERC20.sol";
import {
ISuperToken,
IERC20
} from "../interfaces/superfluid/ISuperfluid.sol";
/**
* @title Super upgrader contract
* @author Superfluid
* NOTE:
* - User would need to first SuperToken.approve the `SuperUpgrader` for the job.
* - Using access control to allow multiple backend agent to upgrade tokens for the users
* - Risk taken by the user is that the underlying tokens are converted to the Super Tokens by the upgrader agents.
*/
contract SuperUpgrader is AccessControlEnumerable {
using SafeERC20 for IERC20;
// Create a new role identifier for the backend role
bytes32 public constant BACKEND_ROLE = keccak256("BACKEND_ROLE");
event OptoutAutoUpgrade(address indexed account);
event OptinAutoUpgrade(address indexed account);
mapping(address => bool) internal _optout;
constructor(address adminRole, address[] memory backendAddr) {
require(adminRole != address(0), "adminRole is empty");
_grantRole(DEFAULT_ADMIN_ROLE, adminRole);
for (uint256 i = 0; i < backendAddr.length; ++i) {
require(backendAddr[i] != address(0), "backend can't be zero");
_grantRole(BACKEND_ROLE, backendAddr[i]);
}
}
/**
* @notice The user should ERC20.approve this contract.
* @dev Execute upgrade function in the name of the user
* @param superTokenAddr Super Token Address to upgrade
* @param account User address that previous approved this contract.
* @param amount Amount value to be upgraded.
*/
function upgrade(
address superTokenAddr,
address account,
uint256 amount
)
external
{
require(msg.sender == account ||
(hasRole(BACKEND_ROLE, msg.sender) &&
!_optout[account])
, "operation not allowed");
// get underlying token
ISuperToken superToken = ISuperToken(superTokenAddr);
// get tokens from user
IERC20 token = IERC20(superToken.getUnderlyingToken());
uint256 beforeBalance = token.balanceOf(address(this));
token.safeTransferFrom(account, address(this), amount);
token.forceApprove(address(superToken), amount);
// upgrade tokens and send back to user
superToken.upgradeTo(
account,
token.balanceOf(address(this)) - beforeBalance, new bytes(0));
}
/**
* @dev Test if account is member BACKEND_ROLE
*/
function isBackendAgent(address account) external view returns(bool yes) {
return hasRole(BACKEND_ROLE, account);
}
/**
* @dev Add account to BACKEND_ROLE
*/
function grantBackendAgent(address account) external {
require(account != address(0), "operation not allowed");
// grantRole will check if sender is adminRole member
grantRole(BACKEND_ROLE, account);
}
/**
* @dev Remove account to BACKEND_ROLE
*/
function revokeBackendAgent(address account) external {
// grantRole will check if sender is adminRole member
revokeRole(BACKEND_ROLE, account);
}
/**
* @dev Get list of all members of BACKEND_ROLE
*/
function getBackendAgents() external view returns(address[] memory) {
uint256 numberOfMembers = getRoleMemberCount(BACKEND_ROLE);
address[] memory members = new address[](numberOfMembers);
for (uint256 i = 0; i < numberOfMembers; ++i) {
members[i] = getRoleMember(BACKEND_ROLE, i);
}
return members;
}
/**
* @dev User signal that opt-out from backend upgrades
*/
function optoutAutoUpgrades() external {
_optout[msg.sender] = true;
emit OptoutAutoUpgrade(msg.sender);
}
/**
* @dev User signal that revoke opt-out from backend upgrades
*/
function optinAutoUpgrades() external {
delete _optout[msg.sender];
emit OptinAutoUpgrade(msg.sender);
}
}