From 4d96b8665a4b841492db8ecca3cffa1c84f4c5d9 Mon Sep 17 00:00:00 2001 From: Keshav Gupta Date: Tue, 9 Aug 2022 13:26:55 +0200 Subject: [PATCH] First push --- contracts/RlnERC20.sol | 100 ++ contracts/SntContract.sol | 1847 +++++++++++++++++++++++++++++++++++++ 2 files changed, 1947 insertions(+) create mode 100644 contracts/RlnERC20.sol create mode 100644 contracts/SntContract.sol diff --git a/contracts/RlnERC20.sol b/contracts/RlnERC20.sol new file mode 100644 index 0000000..23197e9 --- /dev/null +++ b/contracts/RlnERC20.sol @@ -0,0 +1,100 @@ +pragma solidity 0.7.4; + +import { IPoseidonHasher } from "./PoseidonHasher.sol"; + +contract RLN { + uint256 public immutable MEMBERSHIP_DEPOSIT; + uint256 public immutable DEPTH; + uint256 public immutable SET_SIZE; + + uint256 public pubkeyIndex = 0; + mapping(uint256 => uint256) public members; + + IPoseidonHasher public poseidonHasher; + + event MemberRegistered(uint256 pubkey, uint256 index); + event MemberWithdrawn(uint256 pubkey, uint256 index); + + IERC20 immutable AcceptedToken; + + constructor( + uint256 membershipDeposit, + uint256 depth, + address _poseidonHasher, + address _acceptedTokenAddress + ) public { + MEMBERSHIP_DEPOSIT = membershipDeposit; + DEPTH = depth; + SET_SIZE = 1 << depth; + poseidonHasher = IPoseidonHasher(_poseidonHasher); + AcceptedToken = IERC20(_acceptedTokenAddress) + } + + function registerWithAcceptedToken(uint256 deposit, uint256 pubkey) external payable { + require(pubkeyIndex < SET_SIZE, "RLN, register: set is full"); + require(deposit == MEMBERSHIP_DEPOSIT, "RLN, register: membership deposit is not satisfied"); + AcceptedToken.transferFrom(msg.sender,address(this),deposit); + _register(pubkey); + } + + function registerBatchWithAcceptedToken(uint256 deposit, uint256[] calldata pubkeys) external payable { + require(pubkeyIndex + pubkeys.length <= SET_SIZE, "RLN, registerBatch: set is full"); + require(deposit == MEMBERSHIP_DEPOSIT * pubkeys.length, "RLN, registerBatch: membership deposit is not satisfied"); + AcceptedToken.transferFrom(msg.sender,address(this),deposit); + for (uint256 i = 0; i < pubkeys.length; i++) { + _register(pubkeys[i]); + } + } + + function _register(uint256 pubkey) internal { + members[pubkeyIndex] = pubkey; + emit MemberRegistered(pubkey, pubkeyIndex); + pubkeyIndex += 1; + } + + function withdrawBatch( + uint256[] calldata secrets, + uint256[] calldata pubkeyIndexes + ) external { + uint256 batchSize = secrets.length; + require(batchSize != 0, "RLN, withdrawBatch: batch size zero"); + require(batchSize == pubkeyIndexes.length, "RLN, withdrawBatch: batch size mismatch pubkey indexes"); + require(batchSize == receivers.length, "RLN, withdrawBatch: batch size mismatch receivers"); + for (uint256 i = 0; i < batchSize; i++) { + _withdraw(secrets[i], pubkeyIndexes[i], msg.sender); + } + } + + function withdraw( + uint256 secret, + uint256 _pubkeyIndex + ) external { + _withdraw(secret, _pubkeyIndex, msg.sender); + } + + function _withdraw( + uint256 secret, + uint256 _pubkeyIndex, + address payable receiver + ) internal { + require(_pubkeyIndex < SET_SIZE, "RLN, _withdraw: invalid pubkey index"); + require(members[_pubkeyIndex] != 0, "RLN, _withdraw: member doesn't exist"); + require(receiver != address(0), "RLN, _withdraw: empty receiver address"); + + // derive public key + uint256 pubkey = hash([secret, 0]); + require(members[_pubkeyIndex] == pubkey, "RLN, _withdraw: not verified"); + + // delete member + members[_pubkeyIndex] = 0; + + // refund deposit + AcceptedToken.transferFrom(address(this),receiver,MEMBERSHIP_DEPOSIT) + + emit MemberWithdrawn(pubkey, _pubkeyIndex); + } + + function hash(uint256[2] memory input) internal view returns (uint256) { + return poseidonHasher.hash(input); + } +} \ No newline at end of file diff --git a/contracts/SntContract.sol b/contracts/SntContract.sol new file mode 100644 index 0000000..4ccd833 --- /dev/null +++ b/contracts/SntContract.sol @@ -0,0 +1,1847 @@ +/** + *Submitted for verification at Etherscan.io on 2017-06-19 +*/ + +pragma solidity ^0.4.11; + + +/// @dev `Owned` is a base level contract that assigns an `owner` that can be +/// later changed +contract Owned { + + /// @dev `owner` is the only address that can call a function with this + /// modifier + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + address public owner; + + /// @notice The Constructor assigns the message sender to be `owner` + function Owned() { + owner = msg.sender; + } + + address public newOwner; + + /// @notice `owner` can step down and assign some other address to this role + /// @param _newOwner The address of the new owner. 0x0 can be used to create + /// an unowned neutral vault, however that cannot be undone + function changeOwner(address _newOwner) onlyOwner { + newOwner = _newOwner; + } + + + function acceptOwnership() { + if (msg.sender == newOwner) { + owner = newOwner; + } + } +} + +// Abstract contract for the full ERC 20 Token standard +// https://github.com/ethereum/EIPs/issues/20 + +contract ERC20Token { + /* This is a slight change to the ERC20 base standard. + function totalSupply() constant returns (uint256 supply); + is replaced with: + uint256 public totalSupply; + This automatically creates a getter function for the totalSupply. + This is moved to the base contract since public getter functions are not + currently recognised as an implementation of the matching abstract + function by the compiler. + */ + /// total amount of tokens + uint256 public totalSupply; + + /// @param _owner The address from which the balance will be retrieved + /// @return The balance + function balanceOf(address _owner) constant returns (uint256 balance); + + /// @notice send `_value` token to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _value) returns (bool success); + + /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` + /// @param _from The address of the sender + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transferFrom(address _from, address _to, uint256 _value) returns (bool success); + + /// @notice `msg.sender` approves `_spender` to spend `_value` tokens + /// @param _spender The address of the account able to transfer the tokens + /// @param _value The amount of tokens to be approved for transfer + /// @return Whether the approval was successful or not + function approve(address _spender, uint256 _value) returns (bool success); + + /// @param _owner The address of the account owning tokens + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens allowed to spent + function allowance(address _owner, address _spender) constant returns (uint256 remaining); + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); +} + + + +/** + * Math operations with safety checks + */ +library SafeMath { + function mul(uint a, uint b) internal returns (uint) { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function div(uint a, uint b) internal returns (uint) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint a, uint b) internal returns (uint) { + assert(b <= a); + return a - b; + } + + function add(uint a, uint b) internal returns (uint) { + uint c = a + b; + assert(c >= a); + return c; + } + + function max64(uint64 a, uint64 b) internal constant returns (uint64) { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) internal constant returns (uint64) { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) internal constant returns (uint256) { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) internal constant returns (uint256) { + return a < b ? a : b; + } +} + + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title DynamicCeiling Contract +/// @author Jordi Baylina +/// @dev This contract calculates the ceiling from a series of curves. +/// These curves are committed first and revealed later. +/// All the curves must be in increasing order and the last curve is marked +/// as the last one. +/// This contract allows to hide and reveal the ceiling at will of the owner. + + + +contract DynamicCeiling is Owned { + using SafeMath for uint256; + + struct Curve { + bytes32 hash; + // Absolute limit for this curve + uint256 limit; + // The funds remaining to be collected are divided by `slopeFactor` smooth ceiling + // with a long tail where big and small buyers can take part. + uint256 slopeFactor; + // This keeps the curve flat at this number, until funds to be collected is less than this + uint256 collectMinimum; + } + + address public contribution; + + Curve[] public curves; + uint256 public currentIndex; + uint256 public revealedCurves; + bool public allRevealed; + + /// @dev `contribution` is the only address that can call a function with this + /// modifier + modifier onlyContribution { + require(msg.sender == contribution); + _; + } + + function DynamicCeiling(address _owner, address _contribution) { + owner = _owner; + contribution = _contribution; + } + + /// @notice This should be called by the creator of the contract to commit + /// all the curves. + /// @param _curveHashes Array of hashes of each curve. Each hash is calculated + /// by the `calculateHash` method. More hashes than actual curves can be + /// committed in order to hide also the number of curves. + /// The remaining hashes can be just random numbers. + function setHiddenCurves(bytes32[] _curveHashes) public onlyOwner { + require(curves.length == 0); + + curves.length = _curveHashes.length; + for (uint256 i = 0; i < _curveHashes.length; i = i.add(1)) { + curves[i].hash = _curveHashes[i]; + } + } + + + /// @notice Anybody can reveal the next curve if he knows it. + /// @param _limit Ceiling cap. + /// (must be greater or equal to the previous one). + /// @param _last `true` if it's the last curve. + /// @param _salt Random number used to commit the curve + function revealCurve(uint256 _limit, uint256 _slopeFactor, uint256 _collectMinimum, + bool _last, bytes32 _salt) public { + require(!allRevealed); + + require(curves[revealedCurves].hash == calculateHash(_limit, _slopeFactor, _collectMinimum, + _last, _salt)); + + require(_limit != 0 && _slopeFactor != 0 && _collectMinimum != 0); + if (revealedCurves > 0) { + require(_limit >= curves[revealedCurves.sub(1)].limit); + } + + curves[revealedCurves].limit = _limit; + curves[revealedCurves].slopeFactor = _slopeFactor; + curves[revealedCurves].collectMinimum = _collectMinimum; + revealedCurves = revealedCurves.add(1); + + if (_last) allRevealed = true; + } + + /// @notice Reveal multiple curves at once + function revealMulti(uint256[] _limits, uint256[] _slopeFactors, uint256[] _collectMinimums, + bool[] _lasts, bytes32[] _salts) public { + // Do not allow none and needs to be same length for all parameters + require(_limits.length != 0 && + _limits.length == _slopeFactors.length && + _limits.length == _collectMinimums.length && + _limits.length == _lasts.length && + _limits.length == _salts.length); + + for (uint256 i = 0; i < _limits.length; i = i.add(1)) { + revealCurve(_limits[i], _slopeFactors[i], _collectMinimums[i], + _lasts[i], _salts[i]); + } + } + + /// @notice Move to curve, used as a failsafe + function moveTo(uint256 _index) public onlyOwner { + require(_index < revealedCurves && // No more curves + _index == currentIndex.add(1)); // Only move one index at a time + currentIndex = _index; + } + + /// @return Return the funds to collect for the current point on the curve + /// (or 0 if no curves revealed yet) + function toCollect(uint256 collected) public onlyContribution returns (uint256) { + if (revealedCurves == 0) return 0; + + // Move to the next curve + if (collected >= curves[currentIndex].limit) { // Catches `limit == 0` + uint256 nextIndex = currentIndex.add(1); + if (nextIndex >= revealedCurves) return 0; // No more curves + currentIndex = nextIndex; + if (collected >= curves[currentIndex].limit) return 0; // Catches `limit == 0` + } + + // Everything left to collect from this limit + uint256 difference = curves[currentIndex].limit.sub(collected); + + // Current point on the curve + uint256 collect = difference.div(curves[currentIndex].slopeFactor); + + // Prevents paying too much fees vs to be collected; breaks long tail + if (collect <= curves[currentIndex].collectMinimum) { + if (difference > curves[currentIndex].collectMinimum) { + return curves[currentIndex].collectMinimum; + } else { + return difference; + } + } else { + return collect; + } + } + + /// @notice Calculates the hash of a curve. + /// @param _limit Ceiling cap. + /// @param _last `true` if it's the last curve. + /// @param _salt Random number that will be needed to reveal this curve. + /// @return The calculated hash of this curve to be used in the `setHiddenCurves` method + function calculateHash(uint256 _limit, uint256 _slopeFactor, uint256 _collectMinimum, + bool _last, bytes32 _salt) public constant returns (bytes32) { + return keccak256(_limit, _slopeFactor, _collectMinimum, _last, _salt); + } + + /// @return Return the total number of curves committed + /// (can be larger than the number of actual curves on the curve to hide + /// the real number of curves) + function nCurves() public constant returns (uint256) { + return curves.length; + } + +} + + +/* + Copyright 2016, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title MiniMeToken Contract +/// @author Jordi Baylina +/// @dev This token contract's goal is to make it easy for anyone to clone this +/// token using the token distribution at a given block, this will allow DAO's +/// and DApps to upgrade their features in a decentralized manner without +/// affecting the original token +/// @dev It is ERC20 compliant, but still needs to under go further testing. + + +/// @dev The token controller contract must implement these functions +contract TokenController { + /// @notice Called when `_owner` sends ether to the MiniMe Token contract + /// @param _owner The address that sent the ether to create tokens + /// @return True if the ether is accepted, false if it throws + function proxyPayment(address _owner) payable returns(bool); + + /// @notice Notifies the controller about a token transfer allowing the + /// controller to react if desired + /// @param _from The origin of the transfer + /// @param _to The destination of the transfer + /// @param _amount The amount of the transfer + /// @return False if the controller does not authorize the transfer + function onTransfer(address _from, address _to, uint _amount) returns(bool); + + /// @notice Notifies the controller about an approval allowing the + /// controller to react if desired + /// @param _owner The address that calls `approve()` + /// @param _spender The spender in the `approve()` call + /// @param _amount The amount in the `approve()` call + /// @return False if the controller does not authorize the approval + function onApprove(address _owner, address _spender, uint _amount) + returns(bool); +} + +contract Controlled { + /// @notice The address of the controller is the only address that can call + /// a function with this modifier + modifier onlyController { if (msg.sender != controller) throw; _; } + + address public controller; + + function Controlled() { controller = msg.sender;} + + /// @notice Changes the controller of the contract + /// @param _newController The new controller of the contract + function changeController(address _newController) onlyController { + controller = _newController; + } +} + +contract ApproveAndCallFallBack { + function receiveApproval(address from, uint256 _amount, address _token, bytes _data); +} + +/// @dev The actual token contract, the default controller is the msg.sender +/// that deploys the contract, so usually this token will be deployed by a +/// token controller contract, which Giveth will call a "Campaign" +contract MiniMeToken is Controlled { + + string public name; //The Token's name: e.g. DigixDAO Tokens + uint8 public decimals; //Number of decimals of the smallest unit + string public symbol; //An identifier: e.g. REP + string public version = 'MMT_0.1'; //An arbitrary versioning scheme + + + /// @dev `Checkpoint` is the structure that attaches a block number to a + /// given value, the block number attached is the one that last changed the + /// value + struct Checkpoint { + + // `fromBlock` is the block number that the value was generated from + uint128 fromBlock; + + // `value` is the amount of tokens at a specific block number + uint128 value; + } + + // `parentToken` is the Token address that was cloned to produce this token; + // it will be 0x0 for a token that was not cloned + MiniMeToken public parentToken; + + // `parentSnapShotBlock` is the block number from the Parent Token that was + // used to determine the initial distribution of the Clone Token + uint public parentSnapShotBlock; + + // `creationBlock` is the block number that the Clone Token was created + uint public creationBlock; + + // `balances` is the map that tracks the balance of each address, in this + // contract when the balance changes the block number that the change + // occurred is also included in the map + mapping (address => Checkpoint[]) balances; + + // `allowed` tracks any extra transfer rights as in all ERC20 tokens + mapping (address => mapping (address => uint256)) allowed; + + // Tracks the history of the `totalSupply` of the token + Checkpoint[] totalSupplyHistory; + + // Flag that determines if the token is transferable or not. + bool public transfersEnabled; + + // The factory used to create new clone tokens + MiniMeTokenFactory public tokenFactory; + +//////////////// +// Constructor +//////////////// + + /// @notice Constructor to create a MiniMeToken + /// @param _tokenFactory The address of the MiniMeTokenFactory contract that + /// will create the Clone token contracts, the token factory needs to be + /// deployed first + /// @param _parentToken Address of the parent token, set to 0x0 if it is a + /// new token + /// @param _parentSnapShotBlock Block of the parent token that will + /// determine the initial distribution of the clone token, set to 0 if it + /// is a new token + /// @param _tokenName Name of the new token + /// @param _decimalUnits Number of decimals of the new token + /// @param _tokenSymbol Token Symbol for the new token + /// @param _transfersEnabled If true, tokens will be able to be transferred + function MiniMeToken( + address _tokenFactory, + address _parentToken, + uint _parentSnapShotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) { + tokenFactory = MiniMeTokenFactory(_tokenFactory); + name = _tokenName; // Set the name + decimals = _decimalUnits; // Set the decimals + symbol = _tokenSymbol; // Set the symbol + parentToken = MiniMeToken(_parentToken); + parentSnapShotBlock = _parentSnapShotBlock; + transfersEnabled = _transfersEnabled; + creationBlock = getBlockNumber(); + } + + +/////////////////// +// ERC20 Methods +/////////////////// + + /// @notice Send `_amount` tokens to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _amount) returns (bool success) { + if (!transfersEnabled) throw; + return doTransfer(msg.sender, _to, _amount); + } + + /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it + /// is approved by `_from` + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function transferFrom(address _from, address _to, uint256 _amount + ) returns (bool success) { + + // The controller of this contract can move tokens around at will, + // this is important to recognize! Confirm that you trust the + // controller of this contract, which in most situations should be + // another open source smart contract or 0x0 + if (msg.sender != controller) { + if (!transfersEnabled) throw; + + // The standard ERC 20 transferFrom functionality + if (allowed[_from][msg.sender] < _amount) return false; + allowed[_from][msg.sender] -= _amount; + } + return doTransfer(_from, _to, _amount); + } + + /// @dev This is the actual transfer function in the token contract, it can + /// only be called by other functions in this contract. + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function doTransfer(address _from, address _to, uint _amount + ) internal returns(bool) { + + if (_amount == 0) { + return true; + } + + if (parentSnapShotBlock >= getBlockNumber()) throw; + + // Do not allow transfer to 0x0 or the token contract itself + if ((_to == 0) || (_to == address(this))) throw; + + // If the amount being transfered is more than the balance of the + // account the transfer returns false + var previousBalanceFrom = balanceOfAt(_from, getBlockNumber()); + if (previousBalanceFrom < _amount) { + return false; + } + + // Alerts the token controller of the transfer + if (isContract(controller)) { + if (!TokenController(controller).onTransfer(_from, _to, _amount)) + throw; + } + + // First update the balance array with the new value for the address + // sending the tokens + updateValueAtNow(balances[_from], previousBalanceFrom - _amount); + + // Then update the balance array with the new value for the address + // receiving the tokens + var previousBalanceTo = balanceOfAt(_to, getBlockNumber()); + if (previousBalanceTo + _amount < previousBalanceTo) throw; // Check for overflow + updateValueAtNow(balances[_to], previousBalanceTo + _amount); + + // An event to make the transfer easy to find on the blockchain + Transfer(_from, _to, _amount); + + return true; + } + + /// @param _owner The address that's balance is being requested + /// @return The balance of `_owner` at the current block + function balanceOf(address _owner) constant returns (uint256 balance) { + return balanceOfAt(_owner, getBlockNumber()); + } + + /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on + /// its behalf. This is a modified version of the ERC20 approve function + /// to be a little bit safer + /// @param _spender The address of the account able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the approval was successful + function approve(address _spender, uint256 _amount) returns (bool success) { + if (!transfersEnabled) throw; + + // To change the approve amount you first have to reduce the addresses` + // allowance to zero by calling `approve(_spender,0)` if it is not + // already 0 to mitigate the race condition described here: + // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + if ((_amount!=0) && (allowed[msg.sender][_spender] !=0)) throw; + + // Alerts the token controller of the approve function call + if (isContract(controller)) { + if (!TokenController(controller).onApprove(msg.sender, _spender, _amount)) + throw; + } + + allowed[msg.sender][_spender] = _amount; + Approval(msg.sender, _spender, _amount); + return true; + } + + /// @dev This function makes it easy to read the `allowed[]` map + /// @param _owner The address of the account that owns the token + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens of _owner that _spender is allowed + /// to spend + function allowance(address _owner, address _spender + ) constant returns (uint256 remaining) { + return allowed[_owner][_spender]; + } + + /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on + /// its behalf, and then a function is triggered in the contract that is + /// being approved, `_spender`. This allows users to use their tokens to + /// interact with contracts in one function call instead of two + /// @param _spender The address of the contract able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the function call was successful + function approveAndCall(address _spender, uint256 _amount, bytes _extraData + ) returns (bool success) { + if (!approve(_spender, _amount)) throw; + + ApproveAndCallFallBack(_spender).receiveApproval( + msg.sender, + _amount, + this, + _extraData + ); + + return true; + } + + /// @dev This function makes it easy to get the total number of tokens + /// @return The total number of tokens + function totalSupply() constant returns (uint) { + return totalSupplyAt(getBlockNumber()); + } + + +//////////////// +// Query balance and totalSupply in History +//////////////// + + /// @dev Queries the balance of `_owner` at a specific `_blockNumber` + /// @param _owner The address from which the balance will be retrieved + /// @param _blockNumber The block number when the balance is queried + /// @return The balance at `_blockNumber` + function balanceOfAt(address _owner, uint _blockNumber) constant + returns (uint) { + + // These next few lines are used when the balance of the token is + // requested before a check point was ever created for this token, it + // requires that the `parentToken.balanceOfAt` be queried at the + // genesis block for that token as this contains initial balance of + // this token + if ((balances[_owner].length == 0) + || (balances[_owner][0].fromBlock > _blockNumber)) { + if (address(parentToken) != 0) { + return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock)); + } else { + // Has no parent + return 0; + } + + // This will return the expected balance during normal situations + } else { + return getValueAt(balances[_owner], _blockNumber); + } + } + + /// @notice Total amount of tokens at a specific `_blockNumber`. + /// @param _blockNumber The block number when the totalSupply is queried + /// @return The total amount of tokens at `_blockNumber` + function totalSupplyAt(uint _blockNumber) constant returns(uint) { + + // These next few lines are used when the totalSupply of the token is + // requested before a check point was ever created for this token, it + // requires that the `parentToken.totalSupplyAt` be queried at the + // genesis block for this token as that contains totalSupply of this + // token at this block number. + if ((totalSupplyHistory.length == 0) + || (totalSupplyHistory[0].fromBlock > _blockNumber)) { + if (address(parentToken) != 0) { + return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock)); + } else { + return 0; + } + + // This will return the expected totalSupply during normal situations + } else { + return getValueAt(totalSupplyHistory, _blockNumber); + } + } + +//////////////// +// Clone Token Method +//////////////// + + /// @notice Creates a new clone token with the initial distribution being + /// this token at `_snapshotBlock` + /// @param _cloneTokenName Name of the clone token + /// @param _cloneDecimalUnits Number of decimals of the smallest unit + /// @param _cloneTokenSymbol Symbol of the clone token + /// @param _snapshotBlock Block when the distribution of the parent token is + /// copied to set the initial distribution of the new clone token; + /// if the block is zero than the actual block, the current block is used + /// @param _transfersEnabled True if transfers are allowed in the clone + /// @return The address of the new MiniMeToken Contract + function createCloneToken( + string _cloneTokenName, + uint8 _cloneDecimalUnits, + string _cloneTokenSymbol, + uint _snapshotBlock, + bool _transfersEnabled + ) returns(address) { + if (_snapshotBlock == 0) _snapshotBlock = getBlockNumber(); + MiniMeToken cloneToken = tokenFactory.createCloneToken( + this, + _snapshotBlock, + _cloneTokenName, + _cloneDecimalUnits, + _cloneTokenSymbol, + _transfersEnabled + ); + + cloneToken.changeController(msg.sender); + + // An event to make the token easy to find on the blockchain + NewCloneToken(address(cloneToken), _snapshotBlock); + return address(cloneToken); + } + +//////////////// +// Generate and destroy tokens +//////////////// + + /// @notice Generates `_amount` tokens that are assigned to `_owner` + /// @param _owner The address that will be assigned the new tokens + /// @param _amount The quantity of tokens generated + /// @return True if the tokens are generated correctly + function generateTokens(address _owner, uint _amount + ) onlyController returns (bool) { + uint curTotalSupply = getValueAt(totalSupplyHistory, getBlockNumber()); + if (curTotalSupply + _amount < curTotalSupply) throw; // Check for overflow + updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount); + var previousBalanceTo = balanceOf(_owner); + if (previousBalanceTo + _amount < previousBalanceTo) throw; // Check for overflow + updateValueAtNow(balances[_owner], previousBalanceTo + _amount); + Transfer(0, _owner, _amount); + return true; + } + + + /// @notice Burns `_amount` tokens from `_owner` + /// @param _owner The address that will lose the tokens + /// @param _amount The quantity of tokens to burn + /// @return True if the tokens are burned correctly + function destroyTokens(address _owner, uint _amount + ) onlyController returns (bool) { + uint curTotalSupply = getValueAt(totalSupplyHistory, getBlockNumber()); + if (curTotalSupply < _amount) throw; + updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount); + var previousBalanceFrom = balanceOf(_owner); + if (previousBalanceFrom < _amount) throw; + updateValueAtNow(balances[_owner], previousBalanceFrom - _amount); + Transfer(_owner, 0, _amount); + return true; + } + +//////////////// +// Enable tokens transfers +//////////////// + + + /// @notice Enables token holders to transfer their tokens freely if true + /// @param _transfersEnabled True if transfers are allowed in the clone + function enableTransfers(bool _transfersEnabled) onlyController { + transfersEnabled = _transfersEnabled; + } + +//////////////// +// Internal helper functions to query and set a value in a snapshot array +//////////////// + + /// @dev `getValueAt` retrieves the number of tokens at a given block number + /// @param checkpoints The history of values being queried + /// @param _block The block number to retrieve the value at + /// @return The number of tokens being queried + function getValueAt(Checkpoint[] storage checkpoints, uint _block + ) constant internal returns (uint) { + if (checkpoints.length == 0) return 0; + + // Shortcut for the actual value + if (_block >= checkpoints[checkpoints.length-1].fromBlock) + return checkpoints[checkpoints.length-1].value; + if (_block < checkpoints[0].fromBlock) return 0; + + // Binary search of the value in the array + uint min = 0; + uint max = checkpoints.length-1; + while (max > min) { + uint mid = (max + min + 1)/ 2; + if (checkpoints[mid].fromBlock<=_block) { + min = mid; + } else { + max = mid-1; + } + } + return checkpoints[min].value; + } + + /// @dev `updateValueAtNow` used to update the `balances` map and the + /// `totalSupplyHistory` + /// @param checkpoints The history of data being updated + /// @param _value The new number of tokens + function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value + ) internal { + if ((checkpoints.length == 0) + || (checkpoints[checkpoints.length -1].fromBlock < getBlockNumber())) { + Checkpoint newCheckPoint = checkpoints[ checkpoints.length++ ]; + newCheckPoint.fromBlock = uint128(getBlockNumber()); + newCheckPoint.value = uint128(_value); + } else { + Checkpoint oldCheckPoint = checkpoints[checkpoints.length-1]; + oldCheckPoint.value = uint128(_value); + } + } + + /// @dev Internal function to determine if an address is a contract + /// @param _addr The address being queried + /// @return True if `_addr` is a contract + function isContract(address _addr) constant internal returns(bool) { + uint size; + if (_addr == 0) return false; + assembly { + size := extcodesize(_addr) + } + return size>0; + } + + /// @dev Helper function to return a min betwen the two uints + function min(uint a, uint b) internal returns (uint) { + return a < b ? a : b; + } + + /// @notice The fallback function: If the contract's controller has not been + /// set to 0, then the `proxyPayment` method is called which relays the + /// ether and creates tokens as described in the token controller contract + function () payable { + if (isContract(controller)) { + if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender)) + throw; + } else { + throw; + } + } + + +////////// +// Testing specific methods +////////// + + /// @notice This function is overridden by the test Mocks. + function getBlockNumber() internal constant returns (uint256) { + return block.number; + } + +////////// +// Safety Methods +////////// + + /// @notice This method can be used by the controller to extract mistakenly + /// sent tokens to this contract. + /// @param _token The address of the token contract that you want to recover + /// set to 0 in case you want to extract ether. + function claimTokens(address _token) onlyController { + if (_token == 0x0) { + controller.transfer(this.balance); + return; + } + + ERC20Token token = ERC20Token(_token); + uint balance = token.balanceOf(this); + token.transfer(controller, balance); + ClaimedTokens(_token, controller, balance); + } + +//////////////// +// Events +//////////////// + + event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount); + event Transfer(address indexed _from, address indexed _to, uint256 _amount); + event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock); + event Approval( + address indexed _owner, + address indexed _spender, + uint256 _amount + ); + +} + + +//////////////// +// MiniMeTokenFactory +//////////////// + +/// @dev This contract is used to generate clone contracts from a contract. +/// In solidity this is the way to create a contract from a contract of the +/// same class +contract MiniMeTokenFactory { + + /// @notice Update the DApp by creating a new token with new functionalities + /// the msg.sender becomes the controller of this clone token + /// @param _parentToken Address of the token being cloned + /// @param _snapshotBlock Block of the parent token that will + /// determine the initial distribution of the clone token + /// @param _tokenName Name of the new token + /// @param _decimalUnits Number of decimals of the new token + /// @param _tokenSymbol Token Symbol for the new token + /// @param _transfersEnabled If true, tokens will be able to be transferred + /// @return The address of the new token contract + function createCloneToken( + address _parentToken, + uint _snapshotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) returns (MiniMeToken) { + MiniMeToken newToken = new MiniMeToken( + this, + _parentToken, + _snapshotBlock, + _tokenName, + _decimalUnits, + _tokenSymbol, + _transfersEnabled + ); + + newToken.changeController(msg.sender); + return newToken; + } +} + + +/* + Copyright 2017, Jarrad Hope (Status Research & Development GmbH) +*/ + + +contract SNT is MiniMeToken { + // @dev SNT constructor just parametrizes the MiniMeIrrevocableVestedToken constructor + function SNT(address _tokenFactory) + MiniMeToken( + _tokenFactory, + 0x0, // no parent token + 0, // no snapshot block number from parent + "Status Network Token", // Token name + 18, // Decimals + "SNT", // Symbol + true // Enable transfers + ) {} +} + + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title StatusContribution Contract +/// @author Jordi Baylina +/// @dev This contract will be the SNT controller during the contribution period. +/// This contract will determine the rules during this period. +/// Final users will generally not interact directly with this contract. ETH will +/// be sent to the SNT token contract. The ETH is sent to this contract and from here, +/// ETH is sent to the contribution walled and SNTs are mined according to the defined +/// rules. + + +contract StatusContribution is Owned, TokenController { + using SafeMath for uint256; + + uint256 constant public failSafeLimit = 300000 ether; + uint256 constant public maxGuaranteedLimit = 30000 ether; + uint256 constant public exchangeRate = 10000; + uint256 constant public maxGasPrice = 50000000000; + uint256 constant public maxCallFrequency = 100; + + MiniMeToken public SGT; + MiniMeToken public SNT; + uint256 public startBlock; + uint256 public endBlock; + + address public destEthDevs; + + address public destTokensDevs; + address public destTokensReserve; + uint256 public maxSGTSupply; + address public destTokensSgt; + DynamicCeiling public dynamicCeiling; + + address public sntController; + + mapping (address => uint256) public guaranteedBuyersLimit; + mapping (address => uint256) public guaranteedBuyersBought; + + uint256 public totalGuaranteedCollected; + uint256 public totalNormalCollected; + + uint256 public finalizedBlock; + uint256 public finalizedTime; + + mapping (address => uint256) public lastCallBlock; + + bool public paused; + + modifier initialized() { + require(address(SNT) != 0x0); + _; + } + + modifier contributionOpen() { + require(getBlockNumber() >= startBlock && + getBlockNumber() <= endBlock && + finalizedBlock == 0 && + address(SNT) != 0x0); + _; + } + + modifier notPaused() { + require(!paused); + _; + } + + function StatusContribution() { + paused = false; + } + + + /// @notice This method should be called by the owner before the contribution + /// period starts This initializes most of the parameters + /// @param _snt Address of the SNT token contract + /// @param _sntController Token controller for the SNT that will be transferred after + /// the contribution finalizes. + /// @param _startBlock Block when the contribution period starts + /// @param _endBlock The last block that the contribution period is active + /// @param _dynamicCeiling Address of the contract that controls the ceiling + /// @param _destEthDevs Destination address where the contribution ether is sent + /// @param _destTokensReserve Address where the tokens for the reserve are sent + /// @param _destTokensSgt Address of the exchanger SGT-SNT where the SNT are sent + /// to be distributed to the SGT holders. + /// @param _destTokensDevs Address where the tokens for the dev are sent + /// @param _sgt Address of the SGT token contract + /// @param _maxSGTSupply Quantity of SGT tokens that would represent 10% of status. + function initialize( + address _snt, + address _sntController, + + uint256 _startBlock, + uint256 _endBlock, + + address _dynamicCeiling, + + address _destEthDevs, + + address _destTokensReserve, + address _destTokensSgt, + address _destTokensDevs, + + address _sgt, + uint256 _maxSGTSupply + ) public onlyOwner { + // Initialize only once + require(address(SNT) == 0x0); + + SNT = MiniMeToken(_snt); + require(SNT.totalSupply() == 0); + require(SNT.controller() == address(this)); + require(SNT.decimals() == 18); // Same amount of decimals as ETH + + require(_sntController != 0x0); + sntController = _sntController; + + require(_startBlock >= getBlockNumber()); + require(_startBlock < _endBlock); + startBlock = _startBlock; + endBlock = _endBlock; + + require(_dynamicCeiling != 0x0); + dynamicCeiling = DynamicCeiling(_dynamicCeiling); + + require(_destEthDevs != 0x0); + destEthDevs = _destEthDevs; + + require(_destTokensReserve != 0x0); + destTokensReserve = _destTokensReserve; + + require(_destTokensSgt != 0x0); + destTokensSgt = _destTokensSgt; + + require(_destTokensDevs != 0x0); + destTokensDevs = _destTokensDevs; + + require(_sgt != 0x0); + SGT = MiniMeToken(_sgt); + + require(_maxSGTSupply >= MiniMeToken(SGT).totalSupply()); + maxSGTSupply = _maxSGTSupply; + } + + /// @notice Sets the limit for a guaranteed address. All the guaranteed addresses + /// will be able to get SNTs during the contribution period with his own + /// specific limit. + /// This method should be called by the owner after the initialization + /// and before the contribution starts. + /// @param _th Guaranteed address + /// @param _limit Limit for the guaranteed address. + function setGuaranteedAddress(address _th, uint256 _limit) public initialized onlyOwner { + require(getBlockNumber() < startBlock); + require(_limit > 0 && _limit <= maxGuaranteedLimit); + guaranteedBuyersLimit[_th] = _limit; + GuaranteedAddress(_th, _limit); + } + + /// @notice If anybody sends Ether directly to this contract, consider he is + /// getting SNTs. + function () public payable notPaused { + proxyPayment(msg.sender); + } + + + ////////// + // MiniMe Controller functions + ////////// + + /// @notice This method will generally be called by the SNT token contract to + /// acquire SNTs. Or directly from third parties that want to acquire SNTs in + /// behalf of a token holder. + /// @param _th SNT holder where the SNTs will be minted. + function proxyPayment(address _th) public payable notPaused initialized contributionOpen returns (bool) { + require(_th != 0x0); + if (guaranteedBuyersLimit[_th] > 0) { + buyGuaranteed(_th); + } else { + buyNormal(_th); + } + return true; + } + + function onTransfer(address, address, uint256) public returns (bool) { + return false; + } + + function onApprove(address, address, uint256) public returns (bool) { + return false; + } + + function buyNormal(address _th) internal { + require(tx.gasprice <= maxGasPrice); + + // Antispam mechanism + address caller; + if (msg.sender == address(SNT)) { + caller = _th; + } else { + caller = msg.sender; + } + + // Do not allow contracts to game the system + require(!isContract(caller)); + + require(getBlockNumber().sub(lastCallBlock[caller]) >= maxCallFrequency); + lastCallBlock[caller] = getBlockNumber(); + + uint256 toCollect = dynamicCeiling.toCollect(totalNormalCollected); + + uint256 toFund; + if (msg.value <= toCollect) { + toFund = msg.value; + } else { + toFund = toCollect; + } + + totalNormalCollected = totalNormalCollected.add(toFund); + doBuy(_th, toFund, false); + } + + function buyGuaranteed(address _th) internal { + uint256 toCollect = guaranteedBuyersLimit[_th]; + + uint256 toFund; + if (guaranteedBuyersBought[_th].add(msg.value) > toCollect) { + toFund = toCollect.sub(guaranteedBuyersBought[_th]); + } else { + toFund = msg.value; + } + + guaranteedBuyersBought[_th] = guaranteedBuyersBought[_th].add(toFund); + totalGuaranteedCollected = totalGuaranteedCollected.add(toFund); + doBuy(_th, toFund, true); + } + + function doBuy(address _th, uint256 _toFund, bool _guaranteed) internal { + assert(msg.value >= _toFund); // Not needed, but double check. + assert(totalCollected() <= failSafeLimit); + + if (_toFund > 0) { + uint256 tokensGenerated = _toFund.mul(exchangeRate); + assert(SNT.generateTokens(_th, tokensGenerated)); + destEthDevs.transfer(_toFund); + NewSale(_th, _toFund, tokensGenerated, _guaranteed); + } + + uint256 toReturn = msg.value.sub(_toFund); + if (toReturn > 0) { + // If the call comes from the Token controller, + // then we return it to the token Holder. + // Otherwise we return to the sender. + if (msg.sender == address(SNT)) { + _th.transfer(toReturn); + } else { + msg.sender.transfer(toReturn); + } + } + } + + // NOTE on Percentage format + // Right now, Solidity does not support decimal numbers. (This will change very soon) + // So in this contract we use a representation of a percentage that consist in + // expressing the percentage in "x per 10**18" + // This format has a precision of 16 digits for a percent. + // Examples: + // 3% = 3*(10**16) + // 100% = 100*(10**16) = 10**18 + // + // To get a percentage of a value we do it by first multiplying it by the percentage in (x per 10^18) + // and then divide it by 10**18 + // + // Y * X(in x per 10**18) + // X% of Y = ------------------------- + // 100(in x per 10**18) + // + + + /// @notice This method will can be called by the owner before the contribution period + /// end or by anybody after the `endBlock`. This method finalizes the contribution period + /// by creating the remaining tokens and transferring the controller to the configured + /// controller. + function finalize() public initialized { + require(getBlockNumber() >= startBlock); + require(msg.sender == owner || getBlockNumber() > endBlock); + require(finalizedBlock == 0); + + // Do not allow termination until all curves revealed. + require(dynamicCeiling.allRevealed()); + + // Allow premature finalization if final limit is reached + if (getBlockNumber() <= endBlock) { + var (,lastLimit,,) = dynamicCeiling.curves(dynamicCeiling.revealedCurves().sub(1)); + require(totalNormalCollected >= lastLimit); + } + + finalizedBlock = getBlockNumber(); + finalizedTime = now; + + uint256 percentageToSgt; + if (SGT.totalSupply() >= maxSGTSupply) { + percentageToSgt = percent(10); // 10% + } else { + + // + // SGT.totalSupply() + // percentageToSgt = 10% * ------------------- + // maxSGTSupply + // + percentageToSgt = percent(10).mul(SGT.totalSupply()).div(maxSGTSupply); + } + + uint256 percentageToDevs = percent(20); // 20% + + + // + // % To Contributors = 41% + (10% - % to SGT holders) + // + uint256 percentageToContributors = percent(41).add(percent(10).sub(percentageToSgt)); + + uint256 percentageToReserve = percent(29); + + + // SNT.totalSupply() -> Tokens minted during the contribution + // totalTokens -> Total tokens that should be after the allocation + // of devTokens, sgtTokens and reserve + // percentageToContributors -> Which percentage should go to the + // contribution participants + // (x per 10**18 format) + // percent(100) -> 100% in (x per 10**18 format) + // + // percentageToContributors + // SNT.totalSupply() = -------------------------- * totalTokens => + // percent(100) + // + // + // percent(100) + // => totalTokens = ---------------------------- * SNT.totalSupply() + // percentageToContributors + // + uint256 totalTokens = SNT.totalSupply().mul(percent(100)).div(percentageToContributors); + + + // Generate tokens for SGT Holders. + + // + // percentageToReserve + // reserveTokens = ----------------------- * totalTokens + // percentage(100) + // + assert(SNT.generateTokens( + destTokensReserve, + totalTokens.mul(percentageToReserve).div(percent(100)))); + + // + // percentageToSgt + // sgtTokens = ----------------------- * totalTokens + // percentage(100) + // + assert(SNT.generateTokens( + destTokensSgt, + totalTokens.mul(percentageToSgt).div(percent(100)))); + + + // + // percentageToDevs + // devTokens = ----------------------- * totalTokens + // percentage(100) + // + assert(SNT.generateTokens( + destTokensDevs, + totalTokens.mul(percentageToDevs).div(percent(100)))); + + SNT.changeController(sntController); + + Finalized(); + } + + function percent(uint256 p) internal returns (uint256) { + return p.mul(10**16); + } + + /// @dev Internal function to determine if an address is a contract + /// @param _addr The address being queried + /// @return True if `_addr` is a contract + function isContract(address _addr) constant internal returns (bool) { + if (_addr == 0) return false; + uint256 size; + assembly { + size := extcodesize(_addr) + } + return (size > 0); + } + + + ////////// + // Constant functions + ////////// + + /// @return Total tokens issued in weis. + function tokensIssued() public constant returns (uint256) { + return SNT.totalSupply(); + } + + /// @return Total Ether collected. + function totalCollected() public constant returns (uint256) { + return totalNormalCollected.add(totalGuaranteedCollected); + } + + + ////////// + // Testing specific methods + ////////// + + /// @notice This function is overridden by the test Mocks. + function getBlockNumber() internal constant returns (uint256) { + return block.number; + } + + + ////////// + // Safety Methods + ////////// + + /// @notice This method can be used by the controller to extract mistakenly + /// sent tokens to this contract. + /// @param _token The address of the token contract that you want to recover + /// set to 0 in case you want to extract ether. + function claimTokens(address _token) public onlyOwner { + if (SNT.controller() == address(this)) { + SNT.claimTokens(_token); + } + if (_token == 0x0) { + owner.transfer(this.balance); + return; + } + + ERC20Token token = ERC20Token(_token); + uint256 balance = token.balanceOf(this); + token.transfer(owner, balance); + ClaimedTokens(_token, owner, balance); + } + + + /// @notice Pauses the contribution if there is any issue + function pauseContribution() onlyOwner { + paused = true; + } + + /// @notice Resumes the contribution + function resumeContribution() onlyOwner { + paused = false; + } + + event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount); + event NewSale(address indexed _th, uint256 _amount, uint256 _tokens, bool _guaranteed); + event GuaranteedAddress(address indexed _th, uint256 _limit); + event Finalized(); +} + + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title ContributionWallet Contract +/// @author Jordi Baylina +/// @dev This contract will be hold the Ether during the contribution period. +/// The idea of this contract is to avoid recycling Ether during the contribution +/// period. So all the ETH collected will be locked here until the contribution +/// period ends + +// @dev Contract to hold sale raised funds during the sale period. +// Prevents attack in which the Aragon Multisig sends raised ether +// to the sale contract to mint tokens to itself, and getting the +// funds back immediately. + + + +contract ContributionWallet { + + // Public variables + address public multisig; + uint256 public endBlock; + StatusContribution public contribution; + + // @dev Constructor initializes public variables + // @param _multisig The address of the multisig that will receive the funds + // @param _endBlock Block after which the multisig can request the funds + // @param _contribution Address of the StatusContribution contract + function ContributionWallet(address _multisig, uint256 _endBlock, address _contribution) { + require(_multisig != 0x0); + require(_contribution != 0x0); + require(_endBlock != 0 && _endBlock <= 4000000); + multisig = _multisig; + endBlock = _endBlock; + contribution = StatusContribution(_contribution); + } + + // @dev Receive all sent funds without any further logic + function () public payable {} + + // @dev Withdraw function sends all the funds to the wallet if conditions are correct + function withdraw() public { + require(msg.sender == multisig); // Only the multisig can request it + require(block.number > endBlock || // Allow after end block + contribution.finalizedBlock() != 0); // Allow when sale is finalized + multisig.transfer(this.balance); + } + +} + + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title DevTokensHolder Contract +/// @author Jordi Baylina +/// @dev This contract will hold the tokens of the developers. +/// Tokens will not be able to be collected until 6 months after the contribution +/// period ends. And it will be increasing linearly until 2 years. + + +// collectable tokens +// | _/-------- vestedTokens rect +// | _/ +// | _/ +// | _/ +// | _/ +// | _/ +// | _/ +// | _/ +// | | +// | . | +// | . | +// | . | +// +===+======+--------------+----------> time +// Contrib 6 Months 24 Months +// End + + + +contract DevTokensHolder is Owned { + using SafeMath for uint256; + + uint256 collectedTokens; + StatusContribution contribution; + MiniMeToken snt; + + function DevTokensHolder(address _owner, address _contribution, address _snt) { + owner = _owner; + contribution = StatusContribution(_contribution); + snt = MiniMeToken(_snt); + } + + + /// @notice The Dev (Owner) will call this method to extract the tokens + function collectTokens() public onlyOwner { + uint256 balance = snt.balanceOf(address(this)); + uint256 total = collectedTokens.add(balance); + + uint256 finalizedTime = contribution.finalizedTime(); + + require(finalizedTime > 0 && getTime() > finalizedTime.add(months(6))); + + uint256 canExtract = total.mul(getTime().sub(finalizedTime)).div(months(24)); + + canExtract = canExtract.sub(collectedTokens); + + if (canExtract > balance) { + canExtract = balance; + } + + collectedTokens = collectedTokens.add(canExtract); + assert(snt.transfer(owner, canExtract)); + + TokensWithdrawn(owner, canExtract); + } + + function months(uint256 m) internal returns (uint256) { + return m.mul(30 days); + } + + function getTime() internal returns (uint256) { + return now; + } + + + ////////// + // Safety Methods + ////////// + + /// @notice This method can be used by the controller to extract mistakenly + /// sent tokens to this contract. + /// @param _token The address of the token contract that you want to recover + /// set to 0 in case you want to extract ether. + function claimTokens(address _token) public onlyOwner { + require(_token != address(snt)); + if (_token == 0x0) { + owner.transfer(this.balance); + return; + } + + ERC20Token token = ERC20Token(_token); + uint256 balance = token.balanceOf(this); + token.transfer(owner, balance); + ClaimedTokens(_token, owner, balance); + } + + event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount); + event TokensWithdrawn(address indexed _holder, uint256 _amount); +} + + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title SGTExchanger Contract +/// @author Jordi Baylina +/// @dev This contract will be used to distribute SNT between SGT holders. +/// SGT token is not transferable, and we just keep an accounting between all tokens +/// deposited and the tokens collected. +/// The controllerShip of SGT should be transferred to this contract before the +/// contribution period starts. + + +contract SGTExchanger is TokenController, Owned { + using SafeMath for uint256; + + mapping (address => uint256) public collected; + uint256 public totalCollected; + MiniMeToken public sgt; + MiniMeToken public snt; + StatusContribution public statusContribution; + + function SGTExchanger(address _sgt, address _snt, address _statusContribution) { + sgt = MiniMeToken(_sgt); + snt = MiniMeToken(_snt); + statusContribution = StatusContribution(_statusContribution); + } + + /// @notice This method should be called by the SGT holders to collect their + /// corresponding SNTs + function collect() public { + uint256 finalizedBlock = statusContribution.finalizedBlock(); + + require(finalizedBlock != 0); + require(getBlockNumber() > finalizedBlock); + + uint256 total = totalCollected.add(snt.balanceOf(address(this))); + + uint256 balance = sgt.balanceOfAt(msg.sender, finalizedBlock); + + // First calculate how much correspond to him + uint256 amount = total.mul(balance).div(sgt.totalSupplyAt(finalizedBlock)); + + // And then subtract the amount already collected + amount = amount.sub(collected[msg.sender]); + + require(amount > 0); // Notify the user that there are no tokens to exchange + + totalCollected = totalCollected.add(amount); + collected[msg.sender] = collected[msg.sender].add(amount); + + assert(snt.transfer(msg.sender, amount)); + + TokensCollected(msg.sender, amount); + } + + function proxyPayment(address) public payable returns (bool) { + throw; + } + + function onTransfer(address, address, uint256) public returns (bool) { + return false; + } + + function onApprove(address, address, uint256) public returns (bool) { + return false; + } + + ////////// + // Testing specific methods + ////////// + + /// @notice This function is overridden by the test Mocks. + function getBlockNumber() internal constant returns (uint256) { + return block.number; + } + + ////////// + // Safety Method + ////////// + + /// @notice This method can be used by the controller to extract mistakenly + /// sent tokens to this contract. + /// @param _token The address of the token contract that you want to recover + /// set to 0 in case you want to extract ether. + function claimTokens(address _token) public onlyOwner { + require(_token != address(snt)); + if (_token == 0x0) { + owner.transfer(this.balance); + return; + } + + ERC20Token token = ERC20Token(_token); + uint256 balance = token.balanceOf(this); + token.transfer(owner, balance); + ClaimedTokens(_token, owner, balance); + } + + event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount); + event TokensCollected(address indexed _holder, uint256 _amount); + +} + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title SNTPlaceholder Contract +/// @author Jordi Baylina +/// @dev The SNTPlaceholder contract will take control over the SNT after the contribution +/// is finalized and before the Status Network is deployed. +/// The contract allows for SNT transfers and transferFrom and implements the +/// logic for transferring control of the token to the network when the offering +/// asks it to do so. + + +contract SNTPlaceHolder is TokenController, Owned { + using SafeMath for uint256; + + MiniMeToken public snt; + StatusContribution public contribution; + uint256 public activationTime; + address public sgtExchanger; + + /// @notice Constructor + /// @param _owner Trusted owner for this contract. + /// @param _snt SNT token contract address + /// @param _contribution StatusContribution contract address + /// @param _sgtExchanger SGT-SNT Exchange address. (During the first week + /// only this exchanger will be able to move tokens) + function SNTPlaceHolder(address _owner, address _snt, address _contribution, address _sgtExchanger) { + owner = _owner; + snt = MiniMeToken(_snt); + contribution = StatusContribution(_contribution); + sgtExchanger = _sgtExchanger; + } + + /// @notice The owner of this contract can change the controller of the SNT token + /// Please, be sure that the owner is a trusted agent or 0x0 address. + /// @param _newController The address of the new controller + + function changeController(address _newController) public onlyOwner { + snt.changeController(_newController); + ControllerChanged(_newController); + } + + + ////////// + // MiniMe Controller Interface functions + ////////// + + // In between the offering and the network. Default settings for allowing token transfers. + function proxyPayment(address) public payable returns (bool) { + return false; + } + + function onTransfer(address _from, address, uint256) public returns (bool) { + return transferable(_from); + } + + function onApprove(address _from, address, uint256) public returns (bool) { + return transferable(_from); + } + + function transferable(address _from) internal returns (bool) { + // Allow the exchanger to work from the beginning + if (activationTime == 0) { + uint256 f = contribution.finalizedTime(); + if (f > 0) { + activationTime = f.add(1 weeks); + } else { + return false; + } + } + return (getTime() > activationTime) || (_from == sgtExchanger); + } + + + ////////// + // Testing specific methods + ////////// + + /// @notice This function is overrided by the test Mocks. + function getTime() internal returns (uint256) { + return now; + } + + + ////////// + // Safety Methods + ////////// + + /// @notice This method can be used by the controller to extract mistakenly + /// sent tokens to this contract. + /// @param _token The address of the token contract that you want to recover + /// set to 0 in case you want to extract ether. + function claimTokens(address _token) public onlyOwner { + if (snt.controller() == address(this)) { + snt.claimTokens(_token); + } + if (_token == 0x0) { + owner.transfer(this.balance); + return; + } + + ERC20Token token = ERC20Token(_token); + uint256 balance = token.balanceOf(this); + token.transfer(owner, balance); + ClaimedTokens(_token, owner, balance); + } + + event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount); + event ControllerChanged(address indexed _newController); +} \ No newline at end of file