Skip to content

Commit

Permalink
zeppelin changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Federico Martín Alconada Verzini committed Nov 29, 2017
1 parent 1af2da1 commit bd25073
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 68 deletions.
14 changes: 13 additions & 1 deletion contracts/MigrationAgent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ contract QiibeeMigrationTokenInterface {
}

contract MigrationAgent is Ownable {
using SafeMath for uint256;

address public qbxSourceToken;
address public qbxTargetToken;
uint256 public tokenSupply;

event SupplyUpdated(uint256 _value);

function MigrationAgent(address _qbxSourceToken) {
require(QiibeeToken(_qbxSourceToken).migrationAgent() == address(0));
tokenSupply = QiibeeToken(_qbxSourceToken).totalSupply();
Expand All @@ -34,7 +37,7 @@ contract MigrationAgent is Ownable {
function migrateFrom(address _from, uint256 _value) public {
require(msg.sender == qbxSourceToken);
require(qbxTargetToken != address(0));

updateSupply();
safetyInvariantCheck(_value); // qbxSourceToken has already been updated, but corresponding QBX have not been created in the qbxTargetToken contract yet
QiibeeMigrationTokenInterface(qbxTargetToken).createToken(_from, _value);
safetyInvariantCheck(0); // totalSupply invariant must hold
Expand All @@ -50,4 +53,13 @@ contract MigrationAgent is Ownable {
qbxTargetToken = address(0);
tokenSupply = 0;
}

function updateSupply() public {
QiibeeToken sourceToken = QiibeeToken(qbxSourceToken);
tokenSupply = tokenSupply.add(sourceToken.newTokens()).sub(sourceToken.burntTokens());
sourceToken.resetNewTokens();
sourceToken.resetBurntTokens();
// tokenSupply = QiibeeToken(qbxSourceToken).totalSupply();
SupplyUpdated(tokenSupply);
}
}
18 changes: 9 additions & 9 deletions contracts/QiibeePresale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
uint256 public tokensDistributed; // tokens distributed to pools
uint256 public tokensSold; // qbx minted (and sold)

uint64 public vestFromTime = 1530316800; // start time for vested tokens (equiv. to 30/06/2018)
uint64 public vestFromTime = 1530316800; // start time for vested tokens (equiv. to 30/06/2018 12:00:00 AM GMT)

mapping (address => uint256) public balances; // balance of wei invested per investor
mapping (address => AccreditedInvestor) public accredited; // whitelist of investors
Expand All @@ -75,11 +75,6 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
event NewAccreditedInvestor(address indexed from, address indexed buyer);
event TokenDistributed(address indexed beneficiary, uint256 tokens);

modifier afterFundraising {
require(now > endTime || weiRaised >= cap);
_;
}

/*
* @dev Constructor.
* @param _startTime see `startTimestamp`
Expand All @@ -94,6 +89,7 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
function QiibeePresale(
uint256 _startTime,
uint256 _endTime,
address _token,
uint256 _rate,
uint256 _cap,
uint256 _distributionCap,
Expand All @@ -107,10 +103,12 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
require(_distributionCap > 0);
require(_maxGasPrice > 0);
require(_minBuyingRequestInterval > 0);
require(_token != address(0));

distributionCap = _distributionCap;
maxGasPrice = _maxGasPrice;
minBuyingRequestInterval = _minBuyingRequestInterval;
token = QiibeeTokenInterface(_token);
}

/*
Expand Down Expand Up @@ -163,11 +161,12 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
* @param _cliff duration in seconds of the cliff in which tokens will begin to vest.
* @param _vesting duration in seconds of the vesting in which tokens will vest.
*/
function distributeTokens(address _beneficiary, uint256 _tokens, uint64 _cliff, uint64 _vesting, bool _revokable, bool _burnsOnRevoke) public onlyOwner whenNotPaused afterFundraising {
function distributeTokens(address _beneficiary, uint256 _tokens, uint64 _cliff, uint64 _vesting, bool _revokable, bool _burnsOnRevoke) public onlyOwner whenNotPaused {
require(_beneficiary != address(0));
require(_tokens > 0);
require(_vesting >= _cliff);
require(!isFinalized);
require(hasEnded());

// check distribution cap limit
uint256 totalDistributed = tokensDistributed.add(_tokens);
Expand Down Expand Up @@ -196,6 +195,7 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
require(vesting >= cliff);
require(minInvest > 0);
require(maxCumulativeInvest > 0);
require(minInvest <= maxCumulativeInvest);

accredited[investor] = AccreditedInvestor(cliff, vesting, revokable, burnsOnRevoke, minInvest, maxCumulativeInvest);

Expand All @@ -208,7 +208,7 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
*/
function isAccredited(address investor) public constant returns (bool) {
AccreditedInvestor storage data = accredited[investor];
return data.minInvest > 0; //TODO: is there any way to properly check this?
return data.minInvest > 0;
}

/*
Expand Down Expand Up @@ -248,7 +248,7 @@ contract QiibeePresale is CappedCrowdsale, FinalizableCrowdsale, Pausable {
}

/*
* @dev sets the token that the presale will use. Call only be called by the owner and
* @dev sets the token that the presale will use. Can only be called by the owner and
* before the presale starts.
*/
function setToken(address tokenAddress) onlyOwner {
Expand Down
65 changes: 54 additions & 11 deletions contracts/QiibeeToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import "zeppelin-solidity/contracts/token/VestedToken.sol";
contract MigrationAgentInterface {
function migrateFrom(address _from, uint256 _value);
function setSourceToken(address _qbxSourceToken);
function updateSupply();
function qbxSourceToken() returns (address);
}

/**
Expand All @@ -18,19 +20,21 @@ contract MigrationAgentInterface {
the atto. The token call be migrated to a new token by calling the `migrate()` function.
*/
contract QiibeeToken is BurnableToken, PausableToken, VestedToken, MintableToken {
using SafeMath for uint256;

string public constant SYMBOL = "QBX";

string public constant NAME = "qiibeeCoin";

uint8 public constant DECIMALS = 18;
string public constant symbol = "QBX";
string public constant name = "qiibeeCoin";
uint8 public constant decimals = 18;

// migration vars
uint256 public totalMigrated;
uint256 public newTokens; // amount of tokens minted after migrationAgent has been set
uint256 public burntTokens; // amount of tokens burnt after migrationAgent has been set
address public migrationAgent;
address public migrationMaster;

event Migrate(address indexed _from, address indexed _to, uint256 _value);
event NewVestedToken(address indexed from, address indexed to, uint256 value, uint256 grantId);

modifier onlyMigrationMaster {
require(msg.sender == migrationMaster);
Expand Down Expand Up @@ -75,6 +79,7 @@ contract QiibeeToken is BurnableToken, PausableToken, VestedToken, MintableToken
)
);

NewVestedToken(msg.sender, _to, _value, count - 1);
return mint(_to, _value); //mint tokens
}

Expand All @@ -98,7 +103,9 @@ contract QiibeeToken is BurnableToken, PausableToken, VestedToken, MintableToken
@param _agent The address of the MigrationAgent contract
*/
function setMigrationAgent(address _agent) public onlyMigrationMaster {
require(MigrationAgentInterface(_agent).qbxSourceToken() == address(this));
require(migrationAgent == address(0));
require(_agent != address(0));
migrationAgent = _agent;
}

Expand All @@ -110,14 +117,31 @@ contract QiibeeToken is BurnableToken, PausableToken, VestedToken, MintableToken
require(migrationAgent != address(0));
require(_value != 0);
require(_value <= balances[msg.sender]);

balances[msg.sender] -= _value;
totalSupply -= _value;
totalMigrated += _value;
require(_value <= transferableTokens(msg.sender, uint64(now)));
balances[msg.sender] = balances[msg.sender].sub(_value);
totalSupply = totalSupply.sub(_value);
totalMigrated = totalMigrated.add(_value);
MigrationAgentInterface(migrationAgent).migrateFrom(msg.sender, _value);
Migrate(msg.sender, migrationAgent, _value);
}

/**
* @dev Overrides mint() function so as to keep track of the tokens minted after the
* migrationAgent has been set. This is to ensure that the migration agent has always the
* totalTokens variable up to date. This prevents the failure of the safetyInvariantCheck().
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
bool mint = super.mint(_to, _amount);
if (mint && migrationAgent != address(0)) {
newTokens = newTokens.add(_amount);
}
return mint;
}


/*
* @dev Changes the migration master.
* @param _master The address of the migration master.
Expand All @@ -127,11 +151,30 @@ contract QiibeeToken is BurnableToken, PausableToken, VestedToken, MintableToken
migrationMaster = _master;
}

/*
* @dev Resets newTokens to zero. Can only be called by the migrationAgent
*/
function resetNewTokens() {
require(msg.sender == migrationAgent);
newTokens = 0;
}

/*
* @dev Resets burntTokens to zero. Can only be called by the migrationAgent
*/
function resetBurntTokens() {
require(msg.sender == migrationAgent);
burntTokens = 0;
}

/*
* @dev Burns a specific amount of tokens.
* @param _value The amount of tokens to be burnt.
*/
function burn(uint256 _value) whenNotPaused public {
super.burn(_value);
function burn(uint256 _value) whenNotPaused onlyOwner public {
super.burn(_value);
if (migrationAgent != address(0)) {
burntTokens = burntTokens.add(_value);
}
}
}
4 changes: 2 additions & 2 deletions migrations/3_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ module.exports = function(deployer) {
console.log('MULTISIG WALLET IS: ', multisig.address);
foundationWallet = multisig.address;
deployer.deploy(QiibeePresale, startTimePresale, endTimePresale, rate, presalecap, distributionCap, maxGasPrice, minBuyingRequestInterval, foundationWallet);
deployer.deploy(QiibeeToken, migrationMaster);
});
deployer.deploy(QiibeeToken, migrationMaster);

deployer.deploy(QiibeeCrowdsale, startTimeCrowdsale, endTimeCrowdsale, rate, goal, cap, minInvest, maxCumulativeInvest, maxGasPrice, minBuyingRequestInterval, wallet);
// deployer.deploy(QiibeeCrowdsale, startTimeCrowdsale, endTimeCrowdsale, rate, goal, cap, minInvest, maxCumulativeInvest, maxGasPrice, minBuyingRequestInterval, wallet);
};
5 changes: 3 additions & 2 deletions test/QiibeePresale.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function assertExpectedException(e) {
}
}

contract('QiibeePresale', function ([owner, wallet, migrationMaster]) {
contract('QiibeePresale', function ([owner, tokenOwner, wallet, migrationMaster]) {

const defaultTimeDelta = duration.days(1); // time delta used in time calculations (for start, end1 & end2)
const defaults = {
Expand All @@ -45,7 +45,8 @@ contract('QiibeePresale', function ([owner, wallet, migrationMaster]) {
minBuyingRequestInterval = params.minBuyingRequestInterval === undefined ? defaults.minBuyingRequestInterval : params.minBuyingRequestInterval,
wallet = params.wallet === undefined ? defaults.wallet : params.foundationWallet;

return await QiibeePresale.new(startTime, endTime, rate, cap, distributionCap, maxGasPrice, minBuyingRequestInterval, wallet, {from: owner});
let token = await QiibeeToken.new(migrationMaster, {from: tokenOwner});
return await QiibeePresale.new(startTime, endTime, token.address, rate, cap, distributionCap, maxGasPrice, minBuyingRequestInterval, wallet, {from: owner});
}

it('can create a qiibee presale', async function () {
Expand Down
9 changes: 5 additions & 4 deletions test/QiibeePresaleGenTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,13 @@ contract('QiibeePresale property-based test', function(accounts) {
foundationWallet: gen.getAccount(input.presale.foundationWallet),
};

let token = await QiibeeToken.new(migrationMaster, {from: ownerAddress});
await token.pause({from: ownerAddress});

let presale = await QiibeePresale.new(
presaleData.startTime,
presaleData.endTime,
token.address,
presaleData.rate,
presaleData.cap,
presaleData.distributionCap,
Expand All @@ -97,11 +101,8 @@ contract('QiibeePresale property-based test', function(accounts) {
{from: ownerAddress}
);

let token = await QiibeeToken.new(migrationMaster, {from: ownerAddress});
await token.pause({from: ownerAddress});

//set token to presale
await presale.setToken(token.address, {from: ownerAddress});
// await presale.setToken(token.address, {from: ownerAddress});
await token.transferOwnership(presale.address,{ from: ownerAddress});

assert.equal(false, shouldThrow, 'create Presale should have thrown but it did not');
Expand Down

0 comments on commit bd25073

Please sign in to comment.