Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion contracts/schemes/ReputationFromToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ contract ReputationFromToken {
/**
* @dev redeem function
* @param _beneficiary the beneficiary address to redeem for
* @return uint256 minted reputation
*/
function redeem(address _beneficiary) public {
function redeem(address _beneficiary) public returns(uint256) {
require(avatar != Avatar(0), "should initialize first");
require(redeems[msg.sender] == false, "redeeming twice from the same account is not allowed");
redeems[msg.sender] = true;
Expand All @@ -53,5 +54,6 @@ contract ReputationFromToken {
avatar.owner())
.mintReputation(tokenAmount, _beneficiary, address(avatar)), "mint reputation should succeed");
emit Redeem(_beneficiary, msg.sender, tokenAmount);
return tokenAmount;
}
}
61 changes: 61 additions & 0 deletions contracts/utils/RepAllocation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
pragma solidity ^0.5.4;

import "openzeppelin-solidity/contracts/ownership/Ownable.sol";


/**
* @title reputation allocation contract
* This scheme can be used to allocate a pre define amount of reputation to whitelisted
* beneficiaries.
* this contract can be used as the rep mapping contract for RepitationFromToken contract.
*/
contract RepAllocation is Ownable {


// beneficiary -> amount
mapping(address => uint256) public reputationAllocations;
bool public isFreeze;

event BeneficiaryAddressAdded(address indexed _beneficiary, uint256 indexed _amount);

/**
* @dev addBeneficiary function
* @param _beneficiary to be whitelisted
*/
function addBeneficiary(address _beneficiary, uint256 _amount) public onlyOwner {
require(!isFreeze, "can add beneficiary only if not disable");

if (reputationAllocations[_beneficiary] == 0) {
reputationAllocations[_beneficiary] = _amount;
emit BeneficiaryAddressAdded(_beneficiary, _amount);
}
}

/**
* @dev add addBeneficiaries function
* @param _beneficiaries addresses
*/
function addBeneficiaries(address[] memory _beneficiaries, uint256[] memory _amounts) public onlyOwner {
require(_beneficiaries.length == _amounts.length);
for (uint256 i = 0; i < _beneficiaries.length; i++) {
addBeneficiary(_beneficiaries[i], _amounts[i]);
}
}

/**
* @dev freeze function
* cannot defreeze
*/
function freeze() public onlyOwner {
isFreeze = true;
}

/**
* @dev get balanceOf _beneficiary function
* @param _beneficiary addresses
*/
function balanceOf(address _beneficiary) public view returns(uint256) {
return reputationAllocations[_beneficiary];
}

}
44 changes: 22 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@daostack/arc",
"version": "0.0.1-rc.22",
"version": "0.0.1-rc.23",
"description": "A platform for building DAOs",
"files": [
"contracts/",
Expand Down
55 changes: 43 additions & 12 deletions test/reputationfromtoken.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@ const DaoCreator = artifacts.require("./DaoCreator.sol");
const ControllerCreator = artifacts.require("./ControllerCreator.sol");
const constants = require('./constants');
var ReputationFromToken = artifacts.require("./ReputationFromToken.sol");
var ExternalTokenLockerMock = artifacts.require("./ExternalTokenLockerMock.sol");
var RepAllocation = artifacts.require("./RepAllocation.sol");

var PolkaCurve = artifacts.require("./PolkaCurve.sol");

const setup = async function (accounts, _initialize = true) {
var testSetup = new helpers.TestSetup();
var controllerCreator = await ControllerCreator.new({gas: constants.ARC_GAS_LIMIT});
testSetup.daoCreator = await DaoCreator.new(controllerCreator.address,{gas:constants.ARC_GAS_LIMIT});
testSetup.org = await helpers.setupOrganization(testSetup.daoCreator,accounts[0],1000,1000);
testSetup.extetnalTokenLockerMock = await ExternalTokenLockerMock.new();
await testSetup.extetnalTokenLockerMock.lock(100,accounts[0]);
await testSetup.extetnalTokenLockerMock.lock(200,accounts[1]);
await testSetup.extetnalTokenLockerMock.lock(300,accounts[2]);
testSetup.repAllocation = await RepAllocation.new();
await testSetup.repAllocation.addBeneficiary(accounts[0],100);
await testSetup.repAllocation.addBeneficiary(accounts[1],200);
await testSetup.repAllocation.addBeneficiary(accounts[2],300);

testSetup.reputationFromToken = await ReputationFromToken.new();
testSetup.curve = await PolkaCurve.new();
if (_initialize === true) {
await testSetup.reputationFromToken.initialize(testSetup.org.avatar.address,
testSetup.extetnalTokenLockerMock.address,
testSetup.repAllocation.address,
testSetup.curve.address);
}

Expand All @@ -29,25 +30,55 @@ const setup = async function (accounts, _initialize = true) {
return testSetup;
};

contract('ReputationFromToken', accounts => {
contract('ReputationFromToken and RepAllocation', accounts => {
it("initialize", async () => {
let testSetup = await setup(accounts);
assert.equal(await testSetup.reputationFromToken.tokenContract(),testSetup.extetnalTokenLockerMock.address);
assert.equal(await testSetup.reputationFromToken.tokenContract(),testSetup.repAllocation.address);
assert.equal(await testSetup.reputationFromToken.avatar(),testSetup.org.avatar.address);
assert.equal(await testSetup.reputationFromToken.curve(),testSetup.curve.address);
});

it("externalLockingMock is onlyOwner", async () => {
it("repAllocation is onlyOwner", async () => {
let testSetup = await setup(accounts);
try {
await testSetup.extetnalTokenLockerMock.lock(1030,accounts[3],{from:accounts[1]});
assert(false, "externalLockingMock is onlyOwner");
await testSetup.repAllocation.addBeneficiary(accounts[3],1030,{from:accounts[1]});
assert(false, "repAllocation is onlyOwner");
} catch(error) {
helpers.assertVMException(error);
}

});

it("repAllocation cannot allocate after freeze", async () => {
let testSetup = await setup(accounts);
await testSetup.repAllocation.addBeneficiary(accounts[3],1030);
await testSetup.repAllocation.freeze();


try {
await testSetup.repAllocation.addBeneficiary(accounts[4],1030);
assert(false, "cannot allocate after freeze");
} catch(error) {
helpers.assertVMException(error);
}

});

it("repAllocation cannot allocate twice", async () => {
let testSetup = await setup(accounts);
assert(await testSetup.repAllocation.balanceOf(accounts[1]),200);
await testSetup.repAllocation.addBeneficiary(accounts[1],1030);
assert(await testSetup.repAllocation.balanceOf(accounts[1]),200);
});

it("repAllocation addBeneficiaries", async () => {
let testSetup = await setup(accounts);
let tx = await testSetup.repAllocation.addBeneficiaries([accounts[3],accounts[4]],[300,400]);
assert.equal(tx.logs.length,2);
});



it("redeem", async () => {
let testSetup = await setup(accounts);
var tx = await testSetup.reputationFromToken.redeem(accounts[1]);
Expand Down Expand Up @@ -84,7 +115,7 @@ contract('ReputationFromToken', accounts => {
let testSetup = await setup(accounts);
try {
await testSetup.reputationFromToken.initialize(testSetup.org.avatar.address,
testSetup.extetnalTokenLockerMock.address,
testSetup.repAllocation.address,
testSetup.curve.address
);
assert(false, "cannot initialize twice");
Expand Down