Skip to content

Commit

Permalink
Refactoring for tests + added new interface for setting exchange rate
Browse files Browse the repository at this point in the history
  • Loading branch information
chompomonim committed May 30, 2018
1 parent 4baa587 commit 06f42ea
Show file tree
Hide file tree
Showing 15 changed files with 115 additions and 66 deletions.
33 changes: 19 additions & 14 deletions contracts/contracts/JaroCoinCrowdsale.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.23;
pragma solidity ^0.4.24;

import "zeppelin-solidity/contracts/math/SafeMath.sol";

Expand All @@ -12,14 +12,15 @@ contract JaroCoinCrowdsale is Ownable {

address public constant WALLET = 0xefF42c79c0aBea9958432DC82FebC4d65f3d24A3;

// digits of precision for exchange rate
uint8 public constant EXCHANGE_RATE_DECIMALS = 8;

// Max tokens which can be in circulation
uint256 public constant MAX_AMOUNT = 21000000e18; // 21 000 000

// Amount of raised funds in satoshi
uint256 public satoshiRaised;

uint256 public satoshiRaised; // Amount of raised funds in satoshi
uint256 public rate; // number of tokens buyer gets per satoshi
uint256 public conversionRate; // wei per satoshi - per ETH => 0.056 ETH/BTC ? wei per satoshi?
uint256 public conversionRate; // 17e10 wei per satoshi => 0.056 ETH/BTC

JaroCoinToken public token;
JaroSleep public sleepContract;
Expand All @@ -33,6 +34,8 @@ contract JaroCoinCrowdsale is Ownable {
bool public isActive = false;
bool internal initialized = false;

address public exchangeRateOracle;

event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
event SaleActivated(uint256 startTime, uint256 amount);
event SaleClosed();
Expand All @@ -43,10 +46,6 @@ contract JaroCoinCrowdsale is Ownable {
_;
}

constructor(address _owner, address _token, address _familyOwner, address _personalOwner) public {
initialize(_owner, _token, _familyOwner, _personalOwner);
}

function initialize(address _owner, address _token, address _familyOwner, address _personalOwner) public {
require (!initialized);

Expand Down Expand Up @@ -171,10 +170,16 @@ contract JaroCoinCrowdsale is Ownable {
_closeSale();
}

function updateConvertionRate(uint256 _rate) public onlyOwner {
require (_rate > 0);
function setExchangeRateOracle(address _exchangeRateOracle) public onlyOwner {
require(_exchangeRateOracle != address(0));
exchangeRateOracle = _exchangeRateOracle;
}

function setExchangeRate(uint256 _exchangeRate) public {
require(msg.sender == exchangeRateOracle || msg.sender == owner);
require(_exchangeRate > 0);
uint256 one = 1e18;
conversionRate = one.div(_rate);
conversionRate = one.div(_exchangeRate);
}

function mint(address _beneficiary, uint256 _amount) internal {
Expand All @@ -185,11 +190,11 @@ contract JaroCoinCrowdsale is Ownable {

// This function created for easier testing purposes
function createJaroSleep(address _token, uint256 _dailyTime) internal returns (JaroSleep) {
return new JaroSleep(_token, _dailyTime);
return new JaroSleep(_token, _dailyTime, getNow());
}

function createPersonalTime(address _token, uint256 _dailyTime) internal returns (PersonalTime) {
return new PersonalTime(_token, _dailyTime);
return new PersonalTime(_token, _dailyTime, getNow());
}

// This function created for easier testing purposes
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/JaroCoinToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ contract JaroCoinToken is Ownable, ERC820Implementer {
*/
function burn(uint256 _amount, bytes _userData) public {
require (_amount > 0);
require (balanceOf[msg.sender] >= _amount);
require (balanceOf[msg.sender] >= _amount, "Burning more than balance");
requireMultiple(_amount);

callSender(msg.sender, msg.sender, 0x0, _amount, _userData, "");
Expand Down
17 changes: 13 additions & 4 deletions contracts/contracts/Pay.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
pragma solidity ^0.4.23;

import "eip820/contracts/ERC820Implementer.sol";
import "./JaroCoinToken.sol";

interface ERC777TokensRecipient {
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) external;
}

contract BurnableToken {
event Burned(address indexed operator, address indexed from, uint256 amount, bytes userData, bytes operatorData);
function burn(uint256 _amount, bytes _userData) public {
emit Burned(msg.sender, msg.sender, _amount, _userData, "");
}
}

/**
* The Pay contract helps people to burn JaroCoin tokens (pay for Jaro services)
* without knowing how to touch `burn` function from JaroCoin Token smart contract.
*/
contract Pay is ERC820Implementer, ERC777TokensRecipient {
JaroCoinToken public token;
BurnableToken public token;

event Payed(address operator, address from, address to, uint amount, bytes userData, bytes operatorData);

constructor(address _token) public {
setInterfaceImplementation("ERC777TokensRecipient", this);
token = JaroCoinToken(_token);
token = BurnableToken(_token);
}

// ERC777 tokens receiver callback
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) external {
token.burn(amount, userData);
emit Payed(operator, from, to, amount, userData, operatorData);
}

}
4 changes: 2 additions & 2 deletions contracts/contracts/PersonalContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ contract PersonalTime is Ownable, ERC820Implementer, ERC777TokensRecipient {

event ReceivedTokens(address operator, address from, address to, uint amount, bytes userData, bytes operatorData);

constructor(address _token, uint256 _dailyTime) public {
constructor(address _token, uint256 _dailyTime, uint256 _lastBurn) public {
setInterfaceImplementation("ERC777TokensRecipient", this);
token = JaroCoinToken(_token);
lastBurn = getNow();
lastBurn = _lastBurn;
dailyTime = _dailyTime;
}

Expand Down
6 changes: 3 additions & 3 deletions contracts/contracts/SleepContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ contract JaroSleep is ERC820Implementer, ERC777TokensRecipient {

event ReceivedTokens(address operator, address from, address to, uint amount, bytes userData, bytes operatorData);

constructor(address _token, uint256 _dailyTime) public {
constructor(address _token, uint256 _dailyTime, uint256 _lastBurn) public {
setInterfaceImplementation("ERC777TokensRecipient", this);
token = JaroCoinToken(_token);
lastBurn = getNow();
lastBurn = _lastBurn;
dailyTime = _dailyTime;
}

Expand All @@ -30,7 +30,7 @@ contract JaroSleep is ERC820Implementer, ERC777TokensRecipient {
uint256 sec = getNow().sub(lastBurn);
uint256 tokensToBurn = 0;

// // TODO convert into uint64 for saving gas purposes
// TODO convert into uint64 for saving gas purposes
if (sec >= 1 days) {
uint256 d = sec.div(86400);
tokensToBurn = d.mul(dailyTime);
Expand Down
23 changes: 16 additions & 7 deletions contracts/flatten/JaroCoinCrowdsale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -555,14 +555,15 @@ contract JaroCoinCrowdsale is Ownable {

address public constant WALLET = 0xefF42c79c0aBea9958432DC82FebC4d65f3d24A3;

// digits of precision for exchange rate
uint8 public constant EXCHANGE_RATE_DECIMALS = 8;

// Max tokens which can be in circulation
uint256 public constant MAX_AMOUNT = 21000000e18; // 21 000 000

// Amount of raised funds in satoshi
uint256 public satoshiRaised;

uint256 public satoshiRaised; // Amount of raised funds in satoshi
uint256 public rate; // number of tokens buyer gets per satoshi
uint256 public conversionRate; // wei per satoshi - per ETH => 0.056 ETH/BTC ? wei per satoshi?
uint256 public conversionRate; // 17e10 wei per satoshi => 0.056 ETH/BTC

JaroCoinToken public token;
JaroSleep public sleepContract;
Expand All @@ -576,6 +577,8 @@ contract JaroCoinCrowdsale is Ownable {
bool public isActive = false;
bool internal initialized = false;

address public exchangeRateOracle;

event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
event SaleActivated(uint256 startTime, uint256 amount);
event SaleClosed();
Expand Down Expand Up @@ -710,10 +713,16 @@ contract JaroCoinCrowdsale is Ownable {
_closeSale();
}

function updateConvertionRate(uint256 _rate) public onlyOwner {
require (_rate > 0);
function setExchangeRateOracle(address _exchangeRateOracle) public onlyOwner {
require(_exchangeRateOracle != address(0));
exchangeRateOracle = _exchangeRateOracle;
}

function setExchangeRate(uint256 _exchangeRate) public {
require(msg.sender == exchangeRateOracle || msg.sender == owner);
require(_exchangeRate > 0);
uint256 one = 1e18;
conversionRate = one.div(_rate);
conversionRate = one.div(_exchangeRate);
}

function mint(address _beneficiary, uint256 _amount) internal {
Expand Down
1 change: 1 addition & 0 deletions contracts/flatten/JaroSleep.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ contract ERC820Implementer {
erc820Registry.setManager(this, newManager);
}
}

interface ERC777TokensSender {
function tokensToSend(address operator, address from, address to, uint amount, bytes userData,bytes operatorData) external;
}
Expand Down
35 changes: 35 additions & 0 deletions contracts/migrations/2_contract_creation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const JaroCoin = artifacts.require("./JaroCoinToken.sol")
const JaroCoinCrowdsale = artifacts.require("./JaroCoinCrowdsale.sol")
const CrowdsaleProxy = artifacts.require("./CrowdsaleProxy.sol")
const EIP820Registry = require("eip820");

const owner = '0xa465495956083b62b5a2a864ff6a00bc0034d16d'
const familyOwner = '0x807EcA0E76075253816F0361E149b8F2D6F7B42d'
const personalOwner = '0x83A63Ee3E80716391b5C77E7e06c3d75e64597f4'

module.exports = function(deployer, network, accounts) {
if (network === 'development') {
const Web3Latest = require("web3");
const web3latest = new Web3Latest('http://localhost:8545');
return EIP820Registry.deploy(web3latest, accounts[0]);
}

deployer.deploy(JaroCoin).then(() => {
return deployer.deploy(JaroCoinCrowdsale)
}).then(() => {
return deployer.deploy(CrowdsaleProxy, JaroCoinCrowdsale.address)
}).then(() => {
return CrowdsaleProxy.deployed()
}).then((proxy) => {
return proxy.___initialize(JaroCoin.address, familyOwner, personalOwner)
}).then(() => {
return JaroCoin.deployed()
}).then((token) => {
return token.transferOwnership(CrowdsaleProxy.address)
}).then(() => {
return CrowdsaleProxy.deployed()
}).then((proxy) => {
const proxiedCrowdsale = JaroCoinCrowdsale.at(proxy.address)
return proxiedCrowdsale.startSale(1523855000)
})
}
6 changes: 3 additions & 3 deletions contracts/test/TestCoupon.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function getTime(date) {
contract('Crowdsale with Coupon', (accounts) => {
let crowdsale
let token
const owner = accounts[2]
const owner = accounts[0]
const familyOwner = accounts[4]
const wallet = '0x1111111111111111111111111111111111111111' // WALLET where we collect ethereum
const firstBuyTokens = new BigNumber('5882.352e18')
Expand Down Expand Up @@ -96,8 +96,8 @@ contract('Crowdsale with Coupon', (accounts) => {
})

it('should mint more tokens when transfer with coupon', async () => {
const coupon = generateCoupon(550, getTime('2018-04-15'))

const coupon = generateCoupon(100, getTime('2018-05-11'))
console.log('BONUST: ', coupon)
await crowdsale.sendTransaction({
from: accounts[1],
value: OneEther,
Expand Down
17 changes: 12 additions & 5 deletions contracts/test/TestCrowdsale.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function getTime(date) {
return Math.floor(new Date(date).getTime() / 1000)
}

contract('JaroCoinCrowdsale', async (accounts) => {
contract.only('JaroCoinCrowdsale', async (accounts) => {
let crowdsale
let token
const satoshiPrice = new BigNumber("1000") // 0.00001 BTC = 1000 satoshi
Expand All @@ -29,11 +29,13 @@ contract('JaroCoinCrowdsale', async (accounts) => {
const firstBuyTokens = new BigNumber('5882.352e18')
const secondBuyTokens = new BigNumber('7000e18')
const familyOwner = accounts[4]
const wallet = '0x1111111111111111111111111111111111111111' // WALLET where we collect ethereum
const wallet = '0xefF42c79c0aBea9958432DC82FebC4d65f3d24A3' // WALLET where we collect ethereum

before(async () => {
token = await JaroCoin.new()
crowdsale = await Crowdsale.new(owner, token.address, familyOwner, wallet)
crowdsale = await Crowdsale.new()
await crowdsale.testInitialize(owner, token.address, familyOwner, wallet, getTime('2018-04-10'))
await crowdsale.setNow(getTime('2018-04-10'))

// Make crowdsale contract owner of token
await token.transferOwnership(crowdsale.address)
Expand Down Expand Up @@ -63,6 +65,11 @@ contract('JaroCoinCrowdsale', async (accounts) => {
expect(await token.balanceOf(accounts[1])).to.be.bignumber.equal(0)
})

it('wallet should have 0 eth on its balance', async () => {
const walletBalance = web3.eth.getBalance(wallet)
expect(walletBalance).to.be.bignumber.equal(0)
})

it('should accept funds and mint 5882 tokens for 1 eth', async () => {
await crowdsale.sendTransaction({
from: accounts[0],
Expand All @@ -72,14 +79,14 @@ contract('JaroCoinCrowdsale', async (accounts) => {
expect(await token.balanceOf(accounts[0])).to.be.bignumber.equal(firstBuyTokens)
})

it.skip('wallet should have 1 eth on its balance', async () => {
it('wallet should have 1 eth on its balance', async () => {
const walletBalance = web3.eth.getBalance(wallet)
expect(walletBalance).to.be.bignumber.equal(OneEther)
})

it('should set new conversionRate', async () => {
const newConversionRate = new BigNumber("7000e3") // satoshi/eth, 0.07 BTC/ETH
await crowdsale.updateConvertionRate(newConversionRate, {from: owner})
await crowdsale.setExchangeRate(newConversionRate, {from: owner})
expect(await crowdsale.conversionRate()).to.be.bignumber.equal(OneEther.div(newConversionRate).floor())
})

Expand Down
2 changes: 1 addition & 1 deletion contracts/test/TestPay.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const OneToken = new BigNumber("1e18");
const Pay = artifacts.require("./contracts/TestPayContract.sol")
const JaroCoinToken = artifacts.require("./contracts/TestJaroCoinToken.sol");

contract.only('Pay for services', (accounts) => {
contract('Pay for services', (accounts) => {
let token;
let pay;
before(async () => {
Expand Down
12 changes: 5 additions & 7 deletions contracts/test/contracts/TestJaroCoinCrowdsale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ contract TestJaroCoinCrowdsale is JaroCoinCrowdsale {
uint256 testNow;
string public constant name = "Crowdsale";

constructor(
address _owner,
address _token,
address _familyOwner,
address _personalOwner) JaroCoinCrowdsale(_owner, _token, _familyOwner, _personalOwner) public {
function testInitialize(address _owner, address _token, address _familyOwner, address _personalOwner, uint256 _now) public {
testNow = _now;
initialize(_owner, _token, _familyOwner, _personalOwner);
}

function setNow(uint256 _now) public {
Expand All @@ -32,11 +30,11 @@ contract TestJaroCoinCrowdsale is JaroCoinCrowdsale {
}

function createJaroSleep(address _token, uint256 _dailyTime) internal returns (JaroSleep) {
return new TestSleepContract(_token, _dailyTime);
return new TestSleepContract(_token, _dailyTime, getNow());
}

function createPersonalTime(address _token, uint256 _dailyTime) internal returns(PersonalTime) {
return new TestPersonalContract(_token, _dailyTime);
return new TestPersonalContract(_token, _dailyTime, getNow());
}

}
8 changes: 0 additions & 8 deletions contracts/test/contracts/TestJaroCoinToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ pragma solidity ^0.4.23;
import 'contracts/JaroCoinToken.sol';

contract TestJaroCoinToken is JaroCoinToken {
function interfaceAddr(address addr, string ifaceLabel) internal constant returns(address) {
// We're not implementing ERC777TokensSender in tests
if (!isRegularAddress(addr) && keccak256(ifaceLabel) == keccak256("ERC777TokensRecipient")) {
return addr;
} else {
return 0x0;
}
}

function sendProxy(address _to, uint256 _amount, bytes _userData) public {
send(_to, _amount, _userData);
Expand Down
8 changes: 2 additions & 6 deletions contracts/test/contracts/TestPersonalContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ pragma solidity ^0.4.23;
import 'contracts/PersonalContract.sol';

contract TestPersonalContract is PersonalTime {
uint256 testNow = now;

constructor(address _token, uint256 _dailyTime) PersonalTime(_token, _dailyTime) public {
}

function setInterfaceImplementation(string ifaceLabel, address impl) internal {
uint256 testNow;

constructor(address _token, uint256 _dailyTime, uint256 _lastBurn) PersonalTime(_token, _dailyTime, _lastBurn) public {
}

function setNow(uint256 _now) public {
Expand Down
Loading

0 comments on commit 06f42ea

Please sign in to comment.