Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test file with initial tests. #6

Merged
merged 21 commits into from
May 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
817c2de
Updated Vault contract version. Added truffle compiler config. Fixed …
willjgriff May 10, 2019
2d61738
Merge branch 'redemptions-contract-changes' of https://github.com/0xG…
willjgriff May 10, 2019
270b628
Added ERC20 to tests and fleshed out init test.
willjgriff May 10, 2019
4f4fd55
Added babel to enable ES6 in test files. Extracted DAO deployment int…
willjgriff May 10, 2019
728e71a
Extracted helper functions. Added check for contract in addVaultToken…
willjgriff May 10, 2019
6021b0d
Add removeVaultTokenTest
fabriziovigevani May 11, 2019
61ab765
Merge pull request #2 from fabriziovigevani/redemptions-contract-changes
0xGabi May 12, 2019
a9c8df6
Add redeem tests
fabriziovigevani May 13, 2019
f6a1755
Merge pull request #3 from fabriziovigevani/redemptions-contract-changes
0xGabi May 13, 2019
2d6c665
Merge pull request #4 from 0xGabi/master
0xGabi May 13, 2019
8611260
Fix minor issues
fabriziovigevani May 13, 2019
dd3e1ae
remove .vscode and add to gitignore
fabriziovigevani May 13, 2019
7b6eff3
Change token reference to token Manager instead of directly
fabriziovigevani May 14, 2019
7c69be8
Merge pull request #5 from fabriziovigevani/redemptions-contract-changes
0xGabi May 14, 2019
491abe4
Merge pull request #6 from 0xGabi/master
0xGabi May 14, 2019
89f8563
Fix typo: deleted memory on initialize
0xGabi May 14, 2019
e10b3b8
Added to doc strings. Added check for tokenManager being a contract.
willjgriff May 14, 2019
4328d0c
template
rperez89 May 14, 2019
a226ffd
remove some requires
rperez89 May 14, 2019
9950d6a
Update roles on arapp.json
0xGabi May 15, 2019
bcb3498
Style: change app for redemptions
0xGabi May 15, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["es2015", "stage-2", "stage-3"]
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ ipfs.cmd
package-lock.json
coverage.json
coverage
.vscode
14 changes: 12 additions & 2 deletions arapp.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
{
"roles": [
{
"name": "Add member to the list of members",
"id": "ADD_MEMBER_ROLE",
"name": "Redeem tokens from the vault",
"id": "REDEEM_ROLE",
"params": []
},
{
"name": "Add token to the vault list",
"id": "ADD_TOKEN_ROLE",
"params": []
},
{
"name": "Remove token from vault list",
"id": "REMOVE_TOKEN_ROLE",
"params": []
}
],
Expand Down
75 changes: 48 additions & 27 deletions contracts/Redemptions.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pragma solidity ^0.4.24;

import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/apps-token-manager/contracts/TokenManager.sol";
import "@aragon/os/contracts/lib/math/SafeMath.sol";
import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol";
import "@aragon/apps-vault/contracts/Vault.sol";
import "./ArrayUtils.sol";

Expand All @@ -15,74 +15,95 @@ contract Redemptions is AragonApp {
bytes32 constant public REMOVE_TOKEN_ROLE = keccak256("REMOVE_TOKEN_ROLE");

string private constant ERROR_VAULT_NOT_CONTRACT = "REDEMPTIONS_VAULT_NOT_CONTRACT";
string private constant ERROR_REDEEMABLE_TOKEN = "REDEMPTIONS_REDEEMABLE_TOKEN";
string private constant ERROR_TOKEN_MANAGER_NOT_CONTRACT = "REDEMPTIONS_TOKEN_MANAGER_NOT_CONTRACT";
string private constant ERROR_TOKEN_MANAGER = "REDEMPTIONS_TOKEN_MANAGER";
string private constant ERROR_TOKEN_ALREADY_ADDED = "REDEMPTIONS_TOKEN_ALREADY_ADDED";
string private constant ERROR_TOKEN_NOT_CONTRACT = "REDEMPTIONS_TOKEN_NOT_CONTRACT";
string private constant ERROR_NOT_VAULT_TOKEN = "REDEMPTIONS_NOT_VAULT_TOKEN";
string private constant ERROR_CANNOT_REDEEM_ZERO = "REDEMPTIONS_CANNOT_REDEEM_ZERO";
string private constant ERROR_INSUFFICIENT_BALANCE = "REDEMPTIONS_INSUFFICIENT_BALANCE";
string private constant ERROR_THIS_CONTRACT_CANNOT_REDEEM = "REDEMPTIONS_THIS_CONTRACT_CANNOT_REDEEM";
string private constant ERROR_VAULT_CANNOT_REDEEM = "REDEMPTIONS_VAULT_CANNOT_REDEEM";
string private constant ERROR_TOKEN_CANNOT_REDEEM = "REDEMPTIONS_TOKEN_CANNOT_REDEEM";
string private constant ERROR_CANNOT_DESTROY_TOKENS= "REDEMPTIONS_CANNOT_DESTROY_TOKENS";
string private constant ERROR_TOKEN_MANAGER_CANNOT_REDEEM = "REDEMPTIONS_TOKEN_MANAGER_CANNOT_REDEEM";

mapping(address => bool) public tokens;
address[] public vaultTokens;

MiniMeToken public redeemableToken;
Vault public vault;
TokenManager public tokenManager;

mapping(address => bool) public tokenAdded;
address[] public vaultTokens;

event Redeem(address indexed receiver, uint256 amount);

/**
* @notice Initialize
* @notice Initialize Redemptions app contract
* @param _vault Address of the vault
* @param _redeemableToken MiniMeToken address
* @param _tokenManager TokenManager address
* @param _vaultTokens token addreses
*/
function initialize(Vault _vault, MiniMeToken _redeemableToken, address[] memory _vaultTokens) external onlyInit {
function initialize(Vault _vault, TokenManager _tokenManager, address[] _vaultTokens) external onlyInit {
initialized();

require(isContract(_vault), ERROR_VAULT_NOT_CONTRACT);
require(isContract(_tokenManager), ERROR_TOKEN_MANAGER_NOT_CONTRACT);

vault = _vault;
redeemableToken = _redeemableToken;
tokenManager = _tokenManager;
vaultTokens = _vaultTokens;

for (uint i = 0; i < _vaultTokens.length; i++) {
tokens[_vaultTokens[i]] = true;
vaultTokens.push(_vaultTokens[i]); // TODO: Can just do 'vaultTokens = _vaultTokens;' but not if we expect vault tokens to be populated before init
tokenAdded[_vaultTokens[i]] = true;
}
}

/**
* @notice Add token `_token` to vault
* @param _token token address
*/
function addVaultToken(address _token) external auth(ADD_TOKEN_ROLE) {
require(_token != address(redeemableToken), ERROR_REDEEMABLE_TOKEN);
require(!tokens[_token], ERROR_TOKEN_ALREADY_ADDED);
require(_token != address(tokenManager), ERROR_TOKEN_MANAGER);
require(!tokenAdded[_token], ERROR_TOKEN_ALREADY_ADDED);
require(isContract(_token), ERROR_TOKEN_NOT_CONTRACT);

tokens[_token] = true;
tokenAdded[_token] = true;
vaultTokens.push(_token);
}

/**
* @notice Remove token `_token` from vault
* @param _token token address
*/
function removeVaultToken(address _token) external auth(REMOVE_TOKEN_ROLE) {
require(tokens[_token], ERROR_NOT_VAULT_TOKEN);
require(tokenAdded[_token], ERROR_NOT_VAULT_TOKEN);

tokenAdded[_token] = false;
vaultTokens.deleteItem(_token);
}

/**
* @notice Redeem `_amount` tokens from vault
* @param _amount amount of tokens
*/
function redeem(uint256 _amount) external auth(REDEEM_ROLE) {
require(_amount > 0, ERROR_CANNOT_REDEEM_ZERO);
require(redeemableToken.balanceOf(msg.sender) >= _amount, ERROR_INSUFFICIENT_BALANCE);
require(msg.sender != this, ERROR_THIS_CONTRACT_CANNOT_REDEEM);
require(msg.sender != address(vault), ERROR_VAULT_CANNOT_REDEEM);
require(msg.sender != address(redeemableToken), ERROR_TOKEN_CANNOT_REDEEM);

require(tokenManager.spendableBalanceOf(msg.sender) >= _amount, ERROR_INSUFFICIENT_BALANCE);

uint256 redemptionAmount;

for (uint256 i = 0; i < vaultTokens.length; i++) {
redemptionAmount = _amount.mul(vault.balance(vaultTokens[i])).div(redeemableToken.totalSupply);
redemptionAmount = _amount.mul(vault.balance(vaultTokens[i])).div(tokenManager.token().totalSupply());
vault.transfer(vaultTokens[i], msg.sender, redemptionAmount);
}

require(redeemableToken.destroyTokens(msg.sender, _amount), ERROR_CANNOT_DESTROY_TOKENS);
tokenManager.burn(msg.sender, _amount);

emit Redeem(msg.sender, _amount);
}

/**
* @notice Get tokens from vault
* @return token addresses
*/
function getVaultTokens() public view returns (address[]) {
return vaultTokens;
}

}
29 changes: 19 additions & 10 deletions contracts/Template.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import "@aragon/os/contracts/lib/ens/PublicResolver.sol";
import "@aragon/os/contracts/apm/APMNamehash.sol";

import "@aragon/apps-voting/contracts/Voting.sol";
import "@aragon/apps-vault/contracts/Vault.sol";
import "@aragon/apps-token-manager/contracts/TokenManager.sol";
import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol";

import "./CounterApp.sol";
import "./Redemptions.sol";


contract TemplateBase is APMNamehash {
Expand Down Expand Up @@ -67,29 +68,37 @@ contract Template is TemplateBase {
acl.createPermission(this, dao, dao.APP_MANAGER_ROLE(), this);

address root = msg.sender;
bytes32 appId = apmNamehash("redemptions");
bytes32 redemptionsAppId = apmNamehash("redemptions");
bytes32 votingAppId = apmNamehash("voting");
bytes32 tokenManagerAppId = apmNamehash("token-manager");
bytes32 vaultAppId = apmNamehash("vault");

CounterApp app = CounterApp(dao.newAppInstance(appId, latestVersionAppBase(appId)));

Vault vault = Vault(dao.newAppInstance(vaultAppId, latestVersionAppBase(vaultAppId)));
Redemptions redemptions = Redemptions(dao.newAppInstance(redemptionsAppId, latestVersionAppBase(redemptionsAppId)));
Voting voting = Voting(dao.newAppInstance(votingAppId, latestVersionAppBase(votingAppId)));
TokenManager tokenManager = TokenManager(dao.newAppInstance(tokenManagerAppId, latestVersionAppBase(tokenManagerAppId)));

MiniMeToken token = tokenFactory.createCloneToken(MiniMeToken(0), 0, "App token", 0, "APP", true);
MiniMeToken token = tokenFactory.createCloneToken(MiniMeToken(0), 0, "Rdemable token", 0, "RDT", true);
token.changeController(tokenManager);

app.initialize();
tokenManager.initialize(token, true, 0);

// Initialize apps
vault.initialize();
tokenManager.initialize(token, true, 0);
redemptions.initialize(vault, tokenManager, new address[](0));
voting.initialize(token, 50 * PCT, 20 * PCT, 1 days);

acl.createPermission(this, tokenManager, tokenManager.MINT_ROLE(), this);
tokenManager.mint(root, 1); // Give one token to root

acl.createPermission(ANY_ENTITY, voting, voting.CREATE_VOTES_ROLE(), root);
acl.createPermission(tokenManager, voting, voting.CREATE_VOTES_ROLE(), root);

acl.createPermission(redemptions, vault, vault.TRANSFER_ROLE(), root);

acl.createPermission(tokenManager, redemptions, redemptions.REDEEM_ROLE(), root);
acl.createPermission(voting, redemptions, redemptions.ADD_TOKEN_ROLE(), root);
acl.createPermission(voting, redemptions, redemptions.REMOVE_TOKEN_ROLE(), root);

acl.createPermission(voting, app, app.INCREMENT_ROLE(), voting);
acl.createPermission(ANY_ENTITY, app, app.DECREMENT_ROLE(), root);
acl.grantPermission(voting, tokenManager, tokenManager.MINT_ROLE());

// Clean up permissions
Expand Down
10 changes: 10 additions & 0 deletions contracts/test/BasicErc20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pragma solidity ^0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract BasicErc20 is ERC20 {

constructor() public {
_mint(msg.sender, 1000e18);
}
}
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
"version": "1.0.0",
"description": "",
"dependencies": {
"@aragon/os": "^4.0.1",
"@aragon/apps-shared-minime": "^1.0.0",
"@aragon/apps-token-manager": "2.0.0",
"@aragon/apps-vault": "4.1.0",
"@aragon/apps-voting": "2.0.0",
"@aragon/apps-vault": "2.0.0"
"@aragon/os": "^4.0.1",
"openzeppelin-solidity": "2.0.1"
},
"devDependencies": {
"@aragon/cli": "^5.4.0",
"@aragon/test-helpers": "^1.0.1",
"babel-eslint": "^10.0.1",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-2": "^6.24.1",
"babel-preset-stage-3": "^6.17.0",
"babel-register": "^6.23.0",
"cross-env": "^5.2.0",
"eslint": "^5.13.0",
"eslint-config-prettier": "^4.0.0",
Expand Down
Loading