ethereumcommonwealth / cold-staking Goto Github PK
View Code? Open in Web Editor NEWLicense: BSD 4-Clause "Original" or "Old" License
License: BSD 4-Clause "Original" or "Old" License
pragma solidity ^0.4.12;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
pragma solidity ^0.4.12;
import './safeMath.sol';
contract ColdStaking {
using SafeMath for uint256;
event StartStaking(address addr, uint256 value, uint256 weight, uint256 init_block);
event WithdrawStake(address staker, uint256 weight);
event Claim(address staker, uint256 reward);
event FirstStakeDonation(address _address, uint256 value);
/*struct Staker
// Commented out due to error in solidity compiler
{
uint256 weight;
uint256 init_block;
}*/
uint256 public staking_pool;
uint256 public staking_threshold = 0 ether;
//uint256 public round_interval = 172800; // approx. 1 month in blocks
//uint256 public max_delay = 172800 * 12; // approx. 1 year in blocks
/// TESTING VALUES
uint256 public round_interval = 200; // approx. 1 month in blocks
uint256 public max_delay = 7 * 6000; // approx. 1 year in blocks
mapping(address => uint256) staker_weight;
mapping(address => uint256) staker_init_block;
mapping(address => bool) private muted;
function() public payable
{
// No donations accepted to fallback!
// Consider value deposit is an attempt to become staker.
start_staking();
}
function start_staking() public payable
{
assert(msg.value >= staking_threshold);
staking_pool = staking_pool.add(msg.value);
staker_weight[msg.sender] = staker_weight[msg.sender].add(msg.value);
staker_init_block[msg.sender] = block.number;
/*StartStaking(
msg.sender,
msg.value,
staker[msg.sender].weight,
staker[msg.sender].init_block
);*/
}
function First_Stake_donation() public payable {
FirstStakeDonation(msg.sender, msg.value);
}
function claim_and_withdraw() public
{
claim();
withdraw_stake();
}
function withdraw_stake() public only_staker mutex(msg.sender)
{
msg.sender.transfer(staker[msg.sender].weight);
staking_pool = staking_pool.sub(staker_weight[msg.sender]);
staker_weight[msg.sender] = staker_weight[msg.sender].sub(staker_weight[msg.sender]);
WithdrawStake(msg.sender, staker_weight[msg.sender]);
}
function claim() public only_staker mutex(msg.sender)
{
require(block.number >= staker_init_block[msg.sender].add(round_interval));
uint256 _reward = stake_reward(msg.sender);
msg.sender.transfer(_reward);
staker_init_block[msg.sender] = block.number;
Claim(msg.sender, _reward);
}
function stake_reward(address _addr) public constant returns (uint256 _reward)
{
return (reward() * stakerTimeStake(_addr) * stakerWeightStake(_addr));
}
function stakerTimeStake(address _addr) public constant returns (uint256 _time)
{
return ((block.number - staker_init_block[_addr]) / round_interval);
//return 1;
}
function stakerWeightStake(address _addr) public constant returns (uint256 _stake)
{
return (staker_weight[_addr] / (staking_pool + staker_weight[_addr] * (stakerTimeStake(_addr) - 1)));
//return 0;
}
function report_abuse(address _addr) public only_staker mutex(_addr)
{
assert(staker[_addr].weight > 0);
assert(block.number > staker_init_block[_addr].add(max_delay));
_addr.transfer(staker_weight[msg.sender]);
staker_weight[_addr] = 0;
}
function reward() public constant returns (uint256)
{
return address(this).balance.sub(staking_pool);
}
modifier only_staker
{
assert(staker_weight[msg.sender] > 0);
_;
}
modifier mutex(address _target)
{
if (muted[_target])
{
revert();
}
muted[_target] = true;
_;
muted[_target] = false;
}
////////////// DEBUGGING /////////////////////////////////////////////////////////////
function test() public constant returns (string)
{
return "success!";
}
function infoOfStaker(address _addr) constant returns (uint256 weight, uint256 init, uint256 stake_time, uint256 _reward)
{
if (staker[_addr].init_block == 0)
{
return (staker_weight[_addr],staker_init_block[_addr],0,stake_reward(_addr));
}
return (staker_weight[_addr],staker_init_block[_addr],block.number - staker_init_block[_addr],stake_reward(_addr));
}
function info_WEIGHT(address _addr) constant returns (uint256)
{
return staker_weight[_addr];
}
function info_INIT(address _addr) constant returns (uint256)
{
return staker[_addr].init_block;
}
}
Internal exception in StandardCompiler::compileInternal: /src/libsolidity/ast/ASTJsonConverter.cpp(791): Throw in function string dev::solidity::ASTJsonConverter::functionCallKind(dev::solidity::FunctionCallKind)
Dynamic exception type: N5boost16exception_detail10clone_implIN3dev8solidity21InternalCompilerErrorEEE
std::exception::what: std::exception
[PN3dev11tag_commentE] = Unknown kind of function call .
About 29 days ago I did deposit to staking contract 17130 CLO (after that, there are about 122000 coins in the contract).
Staking period must be ended 5 january 2019. During process was error about gas required exceeds.
31 december 2018 (5 days before staking period must end) I send to my wallet 13980 CLO from HitBtc.
After that, there are about 19000 coins in the wallet.
After a couple of minutes, a transaction appeared that sent exactly 17130 CLO to the staking contract.
It looks as if this transaction was created at the beginning of the period (that is, 22 days ago) and was expecting the necessary amount on the wallet to be executed.
So, this transaction which I did not send has reset staking period and reward.
I would not want this to happen again. Not only because I lost about 15,000 coins as a reward for the second round, but even so such "dormant transactions" are not credible.
StakingRewardPool is updated once inside newBlock()
function:
StakingRewardPool = address(this).balance.sub(TotalStakingAmount + msg.value);
However stakers can call start_staking multiple times in the same block. which mean that StakingRewardPool will be updated only once because of the following condition:
if (block.number > LastBlock)
{
....
}
The previous used CurrentBlockDeposits
might solve this issue.
Need to reset time as well:
Line 182 in 863846e
And in near this line:
Line 262 in 863846e
This action will also refund gas:
staker[msg.sender].time = 0;
Auditing smart contracts in live stream: https://www.youtube.com/watch?v=efZY3_COaiE
Your CryptoManiacs :)
Remove this condition:
Line 175 in 863846e
Because of exactly the same condition a few lines ago:
Line 171 in 863846e
Auditing smart contracts in live stream: https://www.youtube.com/watch?v=efZY3_COaiE
Your CryptoManiacs :)
Remove debug method to avoid CLO coin losts:
Line 162 in 863846e
Auditing smart contracts in live stream: https://www.youtube.com/watch?v=efZY3_COaiE
Your CryptoManiacs :)
This line:
Line 223 in 863846e
Should use:
address(this).balance.sub(TotalStakingAmount);
Instead of:
StakingRewardPool
Because balance could be refilled by Treasure.
Auditing smart contracts in live stream: https://www.youtube.com/watch?v=efZY3_COaiE
Your CryptoManiacs :)
This method:
Line 226 in 863846e
Is already exist because of this line:
Line 76 in 863846e
Public property auto-generates getter:
function staker(address staker) public constant returns(uint _amount, uint _time);
Auditing smart contracts in live stream: https://www.youtube.com/watch?v=efZY3_COaiE
Your CryptoManiacs :)
The following variables are not initialized:
uint public LastBlock;
uint public Timestamp;
The value of the following local variables will be affected.
uint _blocks = block.number - _LastBlock;
uint _seconds = now - Timestamp;
It will also affect the future values of timestamp:
Timestamp += _seconds;
If the above mentioned state variables won't be set in the constructor, the following condition will be true for a significant amount of time, which will stretch the time since the actual block time at the moment of writing is ~12 s
, and users will be able to claim in less than the real 27 days:
if (_seconds > _blocks * 25)
{
_seconds = _blocks * 25;
}
If the state variables are initialized in the constructor, the above mentioned condition won't be required. and Timestamp
can be set directly with now
value
here is what I think can optimize the code and solve the issue:
master...RideSolo:master
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.