From 95c7f0e99d3c1adae542e6bab54179d817b83c2e Mon Sep 17 00:00:00 2001 From: Marco Millo Date: Thu, 16 Apr 2020 04:42:01 +0200 Subject: [PATCH 1/2] Adding Transfer/Moving tokens option in Token Manager --- apps/token-manager/arapp.json | 9 +++++++++ apps/token-manager/contracts/TokenManager.sol | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/apps/token-manager/arapp.json b/apps/token-manager/arapp.json index 8c77b58938..9bedf09425 100644 --- a/apps/token-manager/arapp.json +++ b/apps/token-manager/arapp.json @@ -55,6 +55,15 @@ "Token amount" ] }, + { + "name": "Move tokens", + "id": "TRANSFER_FROM_TO_ROLE", + "params": [ + "Holder", + "Receiver", + "Token amount" + ] + }, { "name": "Revoke vesting", "id": "REVOKE_VESTINGS_ROLE", diff --git a/apps/token-manager/contracts/TokenManager.sol b/apps/token-manager/contracts/TokenManager.sol index f96dd51653..4ab7667adc 100644 --- a/apps/token-manager/contracts/TokenManager.sol +++ b/apps/token-manager/contracts/TokenManager.sol @@ -21,6 +21,7 @@ contract TokenManager is ITokenController, IForwarder, AragonApp { bytes32 public constant MINT_ROLE = keccak256("MINT_ROLE"); bytes32 public constant ISSUE_ROLE = keccak256("ISSUE_ROLE"); bytes32 public constant ASSIGN_ROLE = keccak256("ASSIGN_ROLE"); + bytes32 public constant TRANSFER_FROM_TO_ROLE = keccak256("TRANSFER_FROM_TO_ROLE"); bytes32 public constant REVOKE_VESTINGS_ROLE = keccak256("REVOKE_VESTINGS_ROLE"); bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE"); @@ -133,6 +134,16 @@ contract TokenManager is ITokenController, IForwarder, AragonApp { token.destroyTokens(_holder, _amount); } + /** + * @notice Transfer `@tokenAmount(self.token(): address, _amount, false)` tokens from `_holder` to `_receiver` + * @param _holder Holder of tokens being transferred + * @param _receiver The address receiving the tokens + * @param _amount Number of tokens transferred + */ + function transfer_from_to(address _holder, address _receiver, uint256 _amount) external authP(TRANSFER_FROM_TO_ROLE, arr(_holder, _receiver, _amount)) { + _transfer_from_to(_holder, _receiver, _amount); + } + /** * @notice Assign `@tokenAmount(self.token(): address, _amount, false)` tokens to `_receiver` from the Token Manager's holdings with a `_revokable : 'revokable' : ''` vesting starting at `@formatDate(_start)`, cliff at `@formatDate(_cliff)` (first portion of tokens transferable), and completed vesting at `@formatDate(_vested)` (all tokens transferable) * @param _receiver The address receiving the tokens, cannot be Token Manager itself @@ -323,6 +334,11 @@ contract TokenManager is ITokenController, IForwarder, AragonApp { token.generateTokens(_receiver, _amount); // minime.generateTokens() never returns false } + function _transfer_from_to(address _holder, address _receiver, uint256 _amount) internal { + require(_isBalanceIncreaseAllowed(_holder, _receiver, _amount), ERROR_BALANCE_INCREASE_NOT_ALLOWED); + require(token.transferFrom(_holder, _receiver, _amount), ERROR_ASSIGN_TRANSFER_FROM_REVERTED); + } + function _isBalanceIncreaseAllowed(address _receiver, uint256 _inc) internal view returns (bool) { // Max balance doesn't apply to the token manager itself if (_receiver == address(this)) { From 710b6d17d704cfa4d70d9595e6ca9924f6650162 Mon Sep 17 00:00:00 2001 From: Marco Millo Date: Sat, 25 Apr 2020 10:38:07 +0200 Subject: [PATCH 2/2] Trying to create Button in header and side panel with move tokens function. --- apps/token-manager/app/src/App.js | 15 +++++++++- .../app/src/components/AppHeader.js | 11 +++++++ .../UpdateTokenPanel/UpdateTokenPanel.js | 29 +++++++++++++++++-- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/apps/token-manager/app/src/App.js b/apps/token-manager/app/src/App.js index a04618d66e..b06c915636 100644 --- a/apps/token-manager/app/src/App.js +++ b/apps/token-manager/app/src/App.js @@ -37,7 +37,7 @@ class App extends React.PureComponent { ) return holder ? holder.balance : new BN('0') } - handleUpdateTokens = ({ amount, holder, mode }) => { + handleUpdateTokens = ({ amount, holder, to, mode }) => { const { api } = this.props // Don't care about responses @@ -47,6 +47,9 @@ class App extends React.PureComponent { if (mode === 'remove') { api.burn(holder, amount).toPromise() } + if (mode === 'move') { + api.transfer_from_to(holder, to, amount).toPromise() + } this.handleSidepanelClose() } @@ -59,6 +62,15 @@ class App extends React.PureComponent { sidepanelOpened: true, }) } + handleLaunchMoveTokensNoHolder = () => { + this.handleLaunchMoveTokens('') + } + handleLaunchMoveTokens = address => { + this.setState({ + assignTokensConfig: {mode: 'move', holderAddress: address }, + sidepanelOpened: true, + }) + } handleLaunchRemoveTokens = address => { this.setState({ assignTokensConfig: { mode: 'remove', holderAddress: address }, @@ -113,6 +125,7 @@ class App extends React.PureComponent { } secondary={ + <>