Last active
May 29, 2019 16:11
-
-
Save luisivan/87389ccf51a693d73e89630d529b3e8c to your computer and use it in GitHub Desktop.
Aragon wrapper for ERC20 tokens
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
/* Based on https://github.com/MyBitFoundation/MyBit-DAO.tech/blob/master/apps/MyTokens/contracts/MyTokens.sol */ | |
/* solium-disable function-order */ | |
pragma solidity 0.4.24; | |
import "@aragon/os/contracts/apps/AragonApp.sol"; | |
import "@aragon/os/contracts/common/IForwarder.sol"; | |
import "@aragon/os/contracts/lib/token/ERC20.sol"; | |
import "@aragon/os/contracts/lib/math/SafeMath.sol"; | |
import "@aragon/apps-shared-minime/contracts/ITokenController.sol"; | |
import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; | |
contract AragonERC20Wrapper is ITokenController, IForwarder, AragonApp { | |
using SafeMath for uint256; | |
event TokensLocked(address entity, uint256 amount); | |
event TokensUnlocked(address entity, uint256 amount); | |
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); | |
string private constant ERROR_TOKEN_CONTROLLER = "TM_TOKEN_CONTROLLER"; | |
string private constant ERROR_CAN_NOT_FORWARD = "TM_CAN_NOT_FORWARD"; | |
string private constant ERROR_PROXY_PAYMENT_WRONG_SENDER = "TM_PROXY_PAYMENT_WRONG_SENDER"; | |
MiniMeToken public token; | |
ERC20 public erc20; | |
mapping(address => uint256) private lockAmount; | |
/** | |
* @notice Initialize a new MiniMe token that will be the controller of an ERC20 token | |
* @param _token The MiniMe token that is used in the DAO | |
* @param _erc20 The ERC20 token that is locked in order to receive MiniMe tokens | |
*/ | |
function initialize( | |
MiniMeToken _token, | |
address _erc20 | |
) | |
external | |
{ | |
initialized(); | |
require(MiniMeToken(_token).controller() == address(this), ERROR_TOKEN_CONTROLLER); | |
token = _token; | |
token.enableTransfers(false); | |
erc20 = ERC20(_erc20); | |
} | |
/** | |
* @notice Lock `_amount` tokens | |
*/ | |
function lock(uint256 _amount) external { | |
require(amount > 0, 'Token amount is 0'); | |
require(erc20.transferFrom(msg.sender, address(this), _amount), 'ERC20 not sent'); | |
require(token.generateTokens(msg.sender, _amount), 'Tokens not generated'); | |
lockAmount[msg.sender] = lockAmount[msg.sender].add(_amount); | |
emit TokensLocked(msg.sender, _amount); | |
} | |
/** | |
* @notice Unlock `_amount` tokens | |
*/ | |
function unlock(uint256 _amount) external { | |
require(amount > 0, 'Token amount is 0'); | |
require(amount <= lockAmount[msg.sender], 'Token amount to unlock is larger than amount of tokens locked'); | |
require(token.destroyTokens(msg.sender, token.balanceOf(msg.sender).sub(_amount)), 'Tokens not destroyed'); | |
require(erc20.transfer(msg.sender, _amount), 'ERC20 not returned'); | |
lockAmount[msg.sender] = lockAmount[msg.sender].sub(_amount); | |
if (lockAmount[msg.sender] == 0) { | |
delete lockAmount[msg.sender]; | |
} | |
emit TokensUnlocked(msg.sender, _amount); | |
} | |
/** | |
* @notice Give control of the MiniMe token over to `_newController` | |
* @param _newController Ethereum address of contract that will control the token | |
*/ | |
function changeTokenController(address _newController) external auth(MANAGER_ROLE) { | |
token.changeController(_newController); | |
} | |
/** | |
* @notice Execute desired action as a token holder | |
* @dev IForwarder interface conformance. Forwards any token holder action. | |
* @param _evmScript Script being executed | |
*/ | |
function forward(bytes _evmScript) public { | |
require(canForward(msg.sender, _evmScript), ERROR_CAN_NOT_FORWARD); | |
bytes memory input = new bytes(0); // TODO: Consider input for this | |
// Add the managed token to the blacklist to disallow a token holder from executing actions | |
// on the token controller's (this contract) behalf | |
address[] memory blacklist = new address[](2); | |
blacklist[0] = address(token); | |
blacklist[1] = address(erc20); | |
runScript(_evmScript, input, blacklist); | |
} | |
function isForwarder() public pure returns (bool) { | |
return true; | |
} | |
function canForward(address _sender, bytes) public view returns (bool) { | |
return hasInitialized() && token.balanceOf(_sender) > 0; | |
} | |
/* | |
* @dev Notifies the controller about a token transfer allowing the controller to decide whether to allow it or react if desired (only callable from the token) | |
* @param _from The origin of the transfer | |
* @param _to The destination of the transfer | |
* @param _amount The amount of the transfer | |
* @return False if the controller does not authorize the transfer | |
*/ | |
function onTransfer(address _from, address _to, uint _amount) public isInitialized returns (bool) { | |
return false; | |
} | |
/** | |
* @notice Called when ether is sent to the MiniMe Token contract | |
* @return True if the ether is accepted, false for it to throw | |
*/ | |
function proxyPayment(address) public payable returns (bool) { | |
// Sender check is required to avoid anyone sending ETH to the Token Manager through this method | |
// Even though it is tested, solidity-coverage doesnt get it because | |
// MiniMeToken is not instrumented and entire tx is reverted | |
require(msg.sender == address(token), ERROR_PROXY_PAYMENT_WRONG_SENDER); | |
return false; | |
} | |
/** | |
* @dev Notifies the controller about an approval allowing the controller to react if desired | |
* @return False if the controller does not authorize the approval | |
*/ | |
function onApprove(address, address, uint) public returns (bool) { | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment