From 2261e508446293fb2764187719fed42fb9b092fc Mon Sep 17 00:00:00 2001 From: Ivan Kamakin Date: Mon, 21 Aug 2017 01:08:29 +0300 Subject: [PATCH 01/12] Improve contract abstraction with inheritance and composition --- DolphinPresaleToken.sol | 367 ++++++++++++++++++++++++---------------- 1 file changed, 219 insertions(+), 148 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index 71f50c9..c67bc52 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -27,17 +27,52 @@ library SafeMath { } -contract CMCEthereumTicker is usingOraclize { +contract Ownable { + address public owner; + + function Ownable() { + owner = msg.sender; + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function transferOwnership(address newOwner) onlyOwner { + if (newOwner != address(0)) { + owner = newOwner; + } + } + +} + +contract Freezable is Ownable { + + bool frozen = false; + + modifier whileNotFrozen {assert(frozen == true); _;} + + function freeze() onlyOwner { + frozen = true; + } + + function unfreeze() onlyOwner { + frozen = false; + } + +} + +contract CMCEthereumTicker is usingOraclize, Ownable { using SafeMath for uint; uint centsPerETH; - uint delay; + uint256 delay; bool enabled; - address parent; address manager; - modifier onlyParentOrManager() { require(msg.sender == parent || msg.sender == manager); _; } + modifier onlyOwnerOrManager() { require(msg.sender == owner || msg.sender == manager); _; } event newOraclizeQuery(string description); event newPriceTicker(string price); @@ -46,7 +81,6 @@ contract CMCEthereumTicker is usingOraclize { function CMCEthereumTicker(address _manager, uint256 _delay) { oraclize_setProof(proofType_NONE); enabled = false; - parent = msg.sender; manager = _manager; delay = _delay; } @@ -60,7 +94,7 @@ contract CMCEthereumTicker is usingOraclize { } function enable() - onlyParentOrManager + onlyOwnerOrManager { require(enabled == false); enabled = true; @@ -68,7 +102,7 @@ contract CMCEthereumTicker is usingOraclize { } function disable() - onlyParentOrManager + onlyOwnerOrManager { require(enabled == true); enabled = false; @@ -102,7 +136,7 @@ contract CMCEthereumTicker is usingOraclize { } function payToManager(uint _amount) - onlyParentOrManager + onlyOwnerOrManager { manager.transfer(_amount); } @@ -111,55 +145,66 @@ contract CMCEthereumTicker is usingOraclize { } -contract PresaleToken { - using SafeMath for uint256; - - function PresaleToken(uint256 _limitUSD, uint256 _priceCents) { - tokenManager = msg.sender; - priceCents = _priceCents; - maxSupply = (uint(10)**decimals).mul(100).mul(_limitUSD).div(_priceCents); +contract TickerController is Ownable{ + + //Ticker contract + CMCEthereumTicker priceTicker; + + function createTicker(uint256 _delay) + onlyOwner + { + priceTicker = new CMCEthereumTicker(owner, _delay); } - enum Phase { - Created, - Running, - Finished, - Finalized, - Migrating, - Migrated + function attachTicker(address _tickerAddress) + onlyOwner + { + priceTicker = CMCEthereumTicker(_tickerAddress); } - // maximum token supply - uint public maxSupply; - // price of 1 token in USD cents - uint public priceCents; - // Ticker contract - CMCEthereumTicker priceTicker; - + function enableTicker() + onlyOwner + { + priceTicker.enable(); + } - //Phase on contract creation - Phase public currentPhase = Phase.Created; - - // amount of tokens already sold - uint supply = 0; - // amount of tokens given via giveTokens - uint public givenSupply = 0; + function disableTicker() + onlyOwner + { + priceTicker.disable(); + } + + function sendToTicker() payable + onlyOwner + { + assert(address(priceTicker) != 0x0); + address(priceTicker).transfer(msg.value); + } + + function withdrawFromTicker(uint _amount) + onlyOwner + { + assert(address(priceTicker) != 0x0); + priceTicker.payToManager(_amount); + } + + function tickerAddress() constant returns (address) { + return address(priceTicker); + } + + function getCentsPerETH() constant returns (uint) { + return priceTicker.getCentsPerETH(); + } +} - // Token manager has exclusive priveleges to call administrative - // functions on this contract. - address public tokenManager; - // Migration manager has privileges to burn tokens during migration. - address public migrationManager; +contract DBIPToken is Freezable { + using SafeMath for uint256; - // The last buyer is the buyer that purchased - // tokens that add up to the maxSupply or more. - // During the presale finalization they are refunded - // the excess USD according to lastCentsPerETH. - address lastBuyer; - uint refundValue = 0; - uint lastCentsPerETH = 0; + //ERC20 Fields + + uint supply; - //ERC 20 Containers + //ERC20 Containers mapping (address => uint256) private balance; mapping (address => mapping(address => uint256)) private allowed; @@ -167,18 +212,11 @@ contract PresaleToken { string public constant name = "Dolphin Presale Token"; string public constant symbol = "DBIP"; uint8 public constant decimals = 18; - - //External access modifiers - modifier onlyTokenManager() { require(msg.sender == tokenManager); _; } - modifier onlyMigrationManager() { require(msg.sender == migrationManager); _; } - //Presale phase modifiers - modifier onlyWhileCreated() {assert(currentPhase == Phase.Created); _;} - modifier onlyWhileRunning() {assert(currentPhase == Phase.Running); _;} - modifier onlyWhileFinished() {assert(currentPhase == Phase.Finished); _;} - modifier onlyWhileFinalized() {assert(currentPhase == Phase.Finalized); _;} - modifier onlyBeforeMigration() {assert(currentPhase != Phase.Migrating && currentPhase != Phase.Migrated); _;} - modifier onlyWhileMigrating() {assert(currentPhase == Phase.Migrating); _;} + //ERC20 events + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + //Modifier to defend against shortened address attack @@ -187,22 +225,21 @@ contract PresaleToken { _; } - //Presale events - event LogBuy(address indexed owner, uint value, uint centsPerETH); - event LogMigrate(address indexed owner, uint value); - event LogPhaseSwitch(Phase newPhase); + function DBIPToken (uint256 _initial_supply) { + balance[owner] = _initial_supply; + supply = _initial_supply; + } - //ERC20 events - event Transfer(address indexed _from, address indexed _to, uint256 _value); - event Approval(address indexed _owner, address indexed _spender, uint256 _value); - - + //Method to generate additional tokens. Can only be called by parent contract. - function() payable { - buyTokens(msg.sender); + function raiseSupply (uint256 _new_supply) + onlyOwner + { + uint256 increase = _new_supply.sub(supply); + balance[owner] = balance[owner].add(increase); + supply = supply.add(increase); } - ///ERC20 Interface functions function balanceOf(address _owner) constant returns (uint256 balanceOf) { @@ -217,7 +254,7 @@ contract PresaleToken { return allowed[_owner][_spender]; } - function transfer(address _to, uint256 _value) onlyBeforeMigration minimalPayloadSize(2 * 32) returns (bool success) + function transfer(address _to, uint256 _value) whileNotFrozen minimalPayloadSize(2 * 32) returns (bool success) { assert(_value > 0); @@ -228,7 +265,7 @@ contract PresaleToken { return true; } - function approve(address _spender, uint256 _value) onlyBeforeMigration returns (bool success) { + function approve(address _spender, uint256 _value) whileNotFrozen returns (bool success) { assert((_value == 0) || (allowed[msg.sender][_spender] == 0)); allowed[msg.sender][_spender] = _value; @@ -238,7 +275,7 @@ contract PresaleToken { } - function transferFrom(address _from, address _to, uint256 _value) onlyBeforeMigration minimalPayloadSize(3 * 32) returns (bool success) { + function transferFrom(address _from, address _to, uint256 _value) whileNotFrozen minimalPayloadSize(3 * 32) returns (bool success) { assert(_value > 0); @@ -250,8 +287,85 @@ contract PresaleToken { return true; } + +} + +contract PresaleToken is TickerController { + using SafeMath for uint256; + function PresaleToken(uint256 _limitUSD, uint256 _priceCents) { + priceCents = _priceCents; + maxSupply = (uint(10)**decimals).mul(100).mul(_limitUSD).div(_priceCents); + token = new DBIPToken(maxSupply); + assert(decimals == token.decimals()); + } + + enum Phase { + Created, + Running, + Finished, + Finalized, + Migrating, + Migrated + } + + // token + DBIPToken token; + // maximum token supply + uint public maxSupply; + // price of 1 token in USD cents + uint public priceCents; + // Decimals of token needed for most operations + uint public decimals = 18; + + + //Phase on contract creation + Phase public currentPhase = Phase.Created; + + // amount of tokens already sold + uint public funded = 0; + // amount of tokens given via giveTokens + uint public given = 0; + + // Migration manager has privileges to burn tokens during migration. + address public migrationManager; + + // Used to check whether the address has already migrated + mapping (address => bool) migrated; + + // The last buyer is the buyer that purchased + // tokens that add up to the maxSupply or more. + // During the presale finalization they are refunded + // the excess USD according to lastCentsPerETH. + address lastBuyer; + uint refundValue = 0; + uint lastCentsPerETH = 0; + + // Whether the funding cap was already raised + bool capRaised = false; + + //External access modifiers + modifier onlyMigrationManager() { require(msg.sender == migrationManager); _; } + + //Presale phase modifiers + modifier onlyWhileCreated() {assert(currentPhase == Phase.Created); _;} + modifier onlyWhileRunning() {assert(currentPhase == Phase.Running); _;} + modifier onlyWhileFinished() {assert(currentPhase == Phase.Finished); _;} + modifier onlyWhileFinalized() {assert(currentPhase == Phase.Finalized); _;} + modifier onlyBeforeMigration() {assert(currentPhase != Phase.Migrating && currentPhase != Phase.Migrated); _;} + modifier onlyWhileMigrating() {assert(currentPhase == Phase.Migrating); _;} + + //Presale events + event LogBuy(address indexed owner, uint value, uint centsPerETH); + event LogGive(address indexed owner, uint valuem, string reason); + event LogMigrate(address indexed owner, uint value); + event LogPhaseSwitch(Phase newPhase); + ///Presale-specific functions + + function() payable { + buyTokens(msg.sender); + } function buyTokens(address _buyer) payable onlyWhileRunning @@ -265,21 +379,21 @@ contract PresaleToken { var newTokens = msg.value.mul(centsPerETH).mul(uint(10)**decimals).div(priceCents.mul(1 ether / 1 wei)); assert(newTokens != 0); - if (supply.add(newTokens) > maxSupply) { - var remainder = maxSupply.sub(supply); - balance[_buyer] = balance[_buyer].add(remainder); - supply = supply.add(remainder); + if (funded.add(newTokens) > maxSupply) { + var remainder = maxSupply.sub(funded); + token.transfer(_buyer, remainder); + funded = funded.add(remainder); lastBuyer = _buyer; refundValue = newTokens.sub(remainder); LogBuy(_buyer, remainder, centsPerETH); } else { - balance[_buyer] = balance[_buyer].add(newTokens); - supply = supply.add(newTokens); + token.transfer(_buyer, newTokens); + funded = funded.add(newTokens); LogBuy(_buyer, newTokens, centsPerETH); } - if (supply == maxSupply) { + if (funded == maxSupply) { lastCentsPerETH = centsPerETH; currentPhase = Phase.Finished; LogPhaseSwitch(Phase.Finished); @@ -290,29 +404,28 @@ contract PresaleToken { onlyMigrationManager onlyWhileMigrating { - assert(balance[_owner] != 0); - var migratedValue = balance[_owner]; - supply = supply.sub(migratedValue); - balance[_owner] = 0; + assert(token.balanceOf(_owner) != 0); + var migratedValue = token.balanceOf(_owner); + funded = funded.sub(migratedValue); LogMigrate(_owner, migratedValue); - - if(supply == 0) { + migrated[_owner] = true; + if(funded == 0) { currentPhase = Phase.Migrated; LogPhaseSwitch(Phase.Migrated); } } function startPresale() - onlyTokenManager + onlyOwner onlyWhileCreated { - assert(address(priceTicker) != 0x0); + assert(address(priceTicker) != address(0)); currentPhase = Phase.Running; LogPhaseSwitch(Phase.Running); } function finishPresale() - onlyTokenManager + onlyOwner onlyWhileRunning { lastCentsPerETH = priceTicker.getCentsPerETH(); @@ -322,7 +435,7 @@ contract PresaleToken { function finalizePresale() - onlyTokenManager + onlyOwner onlyWhileFinished { if (refundValue != 0) { @@ -334,10 +447,11 @@ contract PresaleToken { } function startMigration() - onlyTokenManager + onlyOwner onlyWhileFinalized { - assert(migrationManager != 0x0); + assert(migrationManager != address(0)); + token.freeze(); currentPhase = Phase.Migrating; LogPhaseSwitch(Phase.Migrating); } @@ -345,80 +459,37 @@ contract PresaleToken { function withdrawEther() private { assert(this.balance > 0); - tokenManager.transfer(this.balance); + owner.transfer(this.balance); } function setMigrationManager(address _mgr) - onlyTokenManager + onlyOwner onlyWhileFinalized { migrationManager = _mgr; } function raiseCap(uint _newCap) - onlyTokenManager + onlyOwner onlyWhileFinalized { + assert(!capRaised); assert(_newCap > maxSupply); maxSupply = _newCap; + token.raiseSupply(_newCap); currentPhase = Phase.Running; LogPhaseSwitch(Phase.Running); } - function giveTokens(address _address, uint _value) - onlyTokenManager + function giveTokens(address _address, uint _value, string _reason) + onlyOwner onlyBeforeMigration { - balance[_address] = balance[_address].add(_value); - supply = supply.add(_value); - givenSupply = givenSupply.add(_value); - } - - ///Ticker interaction functions - - function createTicker(uint256 _delay) - onlyTokenManager - { - priceTicker = new CMCEthereumTicker(tokenManager, _delay); - } - - function attachTicker(address _tickerAddress) - onlyTokenManager - { - priceTicker = CMCEthereumTicker(_tickerAddress); - } - - function enableTicker() - onlyTokenManager - { - priceTicker.enable(); - } - - function disableTicker() - onlyTokenManager - { - priceTicker.disable(); - } - - function sendToTicker() payable - onlyTokenManager - { - assert(address(priceTicker) != 0x0); - address(priceTicker).transfer(msg.value); - } - - function withdrawFromTicker(uint _amount) { - assert(address(priceTicker) != 0x0); - priceTicker.payToManager(_amount); - } - - function tickerAddress() constant returns (address) { - return address(priceTicker); - } - - function getCentsPerETH() constant returns (uint) { - return priceTicker.getCentsPerETH(); + token.transfer(_address, _value); + funded = funded.add(_value); + given = given.add(_value); + LogGive(_address, _value, _reason); } } \ No newline at end of file From d8738b2295e005f805d55be97ae49b46cb4c71e8 Mon Sep 17 00:00:00 2001 From: ivkamakin Date: Tue, 22 Aug 2017 11:49:48 +0300 Subject: [PATCH 02/12] Add proxy logic --- DolphinPresaleToken.sol | 87 +++++++++++++++++++++++++++++++++-------- ReferralProxy.sol | 23 +++++++++++ 2 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 ReferralProxy.sol diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index c67bc52..eb5732a 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -290,7 +290,26 @@ contract DBIPToken is Freezable { } -contract PresaleToken is TickerController { +contract ReferralProxyHandler is Ownable{ + + // Proxy is a contract throught which referral investors buy tokens + address public proxy; + // amount of tokens sold through proxy + uint256 public fundedProxy = 0; + + modifier onlyProxy { require(msg.sender == proxy); _; } + + function setProxy(address _proxy) + onlyOwner + { + proxy = _proxy; + } + + function buyThroughProxy(address _buyer) payable; + +} + +contract PresaleToken is TickerController, ReferralProxyHandler { using SafeMath for uint256; function PresaleToken(uint256 _limitUSD, uint256 _priceCents) { @@ -309,23 +328,23 @@ contract PresaleToken is TickerController { Migrated } - // token + // Token DBIPToken token; // maximum token supply - uint public maxSupply; + uint256 public maxSupply; // price of 1 token in USD cents - uint public priceCents; + uint256 public priceCents; // Decimals of token needed for most operations - uint public decimals = 18; - + uint256 public decimals = 18; //Phase on contract creation Phase public currentPhase = Phase.Created; // amount of tokens already sold - uint public funded = 0; + uint256 public funded = 0; // amount of tokens given via giveTokens - uint public given = 0; + uint256 public given = 0; + // Migration manager has privileges to burn tokens during migration. address public migrationManager; @@ -344,7 +363,7 @@ contract PresaleToken is TickerController { // Whether the funding cap was already raised bool capRaised = false; - //External access modifiers + //External access modifier modifier onlyMigrationManager() { require(msg.sender == migrationManager); _; } //Presale phase modifiers @@ -356,9 +375,9 @@ contract PresaleToken is TickerController { modifier onlyWhileMigrating() {assert(currentPhase == Phase.Migrating); _;} //Presale events - event LogBuy(address indexed owner, uint value, uint centsPerETH); - event LogGive(address indexed owner, uint valuem, string reason); - event LogMigrate(address indexed owner, uint value); + event LogBuy(address indexed owner, uint256 value, uint256 centsPerETH); + event LogGive(address indexed owner, uint256 value, string reason); + event LogMigrate(address indexed owner, uint256 value); event LogPhaseSwitch(Phase newPhase); ///Presale-specific functions @@ -373,16 +392,51 @@ contract PresaleToken is TickerController { require(msg.value != 0); require(priceTicker.getEnabled()); - var centsPerETH = getCentsPerETH(); + uint256 centsPerETH = getCentsPerETH(); + require(centsPerETH != 0); + + uint256 newTokens = msg.value.mul(centsPerETH).mul(uint256(10)**decimals).div(priceCents.mul(1 ether / 1 wei)); + assert(newTokens != 0); + + if (funded.add(newTokens) > maxSupply) { + uint256 remainder = maxSupply.sub(funded); + token.transfer(_buyer, remainder); + funded = funded.add(remainder); + lastBuyer = _buyer; + refundValue = newTokens.sub(remainder); + LogBuy(_buyer, remainder, centsPerETH); + } + else { + token.transfer(_buyer, newTokens); + funded = funded.add(newTokens); + LogBuy(_buyer, newTokens, centsPerETH); + } + + if (funded == maxSupply) { + lastCentsPerETH = centsPerETH; + currentPhase = Phase.Finished; + LogPhaseSwitch(Phase.Finished); + } + } + + function buyThroughProxy(address _buyer) payable + onlyProxy + onlyWhileRunning + { + require(msg.value != 0); + require(priceTicker.getEnabled()); + + uint256 centsPerETH = getCentsPerETH(); require(centsPerETH != 0); - var newTokens = msg.value.mul(centsPerETH).mul(uint(10)**decimals).div(priceCents.mul(1 ether / 1 wei)); + uint256 newTokens = msg.value.mul(centsPerETH).mul(uint256(10)**decimals).div(priceCents.mul(1 ether / 1 wei)); assert(newTokens != 0); if (funded.add(newTokens) > maxSupply) { - var remainder = maxSupply.sub(funded); + uint256 remainder = maxSupply.sub(funded); token.transfer(_buyer, remainder); funded = funded.add(remainder); + fundedProxy = fundedProxy.add(remainder); lastBuyer = _buyer; refundValue = newTokens.sub(remainder); LogBuy(_buyer, remainder, centsPerETH); @@ -390,6 +444,7 @@ contract PresaleToken is TickerController { else { token.transfer(_buyer, newTokens); funded = funded.add(newTokens); + fundedProxy = fundedProxy.add(newTokens); LogBuy(_buyer, newTokens, centsPerETH); } @@ -439,7 +494,7 @@ contract PresaleToken is TickerController { onlyWhileFinished { if (refundValue != 0) { - lastBuyer.transfer((refundValue.mul(priceCents).mul(1 ether / 1 wei)).div(lastCentsPerETH.mul(uint(10)**decimals))); + lastBuyer.transfer((refundValue.mul(priceCents).mul(1 ether / 1 wei)).div(lastCentsPerETH.mul(uint256(10)**decimals))); } withdrawEther(); currentPhase = Phase.Finalized; diff --git a/ReferralProxy.sol b/ReferralProxy.sol new file mode 100644 index 0000000..8c988e5 --- /dev/null +++ b/ReferralProxy.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.4.13; + +interface IReferralProxyHandler { + function buyThroughProxy(address _buyer) payable; +} + +contract ReferralProxy { + + IReferralProxyHandler public presaleContract; + + function ReferralProxy(address _presaleContract) { + presaleContract = IReferralProxyHandler(_presaleContract); + } + + function () payable { + presaleContract.buyThroughProxy(msg.sender); + } + + function buyTokens(address _buyer) payable { + presaleContract.buyThroughProxy(_buyer); + } + +} \ No newline at end of file From db76724e61e83fd42dc5ebd941e0ee9af52b3a60 Mon Sep 17 00:00:00 2001 From: ivkamakin Date: Tue, 22 Aug 2017 14:04:57 +0300 Subject: [PATCH 03/12] Fix WhileNotFrozen modifier --- DolphinPresaleToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index eb5732a..15f8ca3 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -51,7 +51,7 @@ contract Freezable is Ownable { bool frozen = false; - modifier whileNotFrozen {assert(frozen == true); _;} + modifier whileNotFrozen {assert(frozen != true); _;} function freeze() onlyOwner { frozen = true; From 682cf1390b0cad2392cc8bf82d9526d1cc4a0c85 Mon Sep 17 00:00:00 2001 From: ivkamakin Date: Tue, 22 Aug 2017 14:38:00 +0300 Subject: [PATCH 04/12] Make token field public --- DolphinPresaleToken.sol | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index 15f8ca3..a7c3bb4 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -66,7 +66,7 @@ contract Freezable is Ownable { contract CMCEthereumTicker is usingOraclize, Ownable { using SafeMath for uint; - uint centsPerETH; + uint256 centsPerETH; uint256 delay; bool enabled; @@ -85,7 +85,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { delay = _delay; } - function getCentsPerETH() constant returns(uint) { + function getCentsPerETH() constant returns(uint256) { return centsPerETH; } @@ -135,7 +135,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { } } - function payToManager(uint _amount) + function payToManager(uint256 _amount) onlyOwnerOrManager { manager.transfer(_amount); @@ -192,7 +192,7 @@ contract TickerController is Ownable{ return address(priceTicker); } - function getCentsPerETH() constant returns (uint) { + function getCentsPerETH() constant returns (uint256) { return priceTicker.getCentsPerETH(); } } @@ -211,7 +211,7 @@ contract DBIPToken is Freezable { //ERC 20 Additional info string public constant name = "Dolphin Presale Token"; string public constant symbol = "DBIP"; - uint8 public constant decimals = 18; + uint256 public constant decimals = 18; //ERC20 events event Transfer(address indexed _from, address indexed _to, uint256 _value); @@ -220,7 +220,7 @@ contract DBIPToken is Freezable { //Modifier to defend against shortened address attack - modifier minimalPayloadSize(uint size) { + modifier minimalPayloadSize(uint256 size) { assert(msg.data.length >= size + 4); _; } @@ -314,7 +314,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { function PresaleToken(uint256 _limitUSD, uint256 _priceCents) { priceCents = _priceCents; - maxSupply = (uint(10)**decimals).mul(100).mul(_limitUSD).div(_priceCents); + maxSupply = (uint256(10)**decimals).mul(100).mul(_limitUSD).div(_priceCents); token = new DBIPToken(maxSupply); assert(decimals == token.decimals()); } @@ -329,7 +329,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { } // Token - DBIPToken token; + DBIPToken public token; // maximum token supply uint256 public maxSupply; // price of 1 token in USD cents @@ -357,8 +357,8 @@ contract PresaleToken is TickerController, ReferralProxyHandler { // During the presale finalization they are refunded // the excess USD according to lastCentsPerETH. address lastBuyer; - uint refundValue = 0; - uint lastCentsPerETH = 0; + uint256 refundValue = 0; + uint256 lastCentsPerETH = 0; // Whether the funding cap was already raised bool capRaised = false; From 39409bc80b3529d7e24ba13ebf36dd091ee70c42 Mon Sep 17 00:00:00 2001 From: Ivan Kamakin Date: Thu, 24 Aug 2017 23:23:31 +0300 Subject: [PATCH 05/12] Add freeze during presale --- DolphinPresaleToken.sol | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index a7c3bb4..4b55562 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -240,6 +240,19 @@ contract DBIPToken is Freezable { supply = supply.add(increase); } + // Method that allows parent to transfer during freeze + + function ownerTransfer(address _to, uint256 _value) onlyOwner returns (bool success) + { + assert(_value > 0); + + balance[owner] = balance[owner].sub(_value); + balance[_to] = balance[_to].add(_value); + Transfer(owner,_to,_value); + + return true; + } + ///ERC20 Interface functions function balanceOf(address _owner) constant returns (uint256 balanceOf) { @@ -400,14 +413,14 @@ contract PresaleToken is TickerController, ReferralProxyHandler { if (funded.add(newTokens) > maxSupply) { uint256 remainder = maxSupply.sub(funded); - token.transfer(_buyer, remainder); + token.ownerTransfer(_buyer, remainder); funded = funded.add(remainder); lastBuyer = _buyer; refundValue = newTokens.sub(remainder); LogBuy(_buyer, remainder, centsPerETH); } else { - token.transfer(_buyer, newTokens); + token.ownerTransfer(_buyer, newTokens); funded = funded.add(newTokens); LogBuy(_buyer, newTokens, centsPerETH); } @@ -475,6 +488,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { onlyWhileCreated { assert(address(priceTicker) != address(0)); + token.freeze(); currentPhase = Phase.Running; LogPhaseSwitch(Phase.Running); } @@ -497,6 +511,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { lastBuyer.transfer((refundValue.mul(priceCents).mul(1 ether / 1 wei)).div(lastCentsPerETH.mul(uint256(10)**decimals))); } withdrawEther(); + token.unfreeze(); currentPhase = Phase.Finalized; LogPhaseSwitch(Phase.Finalized); } @@ -532,6 +547,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { assert(_newCap > maxSupply); maxSupply = _newCap; token.raiseSupply(_newCap); + token.freeze(); currentPhase = Phase.Running; LogPhaseSwitch(Phase.Running); } @@ -541,7 +557,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { onlyBeforeMigration { - token.transfer(_address, _value); + token.ownerTransfer(_address, _value); funded = funded.add(_value); given = given.add(_value); LogGive(_address, _value, _reason); From 4a04a592f934fbfed90d39a658db06ccd79117be Mon Sep 17 00:00:00 2001 From: zidorov Date: Tue, 29 Aug 2017 16:11:05 +0300 Subject: [PATCH 06/12] remove unnecessary mapping 'migrated' --- DolphinPresaleToken.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index 4b55562..123358c 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -362,9 +362,6 @@ contract PresaleToken is TickerController, ReferralProxyHandler { // Migration manager has privileges to burn tokens during migration. address public migrationManager; - // Used to check whether the address has already migrated - mapping (address => bool) migrated; - // The last buyer is the buyer that purchased // tokens that add up to the maxSupply or more. // During the presale finalization they are refunded @@ -476,7 +473,6 @@ contract PresaleToken is TickerController, ReferralProxyHandler { var migratedValue = token.balanceOf(_owner); funded = funded.sub(migratedValue); LogMigrate(_owner, migratedValue); - migrated[_owner] = true; if(funded == 0) { currentPhase = Phase.Migrated; LogPhaseSwitch(Phase.Migrated); From 1a63c8f9a4d4fea2638e025a6c637ffa8c5079fc Mon Sep 17 00:00:00 2001 From: ivkamakin Date: Mon, 4 Sep 2017 13:22:54 +0300 Subject: [PATCH 07/12] Fix proxy not sending funds to main contract --- ReferralProxy.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReferralProxy.sol b/ReferralProxy.sol index 8c988e5..a234412 100644 --- a/ReferralProxy.sol +++ b/ReferralProxy.sol @@ -13,11 +13,11 @@ contract ReferralProxy { } function () payable { - presaleContract.buyThroughProxy(msg.sender); + presaleContract.buyThroughProxy.value(msg.value)(msg.sender); } function buyTokens(address _buyer) payable { - presaleContract.buyThroughProxy(_buyer); + presaleContract.buyThroughProxy.value(msg.value)(_buyer); } } \ No newline at end of file From f22c4081808bcd2801ee6194fd4ae86cfd4a48cc Mon Sep 17 00:00:00 2001 From: zidorov Date: Tue, 5 Sep 2017 15:00:38 +0300 Subject: [PATCH 08/12] raiseCap to be available on Finished phase --- DolphinPresaleToken.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index 123358c..4ec913d 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -537,13 +537,16 @@ contract PresaleToken is TickerController, ReferralProxyHandler { function raiseCap(uint _newCap) onlyOwner - onlyWhileFinalized + onlyWhileFinished { assert(!capRaised); assert(_newCap > maxSupply); maxSupply = _newCap; token.raiseSupply(_newCap); - token.freeze(); + if (refundValue != 0) { + token.ownerTransfer(lastBuyer, refundValue); + refundValue = 0; + } currentPhase = Phase.Running; LogPhaseSwitch(Phase.Running); } From 4e0a78289efcb279bf4f8007f8dcee70e0d52a1f Mon Sep 17 00:00:00 2001 From: zidorov Date: Tue, 5 Sep 2017 15:50:00 +0300 Subject: [PATCH 09/12] PresaleToken is Freezable --- DolphinPresaleToken.sol | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index 4ec913d..e19cc5b 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -145,7 +145,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { } -contract TickerController is Ownable{ +contract TickerController is Ownable { //Ticker contract CMCEthereumTicker priceTicker; @@ -303,7 +303,7 @@ contract DBIPToken is Freezable { } -contract ReferralProxyHandler is Ownable{ +contract ReferralProxyHandler is Ownable { // Proxy is a contract throught which referral investors buy tokens address public proxy; @@ -322,7 +322,7 @@ contract ReferralProxyHandler is Ownable{ } -contract PresaleToken is TickerController, ReferralProxyHandler { +contract PresaleToken is TickerController, ReferralProxyHandler, Freezable { using SafeMath for uint256; function PresaleToken(uint256 _limitUSD, uint256 _priceCents) { @@ -397,6 +397,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { } function buyTokens(address _buyer) payable + whileNotFrozen onlyWhileRunning { require(msg.value != 0); @@ -430,6 +431,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { } function buyThroughProxy(address _buyer) payable + whileNotFrozen onlyProxy onlyWhileRunning { @@ -536,6 +538,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler { } function raiseCap(uint _newCap) + whileNotFrozen onlyOwner onlyWhileFinished { @@ -551,10 +554,10 @@ contract PresaleToken is TickerController, ReferralProxyHandler { LogPhaseSwitch(Phase.Running); } - function giveTokens(address _address, uint _value, string _reason) + function giveTokens(address _address, uint _value, string _reason) + whileNotFrozen onlyOwner onlyBeforeMigration - { token.ownerTransfer(_address, _value); funded = funded.add(_value); From 355b7bdc6dcc707e934826bc78c8bfc2a9679a07 Mon Sep 17 00:00:00 2001 From: zidorov Date: Wed, 6 Sep 2017 01:32:32 +0300 Subject: [PATCH 10/12] raiseCap to increase funded --- DolphinPresaleToken.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index e19cc5b..bb68fdb 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -548,6 +548,7 @@ contract PresaleToken is TickerController, ReferralProxyHandler, Freezable { token.raiseSupply(_newCap); if (refundValue != 0) { token.ownerTransfer(lastBuyer, refundValue); + funded = funded.add(refundValue); refundValue = 0; } currentPhase = Phase.Running; From 9cf768d8a73d44443c0a191e16b2c42d251cd1a9 Mon Sep 17 00:00:00 2001 From: zidorov Date: Wed, 6 Sep 2017 09:15:29 +0300 Subject: [PATCH 11/12] make CMCEthereumTicker update methods private --- DolphinPresaleToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index bb68fdb..c28bff3 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -117,7 +117,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { } } - function update_instant() payable { + function update_instant() private payable { if (oraclize.getPrice("URL") > this.balance) { newOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); } else { @@ -126,7 +126,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { } } - function update() payable { + function update() private payable { if (oraclize.getPrice("URL") > this.balance) { newOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); } else { From 911b1f2932df96e049e08b6dc99a7ec11d7c7c0e Mon Sep 17 00:00:00 2001 From: zidorov Date: Wed, 6 Sep 2017 11:27:00 +0300 Subject: [PATCH 12/12] make ticker update* methods not payable --- DolphinPresaleToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DolphinPresaleToken.sol b/DolphinPresaleToken.sol index c28bff3..3460c93 100644 --- a/DolphinPresaleToken.sol +++ b/DolphinPresaleToken.sol @@ -117,7 +117,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { } } - function update_instant() private payable { + function update_instant() private { if (oraclize.getPrice("URL") > this.balance) { newOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); } else { @@ -126,7 +126,7 @@ contract CMCEthereumTicker is usingOraclize, Ownable { } } - function update() private payable { + function update() private { if (oraclize.getPrice("URL") > this.balance) { newOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee"); } else {