mirror of https://github.com/crytic/slither
parent
1774c66eb6
commit
f916ee544d
@ -1,62 +0,0 @@ |
||||
# Slither-format: Automatic Code Improvements |
||||
|
||||
Slither-format is a Slither utility tool which uses Slither detectors to identify code patterns of concern (w.r.t security, readability and optimisation) and automatically fix those code patterns with suggested changes. |
||||
|
||||
Slither detectors highlight names, context and source-mapping of code constructs which are then used by Slither-format to programmatically locate those constructs in the Solidity files and then replace them with changes based on best practices. Lexical analysis for identification of such constructs is confined to the smallest possible region to avoid conflicts with similarly named constructs (with potentially different types or signatures) in other scopes, functions or contracts within the same file (because of shadowing, overloading etc.). |
||||
|
||||
## Features |
||||
|
||||
* Removes declarations of unused state variables |
||||
* Changes the visibility of `public` (explicit or implicit until solc 0.5.0) functions to `external` where possible |
||||
* Declares state variables as `constant` where possible |
||||
* Removes `pure`/`view`/`constant` attributes of functions when they are incorrectly used |
||||
* Replaces old/buggy/too-recent versions of `solc` with either `0.4.25` or `0.5.3` |
||||
* Replaces use of different `solc` versions with either `0.4.25` or `0.5.3` |
||||
* Replaces names of various program constructs to adhere to Solidity [naming convention](https://solidity.readthedocs.io/en/v0.4.25/style-guide.html#naming-conventions): |
||||
+ Contract names are converted to CapWords in contract definitions and uses |
||||
+ Structure names are converted to CapWords in structure declarations and uses |
||||
+ Event names are converted to CapWords in event declarations and calls |
||||
+ Enum names are converted to CapWords in enum declarations and uses |
||||
+ State variables: |
||||
+ If constant, are converted to UPPERCASE |
||||
+ If private, are converted to mixedCase with underscore |
||||
+ If not private, are converted to mixedCase |
||||
+ Function names are converted to mixedCase in function definitions and calls |
||||
+ Function parameters are converted to CapWords beginning with underscores in parameter declaration and uses |
||||
+ Function modifiers are converted to mixedCase in modifier definitions and calls |
||||
|
||||
## Usage |
||||
|
||||
Run Slither-format on a single file: |
||||
|
||||
``` |
||||
$ slither-format ./utils/slither_format/tests/test_data/constant.sol |
||||
``` |
||||
|
||||
This produces a `constant.sol.format` file which has all the feature replacements. It also produces a `constant.sol.format.patch` file which is a `git` compatible patch file that can be used to apply format diffs to the original file. |
||||
|
||||
## Dependencies |
||||
|
||||
Slither-format requires Slither and all its dependencies |
||||
|
||||
## To-do List of Known Limitations |
||||
|
||||
1. Naming convention formatting on parameter uses does not work for NatSpec @param attributes. |
||||
2. Naming convention formatting on parameter uses does not work for variables used as indices on LHS (e.g. `_to` in `balances[_to] = 100`). |
||||
3. Overlapping patches are ignored now - Apply the more important patch based on heuristics or user input. |
||||
4. Other to-do's as commented in the code. |
||||
|
||||
## Developer Testing |
||||
|
||||
``` |
||||
$ python3 ./slither_format/tests/test_unused_state_vars.py |
||||
$ python3 ./slither_format/tests/test_external_function.py |
||||
$ python3 ./slither_format/tests/test_constable_states.py |
||||
$ python3 ./slither_format/tests/test_constant_function.py |
||||
$ python3 ./slither_format/tests/test_solc_version.py |
||||
$ python3 ./slither_format/tests/test_pragma.py |
||||
$ python3 ./slither_format/tests/test_naming_convention.py (Has one expected failure because of limitation #2.) |
||||
$ python3 ./slither_format/tests/test_detector_combinations.py |
||||
$ python3 ./slither_format/tests/run_all_tests.py |
||||
$ python3 ./slither_format/tests/runSlitherFormat.py |
||||
``` |
@ -1 +0,0 @@ |
||||
*.patch.* |
@ -1,332 +0,0 @@ |
||||
pragma solidity ^0.4.10; |
||||
|
||||
contract GasToken2 { |
||||
////////////////////////////////////////////////////////////////////////// |
||||
// RLP.sol |
||||
// Due to some unexplained bug, we get a slightly different bytecode if |
||||
// we use an import, and are then unable to verify the code in Etherscan |
||||
////////////////////////////////////////////////////////////////////////// |
||||
|
||||
uint256 constant ADDRESS_BYTES = 20; |
||||
uint256 constant MAX_SINGLE_BYTE = 128; |
||||
uint256 constant MAX_NONCE = 256**9 - 1; |
||||
|
||||
// count number of bytes required to represent an unsigned integer |
||||
function count_bytes(uint256 n) constant internal returns (uint256 c) { |
||||
uint i = 0; |
||||
uint mask = 1; |
||||
while (n >= mask) { |
||||
i += 1; |
||||
mask *= 256; |
||||
} |
||||
|
||||
return i; |
||||
} |
||||
|
||||
function mk_contract_address(address a, uint256 n) constant internal returns (address rlp) { |
||||
/* |
||||
* make sure the RLP encoding fits in one word: |
||||
* total_length 1 byte |
||||
* address_length 1 byte |
||||
* address 20 bytes |
||||
* nonce_length 1 byte (or 0) |
||||
* nonce 1-9 bytes |
||||
* ========== |
||||
* 24-32 bytes |
||||
*/ |
||||
require(n <= MAX_NONCE); |
||||
|
||||
// number of bytes required to write down the nonce |
||||
uint256 nonce_bytes; |
||||
// length in bytes of the RLP encoding of the nonce |
||||
uint256 nonce_rlp_len; |
||||
|
||||
if (0 < n && n < MAX_SINGLE_BYTE) { |
||||
// nonce fits in a single byte |
||||
// RLP(nonce) = nonce |
||||
nonce_bytes = 1; |
||||
nonce_rlp_len = 1; |
||||
} else { |
||||
// RLP(nonce) = [num_bytes_in_nonce nonce] |
||||
nonce_bytes = count_bytes(n); |
||||
nonce_rlp_len = nonce_bytes + 1; |
||||
} |
||||
|
||||
// [address_length(1) address(20) nonce_length(0 or 1) nonce(1-9)] |
||||
uint256 tot_bytes = 1 + ADDRESS_BYTES + nonce_rlp_len; |
||||
|
||||
// concatenate all parts of the RLP encoding in the leading bytes of |
||||
// one 32-byte word |
||||
uint256 word = ((192 + tot_bytes) * 256**31) + |
||||
((128 + ADDRESS_BYTES) * 256**30) + |
||||
(uint256(a) * 256**10); |
||||
|
||||
if (0 < n && n < MAX_SINGLE_BYTE) { |
||||
word += n * 256**9; |
||||
} else { |
||||
word += (128 + nonce_bytes) * 256**9; |
||||
word += n * 256**(9 - nonce_bytes); |
||||
} |
||||
|
||||
uint256 hash; |
||||
|
||||
assembly { |
||||
let mem_start := mload(0x40) // get a pointer to free memory |
||||
mstore(0x40, add(mem_start, 0x20)) // update the pointer |
||||
|
||||
mstore(mem_start, word) // store the rlp encoding |
||||
hash := sha3(mem_start, |
||||
add(tot_bytes, 1)) // hash the rlp encoding |
||||
} |
||||
|
||||
// interpret hash as address (20 least significant bytes) |
||||
return address(hash); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////// |
||||
// Generic ERC20 |
||||
////////////////////////////////////////////////////////////////////////// |
||||
|
||||
// owner -> amount |
||||
mapping(address => uint256) s_balances; |
||||
// owner -> spender -> max amount |
||||
mapping(address => mapping(address => uint256)) s_allowances; |
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 value); |
||||
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value); |
||||
|
||||
// Spec: Get the account balance of another account with address `owner` |
||||
function balanceOf(address owner) public constant returns (uint256 balance) { |
||||
return s_balances[owner]; |
||||
} |
||||
|
||||
function internalTransfer(address from, address to, uint256 value) internal returns (bool success) { |
||||
if (value <= s_balances[from]) { |
||||
s_balances[from] -= value; |
||||
s_balances[to] += value; |
||||
Transfer(from, to, value); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// Spec: Send `value` amount of tokens to address `to` |
||||
function transfer(address to, uint256 value) public returns (bool success) { |
||||
address from = msg.sender; |
||||
return internalTransfer(from, to, value); |
||||
} |
||||
|
||||
// Spec: Send `value` amount of tokens from address `from` to address `to` |
||||
function transferFrom(address from, address to, uint256 value) public returns (bool success) { |
||||
address spender = msg.sender; |
||||
if(value <= s_allowances[from][spender] && internalTransfer(from, to, value)) { |
||||
s_allowances[from][spender] -= value; |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// Spec: Allow `spender` to withdraw from your account, multiple times, up |
||||
// to the `value` amount. If this function is called again it overwrites the |
||||
// current allowance with `value`. |
||||
function approve(address spender, uint256 value) public returns (bool success) { |
||||
address owner = msg.sender; |
||||
if (value != 0 && s_allowances[owner][spender] != 0) { |
||||
return false; |
||||
} |
||||
s_allowances[owner][spender] = value; |
||||
Approval(owner, spender, value); |
||||
return true; |
||||
} |
||||
|
||||
// Spec: Returns the `amount` which `spender` is still allowed to withdraw |
||||
// from `owner`. |
||||
// What if the allowance is higher than the balance of the `owner`? |
||||
// Callers should be careful to use min(allowance, balanceOf) to make sure |
||||
// that the allowance is actually present in the account! |
||||
function allowance(address owner, address spender) public constant returns (uint256 remaining) { |
||||
return s_allowances[owner][spender]; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////// |
||||
// GasToken specifics |
||||
////////////////////////////////////////////////////////////////////////// |
||||
|
||||
uint8 constant public decimals = 2; |
||||
string constant public name = "Gastoken.io"; |
||||
string constant public symbol = "GST2"; |
||||
|
||||
// We build a queue of nonces at which child contracts are stored. s_head is |
||||
// the nonce at the head of the queue, s_tail is the nonce behind the tail |
||||
// of the queue. The queue grows at the head and shrinks from the tail. |
||||
// Note that when and only when a contract CREATEs another contract, the |
||||
// creating contract's nonce is incremented. |
||||
// The first child contract is created with nonce == 1, the second child |
||||
// contract is created with nonce == 2, and so on... |
||||
// For example, if there are child contracts at nonces [2,3,4], |
||||
// then s_head == 4 and s_tail == 1. If there are no child contracts, |
||||
// s_head == s_tail. |
||||
uint256 s_head; |
||||
uint256 s_tail; |
||||
|
||||
// totalSupply gives the number of tokens currently in existence |
||||
// Each token corresponds to one child contract that can be SELFDESTRUCTed |
||||
// for a gas refund. |
||||
function totalSupply() public constant returns (uint256 supply) { |
||||
return s_head - s_tail; |
||||
} |
||||
|
||||
// Creates a child contract that can only be destroyed by this contract. |
||||
function makeChild() internal returns (address addr) { |
||||
assembly { |
||||
// EVM assembler of runtime portion of child contract: |
||||
// ;; Pseudocode: if (msg.sender != 0x0000000000b3f879cb30fe243b4dfee438691c04) { throw; } |
||||
// ;; suicide(msg.sender) |
||||
// PUSH15 0xb3f879cb30fe243b4dfee438691c04 ;; hardcoded address of this contract |
||||
// CALLER |
||||
// XOR |
||||
// PC |
||||
// JUMPI |
||||
// CALLER |
||||
// SELFDESTRUCT |
||||
// Or in binary: 6eb3f879cb30fe243b4dfee438691c043318585733ff |
||||
// Since the binary is so short (22 bytes), we can get away |
||||
// with a very simple initcode: |
||||
// PUSH22 0x6eb3f879cb30fe243b4dfee438691c043318585733ff |
||||
// PUSH1 0 |
||||
// MSTORE ;; at this point, memory locations mem[10] through |
||||
// ;; mem[31] contain the runtime portion of the child |
||||
// ;; contract. all that's left to do is to RETURN this |
||||
// ;; chunk of memory. |
||||
// PUSH1 22 ;; length |
||||
// PUSH1 10 ;; offset |
||||
// RETURN |
||||
// Or in binary: 756eb3f879cb30fe243b4dfee438691c043318585733ff6000526016600af3 |
||||
// Almost done! All we have to do is put this short (31 bytes) blob into |
||||
// memory and call CREATE with the appropriate offsets. |
||||
let solidity_free_mem_ptr := mload(0x40) |
||||
mstore(solidity_free_mem_ptr, 0x00756eb3f879cb30fe243b4dfee438691c043318585733ff6000526016600af3) |
||||
addr := create(0, add(solidity_free_mem_ptr, 1), 31) |
||||
} |
||||
} |
||||
|
||||
// Mints `value` new sub-tokens (e.g. cents, pennies, ...) by creating `value` |
||||
// new child contracts. The minted tokens are owned by the caller of this |
||||
// function. |
||||
function mint(uint256 value) public { |
||||
for (uint256 i = 0; i < value; i++) { |
||||
makeChild(); |
||||
} |
||||
s_head += value; |
||||
s_balances[msg.sender] += value; |
||||
} |
||||
|
||||
// Destroys `value` child contracts and updates s_tail. |
||||
// |
||||
// This function is affected by an issue in solc: https://github.com/ethereum/solidity/issues/2999 |
||||
// The `mk_contract_address(this, i).call();` doesn't forward all available gas, but only GAS - 25710. |
||||
// As a result, when this line is executed with e.g. 30000 gas, the callee will have less than 5000 gas |
||||
// available and its SELFDESTRUCT operation will fail leading to no gas refund occurring. |
||||
// The remaining ~29000 gas left after the call is enough to update s_tail and the caller's balance. |
||||
// Hence tokens will have been destroyed without a commensurate gas refund. |
||||
// Fortunately, there is a simple workaround: |
||||
// Whenever you call free, freeUpTo, freeFrom, or freeUpToFrom, ensure that you pass at least |
||||
// 25710 + `value` * (1148 + 5722 + 150) gas. (It won't all be used) |
||||
function destroyChildren(uint256 value) internal { |
||||
uint256 tail = s_tail; |
||||
// tail points to slot behind the last contract in the queue |
||||
for (uint256 i = tail + 1; i <= tail + value; i++) { |
||||
mk_contract_address(this, i).call(); |
||||
} |
||||
|
||||
s_tail = tail + value; |
||||
} |
||||
|
||||
// Frees `value` sub-tokens (e.g. cents, pennies, ...) belonging to the |
||||
// caller of this function by destroying `value` child contracts, which |
||||
// will trigger a partial gas refund. |
||||
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas |
||||
// when calling this function. For details, see the comment above `destroyChilden`. |
||||
function free(uint256 value) public returns (bool success) { |
||||
uint256 from_balance = s_balances[msg.sender]; |
||||
if (value > from_balance) { |
||||
return false; |
||||
} |
||||
|
||||
destroyChildren(value); |
||||
|
||||
s_balances[msg.sender] = from_balance - value; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// Frees up to `value` sub-tokens. Returns how many tokens were freed. |
||||
// Otherwise, identical to free. |
||||
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas |
||||
// when calling this function. For details, see the comment above `destroyChilden`. |
||||
function freeUpTo(uint256 value) public returns (uint256 freed) { |
||||
uint256 from_balance = s_balances[msg.sender]; |
||||
if (value > from_balance) { |
||||
value = from_balance; |
||||
} |
||||
|
||||
destroyChildren(value); |
||||
|
||||
s_balances[msg.sender] = from_balance - value; |
||||
|
||||
return value; |
||||
} |
||||
|
||||
// Frees `value` sub-tokens owned by address `from`. Requires that `msg.sender` |
||||
// has been approved by `from`. |
||||
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas |
||||
// when calling this function. For details, see the comment above `destroyChilden`. |
||||
function freeFrom(address from, uint256 value) public returns (bool success) { |
||||
address spender = msg.sender; |
||||
uint256 from_balance = s_balances[from]; |
||||
if (value > from_balance) { |
||||
return false; |
||||
} |
||||
|
||||
mapping(address => uint256) from_allowances = s_allowances[from]; |
||||
uint256 spender_allowance = from_allowances[spender]; |
||||
if (value > spender_allowance) { |
||||
return false; |
||||
} |
||||
|
||||
destroyChildren(value); |
||||
|
||||
s_balances[from] = from_balance - value; |
||||
from_allowances[spender] = spender_allowance - value; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// Frees up to `value` sub-tokens owned by address `from`. Returns how many tokens were freed. |
||||
// Otherwise, identical to `freeFrom`. |
||||
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas |
||||
// when calling this function. For details, see the comment above `destroyChilden`. |
||||
function freeFromUpTo(address from, uint256 value) public returns (uint256 freed) { |
||||
address spender = msg.sender; |
||||
uint256 from_balance = s_balances[from]; |
||||
if (value > from_balance) { |
||||
value = from_balance; |
||||
} |
||||
|
||||
mapping(address => uint256) from_allowances = s_allowances[from]; |
||||
uint256 spender_allowance = from_allowances[spender]; |
||||
if (value > spender_allowance) { |
||||
value = spender_allowance; |
||||
} |
||||
|
||||
destroyChildren(value); |
||||
|
||||
s_balances[from] = from_balance - value; |
||||
from_allowances[spender] = spender_allowance - value; |
||||
|
||||
return value; |
||||
} |
||||
} |
@ -1,880 +0,0 @@ |
||||
pragma solidity ^0.4.11; |
||||
|
||||
/* |
||||
Owned contract interface |
||||
*/ |
||||
contract IOwned { |
||||
// this function isn't abstract since the compiler emits automatically generated getter functions as external |
||||
function owner() public constant returns (address owner) { owner; } |
||||
|
||||
function transferOwnership(address _newOwner) public; |
||||
function acceptOwnership() public; |
||||
} |
||||
|
||||
/* |
||||
ERC20 Standard Token interface |
||||
*/ |
||||
contract IERC20Token { |
||||
// these functions aren't abstract since the compiler emits automatically generated getter functions as external |
||||
function name() public constant returns (string name) { name; } |
||||
function symbol() public constant returns (string symbol) { symbol; } |
||||
function decimals() public constant returns (uint8 decimals) { decimals; } |
||||
function totalSupply() public constant returns (uint256 totalSupply) { totalSupply; } |
||||
function balanceOf(address _owner) public constant returns (uint256 balance) { _owner; balance; } |
||||
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) { _owner; _spender; remaining; } |
||||
|
||||
function transfer(address _to, uint256 _value) public returns (bool success); |
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); |
||||
function approve(address _spender, uint256 _value) public returns (bool success); |
||||
} |
||||
|
||||
/* |
||||
Token Holder interface |
||||
*/ |
||||
contract ITokenHolder is IOwned { |
||||
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public; |
||||
} |
||||
|
||||
/* |
||||
Smart Token interface |
||||
*/ |
||||
contract ISmartToken is ITokenHolder, IERC20Token { |
||||
function disableTransfers(bool _disable) public; |
||||
function issue(address _to, uint256 _amount) public; |
||||
function destroy(address _from, uint256 _amount) public; |
||||
} |
||||
|
||||
/* |
||||
Overflow protected math functions |
||||
*/ |
||||
contract SafeMath { |
||||
/** |
||||
constructor |
||||
*/ |
||||
function SafeMath() { |
||||
} |
||||
|
||||
/** |
||||
@dev returns the sum of _x and _y, asserts if the calculation overflows |
||||
|
||||
@param _x value 1 |
||||
@param _y value 2 |
||||
|
||||
@return sum |
||||
*/ |
||||
function safeAdd(uint256 _x, uint256 _y) internal returns (uint256) { |
||||
uint256 z = _x + _y; |
||||
assert(z >= _x); |
||||
return z; |
||||
} |
||||
|
||||
/** |
||||
@dev returns the difference of _x minus _y, asserts if the subtraction results in a negative number |
||||
|
||||
@param _x minuend |
||||
@param _y subtrahend |
||||
|
||||
@return difference |
||||
*/ |
||||
function safeSub(uint256 _x, uint256 _y) internal returns (uint256) { |
||||
assert(_x >= _y); |
||||
return _x - _y; |
||||
} |
||||
|
||||
/** |
||||
@dev returns the product of multiplying _x by _y, asserts if the calculation overflows |
||||
|
||||
@param _x factor 1 |
||||
@param _y factor 2 |
||||
|
||||
@return product |
||||
*/ |
||||
function safeMul(uint256 _x, uint256 _y) internal returns (uint256) { |
||||
uint256 z = _x * _y; |
||||
assert(_x == 0 || z / _x == _y); |
||||
return z; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
ERC20 Standard Token implementation |
||||
*/ |
||||
contract ERC20Token is IERC20Token, SafeMath { |
||||
string public standard = 'Token 0.1'; |
||||
string public name = ''; |
||||
string public symbol = ''; |
||||
uint8 public decimals = 0; |
||||
uint256 public totalSupply = 0; |
||||
mapping (address => uint256) public balanceOf; |
||||
mapping (address => mapping (address => uint256)) public allowance; |
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value); |
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value); |
||||
|
||||
/** |
||||
@dev constructor |
||||
|
||||
@param _name token name |
||||
@param _symbol token symbol |
||||
@param _decimals decimal points, for display purposes |
||||
*/ |
||||
function ERC20Token(string _name, string _symbol, uint8 _decimals) { |
||||
require(bytes(_name).length > 0 && bytes(_symbol).length > 0); // validate input |
||||
|
||||
name = _name; |
||||
symbol = _symbol; |
||||
decimals = _decimals; |
||||
} |
||||
|
||||
// validates an address - currently only checks that it isn't null |
||||
modifier validAddress(address _address) { |
||||
require(_address != 0x0); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
@dev send coins |
||||
throws on any error rather then return a false flag to minimize user errors |
||||
|
||||
@param _to target address |
||||
@param _value transfer amount |
||||
|
||||
@return true if the transfer was successful, false if it wasn't |
||||
*/ |
||||
function transfer(address _to, uint256 _value) |
||||
public |
||||
validAddress(_to) |
||||
returns (bool success) |
||||
{ |
||||
balanceOf[msg.sender] = safeSub(balanceOf[msg.sender], _value); |
||||
balanceOf[_to] = safeAdd(balanceOf[_to], _value); |
||||
Transfer(msg.sender, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
@dev an account/contract attempts to get the coins |
||||
throws on any error rather then return a false flag to minimize user errors |
||||
|
||||
@param _from source address |
||||
@param _to target address |
||||
@param _value transfer amount |
||||
|
||||
@return true if the transfer was successful, false if it wasn't |
||||
*/ |
||||
function transferFrom(address _from, address _to, uint256 _value) |
||||
public |
||||
validAddress(_from) |
||||
validAddress(_to) |
||||
returns (bool success) |
||||
{ |
||||
allowance[_from][msg.sender] = safeSub(allowance[_from][msg.sender], _value); |
||||
balanceOf[_from] = safeSub(balanceOf[_from], _value); |
||||
balanceOf[_to] = safeAdd(balanceOf[_to], _value); |
||||
Transfer(_from, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
@dev allow another account/contract to spend some tokens on your behalf |
||||
throws on any error rather then return a false flag to minimize user errors |
||||
|
||||
also, to minimize the risk of the approve/transferFrom attack vector |
||||
(see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice |
||||
in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value |
||||
|
||||
@param _spender approved address |
||||
@param _value allowance amount |
||||
|
||||
@return true if the approval was successful, false if it wasn't |
||||
*/ |
||||
function approve(address _spender, uint256 _value) |
||||
public |
||||
validAddress(_spender) |
||||
returns (bool success) |
||||
{ |
||||
// if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal |
||||
require(_value == 0 || allowance[msg.sender][_spender] == 0); |
||||
|
||||
allowance[msg.sender][_spender] = _value; |
||||
Approval(msg.sender, _spender, _value); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
/* |
||||
Provides support and utilities for contract ownership |
||||
*/ |
||||
contract Owned is IOwned { |
||||
address public owner; |
||||
address public newOwner; |
||||
|
||||
event OwnerUpdate(address _prevOwner, address _newOwner); |
||||
|
||||
/** |
||||
@dev constructor |
||||
*/ |
||||
function Owned() { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
// allows execution by the owner only |
||||
modifier ownerOnly { |
||||
assert(msg.sender == owner); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
@dev allows transferring the contract ownership |
||||
the new owner still need to accept the transfer |
||||
can only be called by the contract owner |
||||
|
||||
@param _newOwner new contract owner |
||||
*/ |
||||
function transferOwnership(address _newOwner) public ownerOnly { |
||||
require(_newOwner != owner); |
||||
newOwner = _newOwner; |
||||
} |
||||
|
||||
/** |
||||
@dev used by a new owner to accept an ownership transfer |
||||
*/ |
||||
function acceptOwnership() public { |
||||
require(msg.sender == newOwner); |
||||
OwnerUpdate(owner, newOwner); |
||||
owner = newOwner; |
||||
newOwner = 0x0; |
||||
} |
||||
} |
||||
|
||||
/* |
||||
We consider every contract to be a 'token holder' since it's currently not possible |
||||
for a contract to deny receiving tokens. |
||||
|
||||
The TokenHolder's contract sole purpose is to provide a safety mechanism that allows |
||||
the owner to send tokens that were sent to the contract by mistake back to their sender. |
||||
*/ |
||||
contract TokenHolder is ITokenHolder, Owned { |
||||
/** |
||||
@dev constructor |
||||
*/ |
||||
function TokenHolder() { |
||||
} |
||||
|
||||
// validates an address - currently only checks that it isn't null |
||||
modifier validAddress(address _address) { |
||||
require(_address != 0x0); |
||||
_; |
||||
} |
||||
|
||||
// verifies that the address is different than this contract address |
||||
modifier notThis(address _address) { |
||||
require(_address != address(this)); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
@dev withdraws tokens held by the contract and sends them to an account |
||||
can only be called by the owner |
||||
|
||||
@param _token ERC20 token contract address |
||||
@param _to account to receive the new amount |
||||
@param _amount amount to withdraw |
||||
*/ |
||||
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) |
||||
public |
||||
ownerOnly |
||||
validAddress(_token) |
||||
validAddress(_to) |
||||
notThis(_to) |
||||
{ |
||||
assert(_token.transfer(_to, _amount)); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
Smart Token v0.2 |
||||
|
||||
'Owned' is specified here for readability reasons |
||||
*/ |
||||
contract SmartToken is ISmartToken, ERC20Token, Owned, TokenHolder { |
||||
string public version = '0.2'; |
||||
|
||||
bool public transfersEnabled = true; // true if transfer/transferFrom are enabled, false if not |
||||
|
||||
// triggered when a smart token is deployed - the _token address is defined for forward compatibility, in case we want to trigger the event from a factory |
||||
event NewSmartToken(address _token); |
||||
// triggered when the total supply is increased |
||||
event Issuance(uint256 _amount); |
||||
// triggered when the total supply is decreased |
||||
event Destruction(uint256 _amount); |
||||
|
||||
/** |
||||
@dev constructor |
||||
|
||||
@param _name token name |
||||
@param _symbol token short symbol, 1-6 characters |
||||
@param _decimals for display purposes only |
||||
*/ |
||||
function SmartToken(string _name, string _symbol, uint8 _decimals) |
||||
ERC20Token(_name, _symbol, _decimals) |
||||
{ |
||||
require(bytes(_symbol).length <= 6); // validate input |
||||
NewSmartToken(address(this)); |
||||
} |
||||
|
||||
// allows execution only when transfers aren't disabled |
||||
modifier transfersAllowed { |
||||
assert(transfersEnabled); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
@dev disables/enables transfers |
||||
can only be called by the contract owner |
||||
|
||||
@param _disable true to disable transfers, false to enable them |
||||
*/ |
||||
function disableTransfers(bool _disable) public ownerOnly { |
||||
transfersEnabled = !_disable; |
||||
} |
||||
|
||||
/** |
||||
@dev increases the token supply and sends the new tokens to an account |
||||
can only be called by the contract owner |
||||
|
||||
@param _to account to receive the new amount |
||||
@param _amount amount to increase the supply by |
||||
*/ |
||||
function issue(address _to, uint256 _amount) |
||||
public |
||||
ownerOnly |
||||
validAddress(_to) |
||||
notThis(_to) |
||||
{ |
||||
totalSupply = safeAdd(totalSupply, _amount); |
||||
balanceOf[_to] = safeAdd(balanceOf[_to], _amount); |
||||
|
||||
Issuance(_amount); |
||||
Transfer(this, _to, _amount); |
||||
} |
||||
|
||||
/** |
||||
@dev removes tokens from an account and decreases the token supply |
||||
can only be called by the contract owner |
||||
|
||||
@param _from account to remove the amount from |
||||
@param _amount amount to decrease the supply by |
||||
*/ |
||||
function destroy(address _from, uint256 _amount) |
||||
public |
||||
ownerOnly |
||||
{ |
||||
balanceOf[_from] = safeSub(balanceOf[_from], _amount); |
||||
totalSupply = safeSub(totalSupply, _amount); |
||||
|
||||
Transfer(_from, this, _amount); |
||||
Destruction(_amount); |
||||
} |
||||
|
||||
// ERC20 standard method overrides with some extra functionality |
||||
|
||||
/** |
||||
@dev send coins |
||||
throws on any error rather then return a false flag to minimize user errors |
||||
note that when transferring to the smart token's address, the coins are actually destroyed |
||||
|
||||
@param _to target address |
||||
@param _value transfer amount |
||||
|
||||
@return true if the transfer was successful, false if it wasn't |
||||
*/ |
||||
function transfer(address _to, uint256 _value) public transfersAllowed returns (bool success) { |
||||
assert(super.transfer(_to, _value)); |
||||
|
||||
// transferring to the contract address destroys tokens |
||||
if (_to == address(this)) { |
||||
balanceOf[_to] -= _value; |
||||
totalSupply -= _value; |
||||
Destruction(_value); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
@dev an account/contract attempts to get the coins |
||||
throws on any error rather then return a false flag to minimize user errors |
||||
note that when transferring to the smart token's address, the coins are actually destroyed |
||||
|
||||
@param _from source address |
||||
@param _to target address |
||||
@param _value transfer amount |
||||
|
||||
@return true if the transfer was successful, false if it wasn't |
||||
*/ |
||||
function transferFrom(address _from, address _to, uint256 _value) public transfersAllowed returns (bool success) { |
||||
assert(super.transferFrom(_from, _to, _value)); |
||||
|
||||
// transferring to the contract address destroys tokens |
||||
if (_to == address(this)) { |
||||
balanceOf[_to] -= _value; |
||||
totalSupply -= _value; |
||||
Destruction(_value); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
/// @title Ownable |
||||
/// @dev The Ownable contract has an owner address, and provides basic authorization control functions, this simplifies |
||||
/// & the implementation of "user permissions". |
||||
contract Ownable { |
||||
address public owner; |
||||
address public newOwnerCandidate; |
||||
|
||||
event OwnershipRequested(address indexed _by, address indexed _to); |
||||
event OwnershipTransferred(address indexed _from, address indexed _to); |
||||
|
||||
/// @dev The Ownable constructor sets the original `owner` of the contract to the sender account. |
||||
function Ownable() { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
/// @dev Throws if called by any account other than the owner. |
||||
modifier onlyOwner() { |
||||
if (msg.sender != owner) { |
||||
throw; |
||||
} |
||||
|
||||
_; |
||||
} |
||||
|
||||
/// @dev Proposes to transfer control of the contract to a newOwnerCandidate. |
||||
/// @param _newOwnerCandidate address The address to transfer ownership to. |
||||
function transferOwnership(address _newOwnerCandidate) onlyOwner { |
||||
require(_newOwnerCandidate != address(0)); |
||||
|
||||
newOwnerCandidate = _newOwnerCandidate; |
||||
|
||||
OwnershipRequested(msg.sender, newOwnerCandidate); |
||||
} |
||||
|
||||
/// @dev Accept ownership transfer. This method needs to be called by the perviously proposed owner. |
||||
function acceptOwnership() { |
||||
if (msg.sender == newOwnerCandidate) { |
||||
owner = newOwnerCandidate; |
||||
newOwnerCandidate = address(0); |
||||
|
||||
OwnershipTransferred(owner, newOwnerCandidate); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// @title Math operations with safety checks |
||||
library SaferMath { |
||||
function mul(uint256 a, uint256 b) internal returns (uint256) { |
||||
uint256 c = a * b; |
||||
assert(a == 0 || c / a == b); |
||||
return c; |
||||
} |
||||
|
||||
function div(uint256 a, uint256 b) internal 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 returns (uint256) { |
||||
assert(b <= a); |
||||
return a - b; |
||||
} |
||||
|
||||
function add(uint256 a, uint256 b) internal returns (uint256) { |
||||
uint256 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; |
||||
} |
||||
} |
||||
|
||||
|
||||
/// @title Stox Smart Token |
||||
contract StoxSmartToken is SmartToken { |
||||
function StoxSmartToken() SmartToken('Stox', 'STX', 18) { |
||||
disableTransfers(true); |
||||
} |
||||
} |
||||
|
||||
|
||||
/// @title Vesting trustee |
||||
contract Trustee is Ownable { |
||||
using SaferMath for uint256; |
||||
|
||||
// The address of the STX ERC20 token. |
||||
StoxSmartToken public stox; |
||||
|
||||
struct Grant { |
||||
uint256 value; |
||||
uint256 start; |
||||
uint256 cliff; |
||||
uint256 end; |
||||
uint256 transferred; |
||||
bool revokable; |
||||
} |
||||
|
||||
// Grants holder. |
||||
mapping (address => Grant) public grants; |
||||
|
||||
// Total tokens available for vesting. |
||||
uint256 public totalVesting; |
||||
|
||||
event NewGrant(address indexed _from, address indexed _to, uint256 _value); |
||||
event UnlockGrant(address indexed _holder, uint256 _value); |
||||
event RevokeGrant(address indexed _holder, uint256 _refund); |
||||
|
||||
/// @dev Constructor that initializes the address of the StoxSmartToken contract. |
||||
/// @param _stox StoxSmartToken The address of the previously deployed StoxSmartToken smart contract. |
||||
function Trustee(StoxSmartToken _stox) { |
||||
require(_stox != address(0)); |
||||
|
||||
stox = _stox; |
||||
} |
||||
|
||||
/// @dev Grant tokens to a specified address. |
||||
/// @param _to address The address to grant tokens to. |
||||
/// @param _value uint256 The amount of tokens to be granted. |
||||
/// @param _start uint256 The beginning of the vesting period. |
||||
/// @param _cliff uint256 Duration of the cliff period. |
||||
/// @param _end uint256 The end of the vesting period. |
||||
/// @param _revokable bool Whether the grant is revokable or not. |
||||
function grant(address _to, uint256 _value, uint256 _start, uint256 _cliff, uint256 _end, bool _revokable) |
||||
public onlyOwner { |
||||
require(_to != address(0)); |
||||
require(_value > 0); |
||||
|
||||
// Make sure that a single address can be granted tokens only once. |
||||
require(grants[_to].value == 0); |
||||
|
||||
// Check for date inconsistencies that may cause unexpected behavior. |
||||
require(_start <= _cliff && _cliff <= _end); |
||||
|
||||
// Check that this grant doesn't exceed the total amount of tokens currently available for vesting. |
||||
require(totalVesting.add(_value) <= stox.balanceOf(address(this))); |
||||
|
||||
// Assign a new grant. |
||||
grants[_to] = Grant({ |
||||
value: _value, |
||||
start: _start, |
||||
cliff: _cliff, |
||||
end: _end, |
||||
transferred: 0, |
||||
revokable: _revokable |
||||
}); |
||||
|
||||
// Tokens granted, reduce the total amount available for vesting. |
||||
totalVesting = totalVesting.add(_value); |
||||
|
||||
NewGrant(msg.sender, _to, _value); |
||||
} |
||||
|
||||
/// @dev Revoke the grant of tokens of a specifed address. |
||||
/// @param _holder The address which will have its tokens revoked. |
||||
function revoke(address _holder) public onlyOwner { |
||||
Grant grant = grants[_holder]; |
||||
|
||||
require(grant.revokable); |
||||
|
||||
// Send the remaining STX back to the owner. |
||||
uint256 refund = grant.value.sub(grant.transferred); |
||||
|
||||
// Remove the grant. |
||||
delete grants[_holder]; |
||||
|
||||
totalVesting = totalVesting.sub(refund); |
||||
stox.transfer(msg.sender, refund); |
||||
|
||||
RevokeGrant(_holder, refund); |
||||
} |
||||
|
||||
/// @dev Calculate the total amount of vested tokens of a holder at a given time. |
||||
/// @param _holder address The address of the holder. |
||||
/// @param _time uint256 The specific time. |
||||
/// @return a uint256 representing a holder's total amount of vested tokens. |
||||
function vestedTokens(address _holder, uint256 _time) public constant returns (uint256) { |
||||
Grant grant = grants[_holder]; |
||||
if (grant.value == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return calculateVestedTokens(grant, _time); |
||||
} |
||||
|
||||
/// @dev Calculate amount of vested tokens at a specifc time. |
||||
/// @param _grant Grant The vesting grant. |
||||
/// @param _time uint256 The time to be checked |
||||
/// @return An uint256 representing the amount of vested tokens of a specific grant. |
||||
/// | _/-------- vestedTokens rect |
||||
/// | _/ |
||||
/// | _/ |
||||
/// | _/ |
||||
/// | _/ |
||||
/// | / |
||||
/// | .| |
||||
/// | . | |
||||
/// | . | |
||||
/// | . | |
||||
/// | . | |
||||
/// | . | |
||||
/// +===+===========+---------+----------> time |
||||
/// Start Cliff End |
||||
function calculateVestedTokens(Grant _grant, uint256 _time) private constant returns (uint256) { |
||||
// If we're before the cliff, then nothing is vested. |
||||
if (_time < _grant.cliff) { |
||||
return 0; |
||||
} |
||||
|
||||
// If we're after the end of the vesting period - everything is vested; |
||||
if (_time >= _grant.end) { |
||||
return _grant.value; |
||||
} |
||||
|
||||
// Interpolate all vested tokens: vestedTokens = tokens/// (time - start) / (end - start) |
||||
return _grant.value.mul(_time.sub(_grant.start)).div(_grant.end.sub(_grant.start)); |
||||
} |
||||
|
||||
/// @dev Unlock vested tokens and transfer them to their holder. |
||||
/// @return a uint256 representing the amount of vested tokens transferred to their holder. |
||||
function unlockVestedTokens() public { |
||||
Grant grant = grants[msg.sender]; |
||||
require(grant.value != 0); |
||||
|
||||
// Get the total amount of vested tokens, acccording to grant. |
||||
uint256 vested = calculateVestedTokens(grant, now); |
||||
if (vested == 0) { |
||||
return; |
||||
} |
||||
|
||||
// Make sure the holder doesn't transfer more than what he already has. |
||||
uint256 transferable = vested.sub(grant.transferred); |
||||
if (transferable == 0) { |
||||
return; |
||||
} |
||||
|
||||
grant.transferred = grant.transferred.add(transferable); |
||||
totalVesting = totalVesting.sub(transferable); |
||||
stox.transfer(msg.sender, transferable); |
||||
|
||||
UnlockGrant(msg.sender, transferable); |
||||
} |
||||
} |
||||
|
||||
|
||||
/// @title Stox Smart Token sale |
||||
contract StoxSmartTokenSale is Ownable { |
||||
using SaferMath for uint256; |
||||
|
||||
uint256 public constant DURATION = 14 days; |
||||
|
||||
bool public isFinalized = false; |
||||
bool public isDistributed = false; |
||||
|
||||
// The address of the STX ERC20 token. |
||||
StoxSmartToken public stox; |
||||
|
||||
// The address of the token allocation trustee; |
||||
Trustee public trustee; |
||||
|
||||
uint256 public startTime = 0; |
||||
uint256 public endTime = 0; |
||||
address public fundingRecipient; |
||||
|
||||
uint256 public tokensSold = 0; |
||||
|
||||
// TODO: update to the correct values. |
||||
uint256 public constant ETH_CAP = 148000; |
||||
uint256 public constant EXCHANGE_RATE = 200; // 200 STX for ETH |
||||
uint256 public constant TOKEN_SALE_CAP = ETH_CAP * EXCHANGE_RATE * 10 ** 18; |
||||
|
||||
event TokensIssued(address indexed _to, uint256 _tokens); |
||||
|
||||
/// @dev Throws if called when not during sale. |
||||
modifier onlyDuringSale() { |
||||
if (tokensSold >= TOKEN_SALE_CAP || now < startTime || now >= endTime) { |
||||
throw; |
||||
} |
||||
|
||||
_; |
||||
} |
||||
|
||||
/// @dev Throws if called before sale ends. |
||||
modifier onlyAfterSale() { |
||||
if (!(tokensSold >= TOKEN_SALE_CAP || now >= endTime)) { |
||||
throw; |
||||
} |
||||
|
||||
_; |
||||
} |
||||
|
||||
/// @dev Constructor that initializes the sale conditions. |
||||
/// @param _fundingRecipient address The address of the funding recipient. |
||||
/// @param _startTime uint256 The start time of the token sale. |
||||
function StoxSmartTokenSale(address _stox, address _fundingRecipient, uint256 _startTime) { |
||||
require(_stox != address(0)); |
||||
require(_fundingRecipient != address(0)); |
||||
require(_startTime > now); |
||||
|
||||
stox = StoxSmartToken(_stox); |
||||
|
||||
fundingRecipient = _fundingRecipient; |
||||
startTime = _startTime; |
||||
endTime = startTime + DURATION; |
||||
} |
||||
|
||||
/// @dev Distributed tokens to the partners who have participated during the pre-sale. |
||||
function distributePartnerTokens() external onlyOwner { |
||||
require(!isDistributed); |
||||
|
||||
assert(tokensSold == 0); |
||||
assert(stox.totalSupply() == 0); |
||||
|
||||
// Distribute strategic tokens to partners. Please note, that this address doesn't represent a single entity or |
||||
// person and will be only used to distribute tokens to 30~ partners. |
||||
// |
||||
// Please expect to see token transfers from this address in the first 24 hours after the token sale ends. |
||||
issueTokens(0x9065260ef6830f6372F1Bde408DeC57Fe3150530, 14800000 * 10 ** 18); |
||||
|
||||
isDistributed = true; |
||||
} |
||||
|
||||
/// @dev Finalizes the token sale event. |
||||
function finalize() external onlyAfterSale { |
||||
if (isFinalized) { |
||||
throw; |
||||
} |
||||
|
||||
// Grant vesting grants. |
||||
// |
||||
// TODO: use real addresses. |
||||
trustee = new Trustee(stox); |
||||
|
||||
// Since only 50% of the tokens will be sold, we will automatically issue the same amount of sold STX to the |
||||
// trustee. |
||||
uint256 unsoldTokens = tokensSold; |
||||
|
||||
// Issue 55% of the remaining tokens (== 27.5%) go to strategic parternships. |
||||
uint256 strategicPartnershipTokens = unsoldTokens.mul(55).div(100); |
||||
|
||||
// Note: we will substract the bonus tokens from this grant, since they were already issued for the pre-sale |
||||
// strategic partners and should've been taken from this allocation. |
||||
stox.issue(0xbC14105ccDdeAadB96Ba8dCE18b40C45b6bACf58, strategicPartnershipTokens); |
||||
|
||||
// Issue the remaining tokens as vesting grants: |
||||
stox.issue(trustee, unsoldTokens.sub(strategicPartnershipTokens)); |
||||
|
||||
// 25% of the remaining tokens (== 12.5%) go to Invest.com, at uniform 12 months vesting schedule. |
||||
trustee.grant(0xb54c6a870d4aD65e23d471Fb7941aD271D323f5E, unsoldTokens.mul(25).div(100), now, now, |
||||
now.add(1 years), true); |
||||
|
||||
// 20% of the remaining tokens (== 10%) go to Stox team, at uniform 24 months vesting schedule. |
||||
trustee.grant(0x4eB4Cd1D125d9d281709Ff38d65b99a6927b46c1, unsoldTokens.mul(20).div(100), now, now, |
||||
now.add(2 years), true); |
||||
|
||||
// Re-enable transfers after the token sale. |
||||
stox.disableTransfers(false); |
||||
|
||||
isFinalized = true; |
||||
} |
||||
|
||||
/// @dev Create and sell tokens to the caller. |
||||
/// @param _recipient address The address of the recipient. |
||||
function create(address _recipient) public payable onlyDuringSale { |
||||
require(_recipient != address(0)); |
||||
require(msg.value > 0); |
||||
|
||||
assert(isDistributed); |
||||
|
||||
uint256 tokens = SaferMath.min256(msg.value.mul(EXCHANGE_RATE), TOKEN_SALE_CAP.sub(tokensSold)); |
||||
uint256 contribution = tokens.div(EXCHANGE_RATE); |
||||
|
||||
issueTokens(_recipient, tokens); |
||||
|
||||
// Transfer the funds to the funding recipient. |
||||
fundingRecipient.transfer(contribution); |
||||
|
||||
// Refund the msg.sender, in the case that not all of its ETH was used. This can happen only when selling the |
||||
// last chunk of STX. |
||||
uint256 refund = msg.value.sub(contribution); |
||||
if (refund > 0) { |
||||
msg.sender.transfer(refund); |
||||
} |
||||
} |
||||
|
||||
/// @dev Issues tokens for the recipient. |
||||
/// @param _recipient address The address of the recipient. |
||||
/// @param _tokens uint256 The amount of tokens to issue. |
||||
function issueTokens(address _recipient, uint256 _tokens) private { |
||||
// Update total sold tokens. |
||||
tokensSold = tokensSold.add(_tokens); |
||||
|
||||
stox.issue(_recipient, _tokens); |
||||
|
||||
TokensIssued(_recipient, _tokens); |
||||
} |
||||
|
||||
/// @dev Fallback function that will delegate the request to create. |
||||
function () external payable onlyDuringSale { |
||||
create(msg.sender); |
||||
} |
||||
|
||||
/// @dev Proposes to transfer control of the StoxSmartToken contract to a new owner. |
||||
/// @param _newOwnerCandidate address The address to transfer ownership to. |
||||
/// |
||||
/// Note that: |
||||
/// 1. The new owner will need to call StoxSmartToken's acceptOwnership directly in order to accept the ownership. |
||||
/// 2. Calling this method during the token sale will prevent the token sale to continue, since only the owner of |
||||
/// the StoxSmartToken contract can issue new tokens. |
||||
function transferSmartTokenOwnership(address _newOwnerCandidate) external onlyOwner { |
||||
stox.transferOwnership(_newOwnerCandidate); |
||||
} |
||||
|
||||
/// @dev Accepts new ownership on behalf of the StoxSmartToken contract. This can be used, by the token sale |
||||
/// contract itself to claim back ownership of the StoxSmartToken contract. |
||||
function acceptSmartTokenOwnership() external onlyOwner { |
||||
stox.acceptOwnership(); |
||||
} |
||||
|
||||
/// @dev Proposes to transfer control of the Trustee contract to a new owner. |
||||
/// @param _newOwnerCandidate address The address to transfer ownership to. |
||||
/// |
||||
/// Note that: |
||||
/// 1. The new owner will need to call Trustee's acceptOwnership directly in order to accept the ownership. |
||||
/// 2. Calling this method during the token sale won't be possible, as the Trustee is only created after its |
||||
/// finalization. |
||||
function transferTrusteeOwnership(address _newOwnerCandidate) external onlyOwner { |
||||
trustee.transferOwnership(_newOwnerCandidate); |
||||
} |
||||
|
||||
/// @dev Accepts new ownership on behalf of the Trustee contract. This can be used, by the token sale |
||||
/// contract itself to claim back ownership of the Trustee contract. |
||||
function acceptTrusteeOwnership() external onlyOwner { |
||||
trustee.acceptOwnership(); |
||||
} |
||||
} |
@ -1,241 +0,0 @@ |
||||
pragma solidity ^0.4.17; |
||||
|
||||
contract Cofounded { |
||||
mapping (address => uint) public cofounderIndices; |
||||
address[] public cofounders; |
||||
|
||||
|
||||
/// @dev restrict execution to one of original cofounder addresses |
||||
modifier restricted () { |
||||
uint cofounderIndex = cofounderIndices[msg.sender]; |
||||
require(msg.sender == cofounders[cofounderIndex]); |
||||
_; |
||||
} |
||||
|
||||
/// @notice creates the Cofounded contract instance |
||||
/// @dev adds up to cofounders. |
||||
/// also adds the deployment address as a cofounder |
||||
function Cofounded (address[] contractCofounders) public { |
||||
cofounders.push(msg.sender); |
||||
|
||||
for (uint8 x = 0; x < contractCofounders.length; x++) { |
||||
address cofounder = contractCofounders[x]; |
||||
|
||||
bool isValidUniqueCofounder = |
||||
cofounder != address(0) && |
||||
cofounder != msg.sender && |
||||
cofounderIndices[cofounder] == 0; |
||||
|
||||
|
||||
// NOTE: solidity as of 0.4.20 does not have an |
||||
// undefined or null-like value |
||||
// thusly mappings return the default value of the value type |
||||
// for an unregistered key value |
||||
// an address which doesn't exist will return 0 |
||||
// which is actually the index of the address of the first |
||||
// cofounder |
||||
if (isValidUniqueCofounder) { |
||||
uint256 cofounderIndex = cofounders.push(cofounder) - 1; |
||||
cofounderIndices[cofounder] = cofounderIndex; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// @dev get count of cofounders |
||||
function getCofounderCount () public constant returns (uint256) { |
||||
return cofounders.length; |
||||
} |
||||
|
||||
/// @dev get list of cofounders |
||||
function getCofounders () public constant returns (address[]) { |
||||
return cofounders; |
||||
} |
||||
} |
||||
|
||||
interface ERC20 { |
||||
|
||||
// Required methods |
||||
function transfer (address to, uint256 value) public returns (bool success); |
||||
function transferFrom (address from, address to, uint256 value) public returns (bool success); |
||||
function approve (address spender, uint256 value) public returns (bool success); |
||||
function allowance (address owner, address spender) public constant returns (uint256 remaining); |
||||
function balanceOf (address owner) public constant returns (uint256 balance); |
||||
// Events |
||||
event Transfer (address indexed from, address indexed to, uint256 value); |
||||
event Approval (address indexed owner, address indexed spender, uint256 value); |
||||
} |
||||
|
||||
|
||||
/// @title Interface for contracts conforming to ERC-165: Pseudo-Introspection, or standard interface detection |
||||
/// @author Mish Ochu |
||||
interface ERC165 { |
||||
/// @dev true iff the interface is supported |
||||
function supportsInterface(bytes4 interfaceID) external constant returns (bool); |
||||
} |
||||
contract InterfaceSignatureConstants { |
||||
bytes4 constant InterfaceSignature_ERC165 = |
||||
bytes4(keccak256('supportsInterface(bytes4)')); |
||||
|
||||
bytes4 constant InterfaceSignature_ERC20 = |
||||
bytes4(keccak256('totalSupply()')) ^ |
||||
bytes4(keccak256('balanceOf(address)')) ^ |
||||
bytes4(keccak256('transfer(address,uint256)')) ^ |
||||
bytes4(keccak256('transferFrom(address,address,uint256)')) ^ |
||||
bytes4(keccak256('approve(address,uint256)')) ^ |
||||
bytes4(keccak256('allowance(address,address)')); |
||||
|
||||
bytes4 constant InterfaceSignature_ERC20_PlusOptions = |
||||
bytes4(keccak256('name()')) ^ |
||||
bytes4(keccak256('symbol()')) ^ |
||||
bytes4(keccak256('decimals()')) ^ |
||||
bytes4(keccak256('totalSupply()')) ^ |
||||
bytes4(keccak256('balanceOf(address)')) ^ |
||||
bytes4(keccak256('transfer(address,uint256)')) ^ |
||||
bytes4(keccak256('transferFrom(address,address,uint256)')) ^ |
||||
bytes4(keccak256('approve(address,uint256)')) ^ |
||||
bytes4(keccak256('allowance(address,address)')); |
||||
} |
||||
|
||||
/// @title an original cofounder based ERC-20 compliant token |
||||
/// @author Mish Ochu |
||||
/// @dev Ref: https://github.com/ethereum/EIPs/issues/721 |
||||
//http://solidity.readthedocs.io/en/develop/contracts.html#arguments-for-base-constructors |
||||
contract OriginalToken is Cofounded, ERC20, ERC165, InterfaceSignatureConstants { |
||||
bool private hasExecutedCofounderDistribution; |
||||
struct Allowance { |
||||
uint256 amount; |
||||
bool hasBeenPartiallyWithdrawn; |
||||
} |
||||
|
||||
//***** Apparently Optional *****/ |
||||
/// @dev returns the name of the token |
||||
string public constant name = 'Original Crypto Coin'; |
||||
/// @dev returns the symbol of the token (e.g. 'OCC') |
||||
string public constant symbol = 'OCC'; |
||||
/// @dev returns the number of decimals the tokens use |
||||
uint8 public constant decimals = 18; |
||||
//**********/ |
||||
|
||||
/// @dev returns the total token supply |
||||
/// @note implemented as a state variable with an automatic (compiler provided) getter |
||||
/// instead of a constant (view/readonly) function. |
||||
uint256 public totalSupply = 100000000000000000000000000000; |
||||
|
||||
mapping (address => uint256) public balances; |
||||
// TODO: determine if the gas cost for handling the race condition |
||||
// (outlined here: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729) |
||||
// is cheaper this way (or this way: https://github.com/Giveth/minime/blob/master/contracts/MiniMeToken.sol#L221-L225) |
||||
mapping (address => mapping (address => Allowance)) public allowances; |
||||
|
||||
/// @dev creates the token |
||||
/// NOTE passes tokenCofounders to base contract |
||||
/// see Cofounded |
||||
function OriginalToken (address[] tokenCofounders, |
||||
uint256 cofounderDistribution) Cofounded(tokenCofounders) public { |
||||
|
||||
if (hasExecutedCofounderDistribution || |
||||
cofounderDistribution == 0 || |
||||
totalSupply < cofounderDistribution) revert(); |
||||
|
||||
hasExecutedCofounderDistribution = true; |
||||
uint256 initialSupply = totalSupply; |
||||
|
||||
// divvy up initial token supply accross cofounders |
||||
// TODO: ensure each cofounder gets an equal base distribution |
||||
|
||||
for (uint8 x = 0; x < cofounders.length; x++) { |
||||
address cofounder = cofounders[x]; |
||||
|
||||
initialSupply -= cofounderDistribution; |
||||
// there should be some left over for the airdrop campaign |
||||
// otherwise don't create this contract |
||||
if (initialSupply < cofounderDistribution) revert(); |
||||
balances[cofounder] = cofounderDistribution; |
||||
} |
||||
|
||||
balances[msg.sender] += initialSupply; |
||||
} |
||||
|
||||
function transfer (address to, uint256 value) public returns (bool) { |
||||
return transferBalance (msg.sender, to, value); |
||||
} |
||||
|
||||
function transferFrom (address from, address to, uint256 value) public returns (bool success) { |
||||
Allowance storage allowance = allowances[from][msg.sender]; |
||||
if (allowance.amount < value) revert(); |
||||
|
||||
allowance.hasBeenPartiallyWithdrawn = true; |
||||
allowance.amount -= value; |
||||
|
||||
if (allowance.amount == 0) { |
||||
delete allowances[from][msg.sender]; |
||||
} |
||||
|
||||
return transferBalance(from, to, value); |
||||
} |
||||
|
||||
event ApprovalDenied (address indexed owner, address indexed spender); |
||||
|
||||
// TODO: test with an unintialized Allowance struct |
||||
function approve (address spender, uint256 value) public returns (bool success) { |
||||
Allowance storage allowance = allowances[msg.sender][spender]; |
||||
|
||||
if (value == 0) { |
||||
delete allowances[msg.sender][spender]; |
||||
Approval(msg.sender, spender, value); |
||||
return true; |
||||
} |
||||
|
||||
if (allowance.hasBeenPartiallyWithdrawn) { |
||||
delete allowances[msg.sender][spender]; |
||||
ApprovalDenied(msg.sender, spender); |
||||
return false; |
||||
} else { |
||||
allowance.amount = value; |
||||
Approval(msg.sender, spender, value); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// TODO: compare gas cost estimations between this and https://github.com/ConsenSys/Tokens/blob/master/contracts/eip20/EIP20.sol#L39-L45 |
||||
function transferBalance (address from, address to, uint256 value) private returns (bool) { |
||||
// don't burn these tokens |
||||
if (to == address(0) || from == to) revert(); |
||||
// match spec and emit events on 0 value |
||||
if (value == 0) { |
||||
Transfer(msg.sender, to, value); |
||||
return true; |
||||
} |
||||
|
||||
uint256 senderBalance = balances[from]; |
||||
uint256 receiverBalance = balances[to]; |
||||
if (senderBalance < value) revert(); |
||||
senderBalance -= value; |
||||
receiverBalance += value; |
||||
// overflow check (altough one could use https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol) |
||||
if (receiverBalance < value) revert(); |
||||
|
||||
balances[from] = senderBalance; |
||||
balances[to] = receiverBalance; |
||||
|
||||
Transfer(from, to, value); |
||||
return true; |
||||
} |
||||
|
||||
|
||||
// TODO: test with an unintialized Allowance struct |
||||
function allowance (address owner, address spender) public constant returns (uint256 remaining) { |
||||
return allowances[owner][spender].amount; |
||||
} |
||||
|
||||
function balanceOf (address owner) public constant returns (uint256 balance) { |
||||
return balances[owner]; |
||||
} |
||||
|
||||
function supportsInterface (bytes4 interfaceID) external constant returns (bool) { |
||||
return ((interfaceID == InterfaceSignature_ERC165) || |
||||
(interfaceID == InterfaceSignature_ERC20) || |
||||
(interfaceID == InterfaceSignature_ERC20_PlusOptions)); |
||||
} |
||||
} |
@ -1,349 +0,0 @@ |
||||
pragma solidity ^0.4.18; |
||||
|
||||
/** |
||||
* @title ERC20Basic |
||||
* @dev Simpler version of ERC20 interface |
||||
* @dev see https://github.com/ethereum/EIPs/issues/179 |
||||
*/ |
||||
contract ERC20Basic { |
||||
uint256 public totalSupply; |
||||
function balanceOf(address who) public view returns (uint256); |
||||
function transfer(address to, uint256 value) public returns (bool); |
||||
event Transfer(address indexed from, address indexed to, uint256 value); |
||||
} |
||||
|
||||
/** |
||||
* @title ERC20 interface |
||||
* @dev see https://github.com/ethereum/EIPs/issues/20 |
||||
*/ |
||||
contract ERC20 is ERC20Basic { |
||||
function allowance(address owner, address spender) public view returns (uint256); |
||||
function transferFrom(address from, address to, uint256 value) public returns (bool); |
||||
function approve(address spender, uint256 value) public returns (bool); |
||||
event Approval(address indexed owner, address indexed spender, uint256 value); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @title SafeMath |
||||
* @dev Math operations with safety checks that throw on error |
||||
*/ |
||||
library SafeMath { |
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
if (a == 0) { |
||||
return 0; |
||||
} |
||||
uint256 c = a * b; |
||||
assert(c / a == b); |
||||
return c; |
||||
} |
||||
|
||||
function div(uint256 a, uint256 b) internal pure 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 pure returns (uint256) { |
||||
assert(b <= a); |
||||
return a - b; |
||||
} |
||||
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
uint256 c = a + b; |
||||
assert(c >= a); |
||||
return c; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @title Basic token |
||||
* @dev Basic version of StandardToken, with no allowances. |
||||
*/ |
||||
contract BasicToken is ERC20Basic { |
||||
using SafeMath for uint256; |
||||
|
||||
mapping(address => uint256) balances; |
||||
|
||||
/** |
||||
* @dev transfer token for a specified address |
||||
* @param _to The address to transfer to. |
||||
* @param _value The amount to be transferred. |
||||
*/ |
||||
function transfer(address _to, uint256 _value) public returns (bool) { |
||||
require(_to != address(0)); |
||||
require(_value <= balances[msg.sender]); |
||||
|
||||
// SafeMath.sub will throw if there is not enough balance. |
||||
balances[msg.sender] = balances[msg.sender].sub(_value); |
||||
balances[_to] = balances[_to].add(_value); |
||||
Transfer(msg.sender, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Gets the balance of the specified address. |
||||
* @param _owner The address to query the the balance of. |
||||
* @return An uint256 representing the amount owned by the passed address. |
||||
*/ |
||||
function balanceOf(address _owner) public view returns (uint256 balance) { |
||||
return balances[_owner]; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* @title Standard ERC20 token |
||||
* |
||||
* @dev Implementation of the basic standard token. |
||||
* @dev https://github.com/ethereum/EIPs/issues/20 |
||||
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol |
||||
*/ |
||||
contract StandardToken is ERC20, BasicToken { |
||||
|
||||
mapping (address => mapping (address => uint256)) internal allowed; |
||||
|
||||
|
||||
/** |
||||
* @dev Transfer tokens from one address to another |
||||
* @param _from address The address which you want to send tokens from |
||||
* @param _to address The address which you want to transfer to |
||||
* @param _value uint256 the amount of tokens to be transferred |
||||
*/ |
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { |
||||
require(_to != address(0)); |
||||
require(_value <= balances[_from]); |
||||
require(_value <= allowed[_from][msg.sender]); |
||||
|
||||
balances[_from] = balances[_from].sub(_value); |
||||
balances[_to] = balances[_to].add(_value); |
||||
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); |
||||
Transfer(_from, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. |
||||
* |
||||
* Beware that changing an allowance with this method brings the risk that someone may use both the old |
||||
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this |
||||
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: |
||||
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 |
||||
* @param _spender The address which will spend the funds. |
||||
* @param _value The amount of tokens to be spent. |
||||
*/ |
||||
function approve(address _spender, uint256 _value) public returns (bool) { |
||||
allowed[msg.sender][_spender] = _value; |
||||
Approval(msg.sender, _spender, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Function to check the amount of tokens that an owner allowed to a spender. |
||||
* @param _owner address The address which owns the funds. |
||||
* @param _spender address The address which will spend the funds. |
||||
* @return A uint256 specifying the amount of tokens still available for the spender. |
||||
*/ |
||||
function allowance(address _owner, address _spender) public view returns (uint256) { |
||||
return allowed[_owner][_spender]; |
||||
} |
||||
|
||||
/** |
||||
* approve should be called when allowed[_spender] == 0. To increment |
||||
* allowed value is better to use this function to avoid 2 calls (and wait until |
||||
* the first transaction is mined) |
||||
* From MonolithDAO Token.sol |
||||
*/ |
||||
function increaseApproval(address _spender, uint _addedValue) public returns (bool) { |
||||
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); |
||||
Approval(msg.sender, _spender, allowed[msg.sender][_spender]); |
||||
return true; |
||||
} |
||||
|
||||
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { |
||||
uint oldValue = allowed[msg.sender][_spender]; |
||||
if (_subtractedValue > oldValue) { |
||||
allowed[msg.sender][_spender] = 0; |
||||
} else { |
||||
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); |
||||
} |
||||
Approval(msg.sender, _spender, allowed[msg.sender][_spender]); |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* @title Ownable |
||||
* @dev The Ownable contract has an owner address, and provides basic authorization control |
||||
* functions, this simplifies the implementation of "user permissions". |
||||
*/ |
||||
contract Ownable { |
||||
address public owner; |
||||
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); |
||||
|
||||
|
||||
/** |
||||
* @dev The Ownable constructor sets the original `owner` of the contract to the sender |
||||
* account. |
||||
*/ |
||||
function Ownable() public { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @dev Throws if called by any account other than the owner. |
||||
*/ |
||||
modifier onlyOwner() { |
||||
require(msg.sender == owner); |
||||
_; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @dev Allows the current owner to transfer control of the contract to a newOwner. |
||||
* @param newOwner The address to transfer ownership to. |
||||
*/ |
||||
function transferOwnership(address newOwner) public onlyOwner { |
||||
require(newOwner != address(0)); |
||||
OwnershipTransferred(owner, newOwner); |
||||
owner = newOwner; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* @title Pausable |
||||
* @dev Base contract which allows children to implement an emergency stop mechanism. |
||||
*/ |
||||
contract Pausable is Ownable { |
||||
event PausePublic(bool newState); |
||||
event PauseOwnerAdmin(bool newState); |
||||
|
||||
bool public pausedPublic = true; |
||||
bool public pausedOwnerAdmin = false; |
||||
|
||||
address public admin; |
||||
|
||||
/** |
||||
* @dev Modifier to make a function callable based on pause states. |
||||
*/ |
||||
modifier whenNotPaused() { |
||||
if(pausedPublic) { |
||||
if(!pausedOwnerAdmin) { |
||||
require(msg.sender == admin || msg.sender == owner); |
||||
} else { |
||||
revert(); |
||||
} |
||||
} |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
* @dev called by the owner to set new pause flags |
||||
* pausedPublic can't be false while pausedOwnerAdmin is true |
||||
*/ |
||||
function pause(bool newPausedPublic, bool newPausedOwnerAdmin) onlyOwner public { |
||||
require(!(newPausedPublic == false && newPausedOwnerAdmin == true)); |
||||
|
||||
pausedPublic = newPausedPublic; |
||||
pausedOwnerAdmin = newPausedOwnerAdmin; |
||||
|
||||
PausePublic(newPausedPublic); |
||||
PauseOwnerAdmin(newPausedOwnerAdmin); |
||||
} |
||||
} |
||||
|
||||
contract PausableToken is StandardToken, Pausable { |
||||
|
||||
function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) { |
||||
return super.transfer(_to, _value); |
||||
} |
||||
|
||||
function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) { |
||||
return super.transferFrom(_from, _to, _value); |
||||
} |
||||
|
||||
function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) { |
||||
return super.approve(_spender, _value); |
||||
} |
||||
|
||||
function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) { |
||||
return super.increaseApproval(_spender, _addedValue); |
||||
} |
||||
|
||||
function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) { |
||||
return super.decreaseApproval(_spender, _subtractedValue); |
||||
} |
||||
} |
||||
|
||||
|
||||
contract ZilliqaToken is PausableToken { |
||||
string public constant name = "Zilliqa"; |
||||
string public constant symbol = "ZIL"; |
||||
uint8 public constant decimals = 12; |
||||
|
||||
modifier validDestination( address to ) |
||||
{ |
||||
require(to != address(0x0)); |
||||
require(to != address(this)); |
||||
_; |
||||
} |
||||
|
||||
function ZilliqaToken( address _admin, uint _totalTokenAmount ) |
||||
{ |
||||
// assign the admin account |
||||
admin = _admin; |
||||
|
||||
// assign the total tokens to zilliqa |
||||
totalSupply = _totalTokenAmount; |
||||
balances[msg.sender] = _totalTokenAmount; |
||||
Transfer(address(0x0), msg.sender, _totalTokenAmount); |
||||
} |
||||
|
||||
function transfer(address _to, uint _value) validDestination(_to) returns (bool) |
||||
{ |
||||
return super.transfer(_to, _value); |
||||
} |
||||
|
||||
function transferFrom(address _from, address _to, uint _value) validDestination(_to) returns (bool) |
||||
{ |
||||
return super.transferFrom(_from, _to, _value); |
||||
} |
||||
|
||||
event Burn(address indexed _burner, uint _value); |
||||
|
||||
function burn(uint _value) returns (bool) |
||||
{ |
||||
balances[msg.sender] = balances[msg.sender].sub(_value); |
||||
totalSupply = totalSupply.sub(_value); |
||||
Burn(msg.sender, _value); |
||||
Transfer(msg.sender, address(0x0), _value); |
||||
return true; |
||||
} |
||||
|
||||
// save some gas by making only one contract call |
||||
function burnFrom(address _from, uint256 _value) returns (bool) |
||||
{ |
||||
assert( transferFrom( _from, msg.sender, _value ) ); |
||||
return burn(_value); |
||||
} |
||||
|
||||
function emergencyERC20Drain( ERC20 token, uint amount ) onlyOwner { |
||||
// owner can drain tokens that are sent here by mistake |
||||
token.transfer( owner, amount ); |
||||
} |
||||
|
||||
event AdminTransferred(address indexed previousAdmin, address indexed newAdmin); |
||||
|
||||
function changeAdmin(address newAdmin) onlyOwner { |
||||
// owner can re-assign the admin |
||||
AdminTransferred(admin, newAdmin); |
||||
admin = newAdmin; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,286 +0,0 @@ |
||||
pragma solidity ^0.4.18; |
||||
|
||||
// File: contracts/EtherDeltaI.sol |
||||
|
||||
contract EtherDeltaI { |
||||
|
||||
uint public feeMake; //percentage times (1 ether) |
||||
uint public feeTake; //percentage times (1 ether) |
||||
|
||||
mapping (address => mapping (address => uint)) public tokens; //mapping of token addresses to mapping of account balances (token=0 means Ether) |
||||
mapping (address => mapping (bytes32 => bool)) public orders; //mapping of user accounts to mapping of order hashes to booleans (true = submitted by user, equivalent to offchain signature) |
||||
mapping (address => mapping (bytes32 => uint)) public orderFills; //mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled) |
||||
|
||||
function deposit() payable; |
||||
|
||||
function withdraw(uint amount); |
||||
|
||||
function depositToken(address token, uint amount); |
||||
|
||||
function withdrawToken(address token, uint amount); |
||||
|
||||
function balanceOf(address token, address user) constant returns (uint); |
||||
|
||||
function order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce); |
||||
|
||||
function trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount); |
||||
|
||||
function testTrade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount, address sender) constant returns(bool); |
||||
|
||||
function availableVolume(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) constant returns(uint); |
||||
|
||||
function amountFilled(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) constant returns(uint); |
||||
|
||||
function cancelOrder(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, uint8 v, bytes32 r, bytes32 s); |
||||
|
||||
} |
||||
|
||||
// File: contracts/KindMath.sol |
||||
|
||||
/** |
||||
* @title KindMath |
||||
* @dev Math operations with safety checks that fail |
||||
*/ |
||||
library KindMath { |
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
uint256 c = a * b; |
||||
require(a == 0 || c / a == b); |
||||
return c; |
||||
} |
||||
|
||||
function div(uint256 a, uint256 b) internal pure 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 pure returns (uint256) { |
||||
require(b <= a); |
||||
return a - b; |
||||
} |
||||
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
uint256 c = a + b; |
||||
require(c >= a); |
||||
return c; |
||||
} |
||||
} |
||||
|
||||
// File: contracts/KeyValueStorage.sol |
||||
|
||||
contract KeyValueStorage { |
||||
|
||||
mapping(address => mapping(bytes32 => uint256)) _uintStorage; |
||||
mapping(address => mapping(bytes32 => address)) _addressStorage; |
||||
mapping(address => mapping(bytes32 => bool)) _boolStorage; |
||||
mapping(address => mapping(bytes32 => bytes32)) _bytes32Storage; |
||||
|
||||
/**** Get Methods ***********/ |
||||
|
||||
function getAddress(bytes32 key) public view returns (address) { |
||||
return _addressStorage[msg.sender][key]; |
||||
} |
||||
|
||||
function getUint(bytes32 key) public view returns (uint) { |
||||
return _uintStorage[msg.sender][key]; |
||||
} |
||||
|
||||
function getBool(bytes32 key) public view returns (bool) { |
||||
return _boolStorage[msg.sender][key]; |
||||
} |
||||
|
||||
function getBytes32(bytes32 key) public view returns (bytes32) { |
||||
return _bytes32Storage[msg.sender][key]; |
||||
} |
||||
|
||||
/**** Set Methods ***********/ |
||||
|
||||
function setAddress(bytes32 key, address value) public { |
||||
_addressStorage[msg.sender][key] = value; |
||||
} |
||||
|
||||
function setUint(bytes32 key, uint value) public { |
||||
_uintStorage[msg.sender][key] = value; |
||||
} |
||||
|
||||
function setBool(bytes32 key, bool value) public { |
||||
_boolStorage[msg.sender][key] = value; |
||||
} |
||||
|
||||
function setBytes32(bytes32 key, bytes32 value) public { |
||||
_bytes32Storage[msg.sender][key] = value; |
||||
} |
||||
|
||||
/**** Delete Methods ***********/ |
||||
|
||||
function deleteAddress(bytes32 key) public { |
||||
delete _addressStorage[msg.sender][key]; |
||||
} |
||||
|
||||
function deleteUint(bytes32 key) public { |
||||
delete _uintStorage[msg.sender][key]; |
||||
} |
||||
|
||||
function deleteBool(bytes32 key) public { |
||||
delete _boolStorage[msg.sender][key]; |
||||
} |
||||
|
||||
function deleteBytes32(bytes32 key) public { |
||||
delete _bytes32Storage[msg.sender][key]; |
||||
} |
||||
|
||||
} |
||||
|
||||
// File: contracts/StorageStateful.sol |
||||
|
||||
contract StorageStateful { |
||||
KeyValueStorage public keyValueStorage; |
||||
} |
||||
|
||||
// File: contracts/StorageConsumer.sol |
||||
|
||||
contract StorageConsumer is StorageStateful { |
||||
function StorageConsumer(address _storageAddress) public { |
||||
require(_storageAddress != address(0)); |
||||
keyValueStorage = KeyValueStorage(_storageAddress); |
||||
} |
||||
} |
||||
|
||||
// File: contracts/TokenI.sol |
||||
|
||||
contract Token { |
||||
/// @return total amount of tokens |
||||
function totalSupply() public returns (uint256); |
||||
|
||||
/// @param _owner The address from which the balance will be retrieved |
||||
/// @return The balance |
||||
function balanceOf(address _owner) public returns (uint256); |
||||
|
||||
/// @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) public returns (bool); |
||||
|
||||
/// @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) public returns (bool); |
||||
|
||||
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens |
||||
/// @param _spender The address of the account able to transfer the tokens |
||||
/// @param _value The amount of wei to be approved for transfer |
||||
/// @return Whether the approval was successful or not |
||||
function approve(address _spender, uint256 _value) public returns (bool); |
||||
|
||||
/// @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) public returns (uint256); |
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value); |
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value); |
||||
|
||||
uint256 public decimals; |
||||
string public name; |
||||
} |
||||
|
||||
// File: contracts/EnclavesDEXProxy.sol |
||||
|
||||
contract EnclavesDEXProxy is StorageConsumer { |
||||
using KindMath for uint256; |
||||
|
||||
address public admin; //the admin address |
||||
address public feeAccount; //the account that will receive fees |
||||
|
||||
struct EtherDeltaInfo { |
||||
uint256 feeMake; |
||||
uint256 feeTake; |
||||
} |
||||
|
||||
EtherDeltaInfo public etherDeltaInfo; |
||||
|
||||
uint256 public feeTake; //percentage times 1 ether |
||||
uint256 public feeAmountThreshold; //gasPrice amount under which no fees are charged |
||||
|
||||
address public etherDelta; |
||||
|
||||
bool public useEIP712 = true; |
||||
bytes32 public tradeABIHash; |
||||
bytes32 public withdrawABIHash; |
||||
|
||||
bool freezeTrading; |
||||
bool depositTokenLock; |
||||
|
||||
mapping (address => mapping (uint256 => bool)) nonceCheck; |
||||
|
||||
mapping (address => mapping (address => uint256)) public tokens; //mapping of token addresses to mapping of account balances (token=0 means Ether) |
||||
mapping (address => mapping (bytes32 => bool)) public orders; //mapping of user accounts to mapping of order hashes to booleans (true = submitted by user, equivalent to offchain signature) |
||||
mapping (address => mapping (bytes32 => uint256)) public orderFills; //mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled) |
||||
|
||||
address internal implementation; |
||||
address public proposedImplementation; |
||||
uint256 public proposedTimestamp; |
||||
|
||||
event Upgraded(address _implementation); |
||||
event UpgradedProposed(address _proposedImplementation, uint256 _proposedTimestamp); |
||||
|
||||
modifier onlyAdmin { |
||||
require(msg.sender == admin); |
||||
_; |
||||
} |
||||
|
||||
function EnclavesDEXProxy(address _storageAddress, address _implementation, address _admin, address _feeAccount, uint256 _feeTake, uint256 _feeAmountThreshold, address _etherDelta, bytes32 _tradeABIHash, bytes32 _withdrawABIHash) public |
||||
StorageConsumer(_storageAddress) |
||||
{ |
||||
require(_implementation != address(0)); |
||||
implementation = _implementation; |
||||
admin = _admin; |
||||
feeAccount = _feeAccount; |
||||
feeTake = _feeTake; |
||||
feeAmountThreshold = _feeAmountThreshold; |
||||
etherDelta = _etherDelta; |
||||
tradeABIHash = _tradeABIHash; |
||||
withdrawABIHash = _withdrawABIHash; |
||||
etherDeltaInfo.feeMake = EtherDeltaI(etherDelta).feeMake(); |
||||
etherDeltaInfo.feeTake = EtherDeltaI(etherDelta).feeTake(); |
||||
} |
||||
|
||||
function getImplementation() public view returns(address) { |
||||
return implementation; |
||||
} |
||||
|
||||
function proposeUpgrade(address _proposedImplementation) public onlyAdmin { |
||||
require(implementation != _proposedImplementation); |
||||
require(_proposedImplementation != address(0)); |
||||
proposedImplementation = _proposedImplementation; |
||||
proposedTimestamp = now + 2 weeks; |
||||
UpgradedProposed(proposedImplementation, now); |
||||
} |
||||
|
||||
function upgrade() public onlyAdmin { |
||||
require(proposedImplementation != address(0)); |
||||
require(proposedTimestamp < now); |
||||
implementation = proposedImplementation; |
||||
Upgraded(implementation); |
||||
} |
||||
|
||||
function () payable public { |
||||
bytes memory data = msg.data; |
||||
address impl = getImplementation(); |
||||
|
||||
assembly { |
||||
let result := delegatecall(gas, impl, add(data, 0x20), mload(data), 0, 0) |
||||
let size := returndatasize |
||||
let ptr := mload(0x40) |
||||
returndatacopy(ptr, 0, size) |
||||
switch result |
||||
case 0 { revert(ptr, size) } |
||||
default { return(ptr, size) } |
||||
} |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,454 +0,0 @@ |
||||
pragma solidity ^0.4.18; |
||||
|
||||
/** |
||||
|
||||
Copyright (c) 2018 The Ocean. |
||||
|
||||
Licensed under the MIT License: https://opensource.org/licenses/MIT. |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of this software and associated documentation files (the |
||||
"Software"), to deal in the Software without restriction, including |
||||
without limitation the rights to use, copy, modify, merge, publish, |
||||
distribute, sublicense, and/or sell copies of the Software, and to |
||||
permit persons to whom the Software is furnished to do so, subject to |
||||
the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
||||
**/ |
||||
|
||||
/** |
||||
* @title Ownable |
||||
* @dev The Ownable contract has an owner address, and provides basic authorization control |
||||
* functions, this simplifies the implementation of "user permissions". |
||||
*/ |
||||
contract Ownable { |
||||
address public owner; |
||||
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); |
||||
|
||||
|
||||
/** |
||||
* @dev The Ownable constructor sets the original `owner` of the contract to the sender |
||||
* account. |
||||
*/ |
||||
function Ownable() public { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
/** |
||||
* @dev Throws if called by any account other than the owner. |
||||
*/ |
||||
modifier onlyOwner() { |
||||
require(msg.sender == owner); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
* @dev Allows the current owner to transfer control of the contract to a newOwner. |
||||
* @param newOwner The address to transfer ownership to. |
||||
*/ |
||||
function transferOwnership(address newOwner) public onlyOwner { |
||||
require(newOwner != address(0)); |
||||
OwnershipTransferred(owner, newOwner); |
||||
owner = newOwner; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* @title ERC20Basic |
||||
* @dev Simpler version of ERC20 interface |
||||
* @dev see https://github.com/ethereum/EIPs/issues/179 |
||||
*/ |
||||
contract ERC20Basic { |
||||
function totalSupply() public view returns (uint256); |
||||
function balanceOf(address who) public view returns (uint256); |
||||
function transfer(address to, uint256 value) public returns (bool); |
||||
event Transfer(address indexed from, address indexed to, uint256 value); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* @title SafeMath |
||||
* @dev Math operations with safety checks that throw on error |
||||
*/ |
||||
library SafeMath { |
||||
|
||||
/** |
||||
* @dev Multiplies two numbers, throws on overflow. |
||||
*/ |
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
if (a == 0) { |
||||
return 0; |
||||
} |
||||
uint256 c = a * b; |
||||
assert(c / a == b); |
||||
return c; |
||||
} |
||||
|
||||
/** |
||||
* @dev Integer division of two numbers, truncating the quotient. |
||||
*/ |
||||
function div(uint256 a, uint256 b) internal pure 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; |
||||
} |
||||
|
||||
/** |
||||
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). |
||||
*/ |
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
assert(b <= a); |
||||
return a - b; |
||||
} |
||||
|
||||
/** |
||||
* @dev Adds two numbers, throws on overflow. |
||||
*/ |
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) { |
||||
uint256 c = a + b; |
||||
assert(c >= a); |
||||
return c; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* @title Basic token |
||||
* @dev Basic version of StandardToken, with no allowances. |
||||
*/ |
||||
contract BasicToken is ERC20Basic { |
||||
using SafeMath for uint256; |
||||
|
||||
mapping(address => uint256) balances; |
||||
|
||||
uint256 totalSupply_; |
||||
|
||||
/** |
||||
* @dev total number of tokens in existence |
||||
*/ |
||||
function totalSupply() public view returns (uint256) { |
||||
return totalSupply_; |
||||
} |
||||
|
||||
/** |
||||
* @dev transfer token for a specified address |
||||
* @param _to The address to transfer to. |
||||
* @param _value The amount to be transferred. |
||||
*/ |
||||
function transfer(address _to, uint256 _value) public returns (bool) { |
||||
require(_to != address(0)); |
||||
require(_value <= balances[msg.sender]); |
||||
|
||||
// SafeMath.sub will throw if there is not enough balance. |
||||
balances[msg.sender] = balances[msg.sender].sub(_value); |
||||
balances[_to] = balances[_to].add(_value); |
||||
Transfer(msg.sender, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Gets the balance of the specified address. |
||||
* @param _owner The address to query the the balance of. |
||||
* @return An uint256 representing the amount owned by the passed address. |
||||
*/ |
||||
function balanceOf(address _owner) public view returns (uint256 balance) { |
||||
return balances[_owner]; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* @title ERC20 interface |
||||
* @dev see https://github.com/ethereum/EIPs/issues/20 |
||||
*/ |
||||
contract ERC20 is ERC20Basic { |
||||
function allowance(address owner, address spender) public view returns (uint256); |
||||
function transferFrom(address from, address to, uint256 value) public returns (bool); |
||||
function approve(address spender, uint256 value) public returns (bool); |
||||
event Approval(address indexed owner, address indexed spender, uint256 value); |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* @title Standard ERC20 token |
||||
* |
||||
* @dev Implementation of the basic standard token. |
||||
* @dev https://github.com/ethereum/EIPs/issues/20 |
||||
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol |
||||
*/ |
||||
contract StandardToken is ERC20, BasicToken { |
||||
|
||||
mapping (address => mapping (address => uint256)) internal allowed; |
||||
|
||||
|
||||
/** |
||||
* @dev Transfer tokens from one address to another |
||||
* @param _from address The address which you want to send tokens from |
||||
* @param _to address The address which you want to transfer to |
||||
* @param _value uint256 the amount of tokens to be transferred |
||||
*/ |
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { |
||||
require(_to != address(0)); |
||||
require(_value <= balances[_from]); |
||||
require(_value <= allowed[_from][msg.sender]); |
||||
|
||||
balances[_from] = balances[_from].sub(_value); |
||||
balances[_to] = balances[_to].add(_value); |
||||
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); |
||||
Transfer(_from, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. |
||||
* |
||||
* Beware that changing an allowance with this method brings the risk that someone may use both the old |
||||
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this |
||||
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: |
||||
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 |
||||
* @param _spender The address which will spend the funds. |
||||
* @param _value The amount of tokens to be spent. |
||||
*/ |
||||
function approve(address _spender, uint256 _value) public returns (bool) { |
||||
allowed[msg.sender][_spender] = _value; |
||||
Approval(msg.sender, _spender, _value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Function to check the amount of tokens that an owner allowed to a spender. |
||||
* @param _owner address The address which owns the funds. |
||||
* @param _spender address The address which will spend the funds. |
||||
* @return A uint256 specifying the amount of tokens still available for the spender. |
||||
*/ |
||||
function allowance(address _owner, address _spender) public view returns (uint256) { |
||||
return allowed[_owner][_spender]; |
||||
} |
||||
|
||||
/** |
||||
* @dev Increase the amount of tokens that an owner allowed to a spender. |
||||
* |
||||
* approve should be called when allowed[_spender] == 0. To increment |
||||
* allowed value is better to use this function to avoid 2 calls (and wait until |
||||
* the first transaction is mined) |
||||
* From MonolithDAO Token.sol |
||||
* @param _spender The address which will spend the funds. |
||||
* @param _addedValue The amount of tokens to increase the allowance by. |
||||
*/ |
||||
function increaseApproval(address _spender, uint _addedValue) public returns (bool) { |
||||
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); |
||||
Approval(msg.sender, _spender, allowed[msg.sender][_spender]); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Decrease the amount of tokens that an owner allowed to a spender. |
||||
* |
||||
* approve should be called when allowed[_spender] == 0. To decrement |
||||
* allowed value is better to use this function to avoid 2 calls (and wait until |
||||
* the first transaction is mined) |
||||
* From MonolithDAO Token.sol |
||||
* @param _spender The address which will spend the funds. |
||||
* @param _subtractedValue The amount of tokens to decrease the allowance by. |
||||
*/ |
||||
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { |
||||
uint oldValue = allowed[msg.sender][_spender]; |
||||
if (_subtractedValue > oldValue) { |
||||
allowed[msg.sender][_spender] = 0; |
||||
} else { |
||||
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); |
||||
} |
||||
Approval(msg.sender, _spender, allowed[msg.sender][_spender]); |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* @title Whitelist |
||||
* @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions. |
||||
* @dev This simplifies the implementation of "user permissions". |
||||
*/ |
||||
contract Whitelist is Ownable { |
||||
mapping(address => bool) public whitelist; |
||||
|
||||
event WhitelistedAddressAdded(address addr); |
||||
event WhitelistedAddressRemoved(address addr); |
||||
|
||||
/** |
||||
* @dev Throws if called by any account that's not whitelisted. |
||||
*/ |
||||
modifier onlyWhitelisted() { |
||||
require(whitelist[msg.sender]); |
||||
_; |
||||
} |
||||
|
||||
/** |
||||
* @dev add an address to the whitelist |
||||
* @param addr address |
||||
* @return true if the address was added to the whitelist, false if the address was already in the whitelist |
||||
*/ |
||||
function addAddressToWhitelist(address addr) onlyOwner public returns(bool success) { |
||||
if (!whitelist[addr]) { |
||||
whitelist[addr] = true; |
||||
WhitelistedAddressAdded(addr); |
||||
success = true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @dev add addresses to the whitelist |
||||
* @param addrs addresses |
||||
* @return true if at least one address was added to the whitelist, |
||||
* false if all addresses were already in the whitelist |
||||
*/ |
||||
function addAddressesToWhitelist(address[] addrs) onlyOwner public returns(bool success) { |
||||
for (uint256 i = 0; i < addrs.length; i++) { |
||||
if (addAddressToWhitelist(addrs[i])) { |
||||
success = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @dev remove an address from the whitelist |
||||
* @param addr address |
||||
* @return true if the address was removed from the whitelist, |
||||
* false if the address wasn't in the whitelist in the first place |
||||
*/ |
||||
function removeAddressFromWhitelist(address addr) onlyOwner public returns(bool success) { |
||||
if (whitelist[addr]) { |
||||
whitelist[addr] = false; |
||||
WhitelistedAddressRemoved(addr); |
||||
success = true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @dev remove addresses from the whitelist |
||||
* @param addrs addresses |
||||
* @return true if at least one address was removed from the whitelist, |
||||
* false if all addresses weren't in the whitelist in the first place |
||||
*/ |
||||
function removeAddressesFromWhitelist(address[] addrs) onlyOwner public returns(bool success) { |
||||
for (uint256 i = 0; i < addrs.length; i++) { |
||||
if (removeAddressFromWhitelist(addrs[i])) { |
||||
success = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
contract OceanTokenTransferManager is Ownable, Whitelist { |
||||
|
||||
/** |
||||
* @dev check if transferFrom is possible |
||||
* @param _from address The address which you want to send tokens from |
||||
* @param _to address The address which you want to transfer to |
||||
*/ |
||||
function canTransferFrom(address _from, address _to) public constant returns (bool success) { |
||||
if (whitelist[_from] == true || whitelist[_to] == true) { |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
contract OceanToken is StandardToken, Ownable { |
||||
event Airdrop(address indexed _to, uint256 _amount); |
||||
|
||||
string public constant name = 'The Ocean Token'; |
||||
string public constant symbol = 'OCEAN'; |
||||
uint8 public constant decimals = 18; |
||||
|
||||
OceanTokenTransferManager public transferManagerContract; |
||||
|
||||
/** |
||||
* @dev Airdrop the specified amount to the address |
||||
* @param _to The address that will receive the airdropped tokens. |
||||
* @param _requestedAmount The amount of tokens to airdrop. |
||||
* @return A boolean that indicates if the operation was successful. |
||||
*/ |
||||
function airdrop(address _to, uint256 _requestedAmount) onlyOwner public returns (bool) { |
||||
uint256 _amountToDrop = _requestedAmount; |
||||
|
||||
totalSupply_ = totalSupply_.add(_amountToDrop); |
||||
balances[_to] = balances[_to].add(_amountToDrop); |
||||
emit Airdrop(_to, _amountToDrop); |
||||
emit Transfer(address(0), _to, _amountToDrop); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @dev Transfer tokens from one address to another |
||||
* @param _from address The address which you want to send tokens from |
||||
* @param _to address The address which you want to transfer to |
||||
* @param _value uint256 the amount of tokens to be transferred |
||||
*/ |
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { |
||||
require(_to != address(0)); |
||||
require(_value <= balances[_from]); |
||||
require(_value <= allowed[_from][msg.sender]); |
||||
|
||||
// trading possible when at least one from list [_from, _to] is whitelisted |
||||
require(transferManagerContract.canTransferFrom(_from, _to)); |
||||
|
||||
balances[_from] = balances[_from].sub(_value); |
||||
balances[_to] = balances[_to].add(_value); |
||||
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); |
||||
emit Transfer(_from, _to, _value); |
||||
return true; |
||||
} |
||||
|
||||
function setTransferManagerContract(OceanTokenTransferManager _transferManagerContract) onlyOwner public { |
||||
transferManagerContract = _transferManagerContract; |
||||
} |
||||
} |
@ -1,24 +0,0 @@ |
||||
from os import listdir |
||||
from os.path import isfile, join |
||||
import subprocess |
||||
|
||||
contracts_path = "../../smart-contracts-detectors-testing/most_used/contracts/" |
||||
slither_format_output_path = "./slither_format/tests/slither_format_output_most_used_contracts/" |
||||
|
||||
def analyze_contract_with_slither_format(): |
||||
for contract_file in contract_files: |
||||
run_slither_format(contract_file) |
||||
|
||||
def run_slither_format(contract_name): |
||||
print("Running Slither Format on contract: " + contract_name) |
||||
command = "python3 -m slither_format " + contracts_path+contract_name |
||||
contract_slither_output_fd = open(slither_format_output_path+contract_name[:-21]+".txt","w+") |
||||
contract_slither_output_fd.write("Command run: " + command + "\n\n") |
||||
contract_slither_output_fd.flush() |
||||
result = subprocess.run(command, shell=True, stdout=contract_slither_output_fd, stderr=contract_slither_output_fd) |
||||
contract_slither_output_fd.close() |
||||
|
||||
if __name__ == "__main__": |
||||
contract_files = [f for f in listdir(contracts_path) if f.endswith(".sol")] |
||||
print("Number of contract files: " + str(len(contract_files))) |
||||
analyze_contract_with_slither_format() |
@ -1,22 +0,0 @@ |
||||
import subprocess |
||||
|
||||
p9 = subprocess.Popen(['python3', './slither_format/tests/test_unicode.py']) |
||||
p9.wait() |
||||
p8 = subprocess.Popen(['python3', './slither_format/tests/test_detector_combinations.py']) |
||||
p8.wait() |
||||
p7 = subprocess.Popen(['python3', './slither_format/tests/test_solc_version.py']) |
||||
p7.wait() |
||||
p6 = subprocess.Popen(['python3', './slither_format/tests/test_pragma.py']) |
||||
p6.wait() |
||||
p5 = subprocess.Popen(['python3', './slither_format/tests/test_naming_convention.py']) |
||||
p5.wait() |
||||
p4 = subprocess.Popen(['python3', './slither_format/tests/test_unused_state_vars.py']) |
||||
p4.wait() |
||||
p3 = subprocess.Popen(['python3', './slither_format/tests/test_external_function.py']) |
||||
p3.wait() |
||||
p2 = subprocess.Popen(['python3', './slither_format/tests/test_constant_function.py']) |
||||
p2.wait() |
||||
p1 = subprocess.Popen(['python3', './slither_format/tests/test_constable_states.py']) |
||||
p1.wait() |
||||
|
||||
|
@ -1,57 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestConstableState(unittest.TestCase): |
||||
testDataFile = "const_state_variables.sol" |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testFilePath = testDataDir+testDataFile |
||||
|
||||
def setUp(self): |
||||
outFD = open(self.testFilePath+".out","w") |
||||
errFD = open(self.testFilePath+".err","w") |
||||
p = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','constable-states',self.testFilePath], stdout=outFD,stderr=errFD) |
||||
p.wait() |
||||
outFD.close() |
||||
errFD.close() |
||||
|
||||
def tearDown(self): |
||||
p = subprocess.Popen(['rm','-f',self.testFilePath+'.out',self.testFilePath+'.err',self.testFilePath+'.format']) |
||||
p.wait() |
||||
|
||||
def test_constable_states(self): |
||||
errFD = open(self.testFilePath+".err","r") |
||||
errFD_lines = errFD.readlines() |
||||
for i in range(len(errFD_lines)): |
||||
errFD_lines[i] = errFD_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD_lines[0].rstrip(),"INFO:Slither.Format:Number of Slither results: 6") |
||||
self.assertEqual(errFD_lines[1].rstrip(),"INFO:Slither.Format:Number of patches: 6") |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Detector: constable-states"), 6) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: address public constant myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 132"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 208"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: uint public test = 5"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: uint public constant test = 5"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 237"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 257"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: string text2 = \"xyz\""), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: string constant text2 = \"xyz\""), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 333"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 353"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: address public constant mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 496"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 572"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: bytes32 should_be_constant = sha256('abc')"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: bytes32 constant should_be_constant = sha256('abc')"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 793"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 835"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: uint should_be_constant_2 = A + 1"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: uint constant should_be_constant_2 = A + 1"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 841"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 874"), 1) |
||||
errFD.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,65 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestConstantFunctions(unittest.TestCase): |
||||
testDataFile1 = "constant.sol" |
||||
testDataFile2 = "constant-0.5.1.sol" |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testFilePath1 = testDataDir+testDataFile1 |
||||
testFilePath2 = testDataDir+testDataFile2 |
||||
|
||||
def setUp(self): |
||||
outFD1 = open(self.testFilePath1+".out","w") |
||||
errFD1 = open(self.testFilePath1+".err","w") |
||||
p1 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','constant-function',self.testFilePath1], stdout=outFD1,stderr=errFD1) |
||||
p1.wait() |
||||
outFD2 = open(self.testFilePath2+".out","w") |
||||
errFD2 = open(self.testFilePath2+".err","w") |
||||
p2 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','constant-function',self.testFilePath2], stdout=outFD2,stderr=errFD2) |
||||
p2.wait() |
||||
outFD1.close() |
||||
errFD1.close() |
||||
outFD2.close() |
||||
errFD2.close() |
||||
|
||||
def tearDown(self): |
||||
p1 = subprocess.Popen(['rm','-f',self.testFilePath1+'.out',self.testFilePath1+'.err',self.testFilePath1+'.format']) |
||||
p1.wait() |
||||
p2 = subprocess.Popen(['rm','-f',self.testFilePath2+'.out',self.testFilePath2+'.err',self.testFilePath2+'.format']) |
||||
p2.wait() |
||||
|
||||
def test_constant_function(self): |
||||
errFD1 = open(self.testFilePath1+".err","r") |
||||
errFD1_lines = errFD1.readlines() |
||||
for i in range(len(errFD1_lines)): |
||||
errFD1_lines[i] = errFD1_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath1+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD1_lines[0],"INFO:Slither.Format:Number of Slither results: 3") |
||||
self.assertEqual(errFD1_lines[1],"INFO:Slither.Format:Number of patches: 3") |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: constant-function"), 3) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: view"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: constant"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string:"), 3) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 77"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 81"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 149"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 157"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 360"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 364"), 1) |
||||
errFD1.close() |
||||
|
||||
errFD2 = open(self.testFilePath2+".err","r") |
||||
errFD2_lines = errFD2.readlines() |
||||
for i in range(len(errFD2_lines)): |
||||
errFD2_lines[i] = errFD2_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath2+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD2_lines[0],"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD2_lines[1],"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: view"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string:"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 221"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 225"), 1) |
||||
errFD2.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,52 +0,0 @@ |
||||
//pragma solidity ^0.4.24; |
||||
|
||||
|
||||
contract A { |
||||
|
||||
address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; |
||||
address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; |
||||
|
||||
uint public used; |
||||
uint public test = 5; |
||||
|
||||
uint constant X = 32**22 + 8; |
||||
string constant TEXT1 = "abc"; |
||||
string text2 = "xyz"; |
||||
|
||||
function setUsed() public { |
||||
if (msg.sender == MY_ADDRESS) { |
||||
used = test; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
contract B is A { |
||||
|
||||
address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; |
||||
|
||||
function () external { |
||||
used = 0; |
||||
} |
||||
|
||||
function setUsed(uint a) public { |
||||
if (msg.sender == MY_ADDRESS) { |
||||
used = a; |
||||
} |
||||
} |
||||
} |
||||
|
||||
contract MyConc{ |
||||
|
||||
uint constant A = 1; |
||||
bytes32 should_be_constant = sha256('abc'); |
||||
uint should_be_constant_2 = A + 1; |
||||
address not_constant = msg.sender; |
||||
uint not_constant_2 = getNumber(); |
||||
uint not_constant_3 = 10 + block.number; |
||||
|
||||
function getNumber() public returns(uint){ |
||||
return block.number; |
||||
} |
||||
|
||||
} |
@ -1,18 +0,0 @@ |
||||
contract Constant { |
||||
|
||||
uint a; |
||||
|
||||
|
||||
function test_view_shadow() public view{ |
||||
uint a; |
||||
a = 0; |
||||
} |
||||
|
||||
function test_view() public view{ |
||||
a; |
||||
} |
||||
|
||||
function test_assembly_bug() public view{ |
||||
assembly{} |
||||
} |
||||
} |
@ -1,25 +0,0 @@ |
||||
contract Constant { |
||||
|
||||
uint a; |
||||
|
||||
function test_view_bug() public view{ |
||||
a = 0; |
||||
} |
||||
|
||||
function test_constant_bug() public constant{ |
||||
a = 0; |
||||
} |
||||
|
||||
function test_view_shadow() public view{ |
||||
uint a; |
||||
a = 0; |
||||
} |
||||
|
||||
function test_view() public view{ |
||||
a; |
||||
} |
||||
|
||||
function test_assembly_bug() public view{ |
||||
assembly{} |
||||
} |
||||
} |
@ -1,48 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract A { |
||||
|
||||
/* constant state variable naming - bad */ |
||||
/* unused state variable - bad */ |
||||
/* Overlapping detectors - so neither will be applied for now */ |
||||
uint max_tx = 100; |
||||
|
||||
/* state variable declaration naming convention - bad */ |
||||
uint SV_count = 0; |
||||
|
||||
modifier mod (uint c) { |
||||
require (c > 100); |
||||
_; |
||||
} |
||||
|
||||
/* parameter declaration naming convention - bad */ |
||||
function foo(uint Count) { |
||||
/* parameter use naming convention- bad */ |
||||
/* state variable use naming convention - bad */ |
||||
SV_count = Count; |
||||
} |
||||
|
||||
/* implicitly public, can be made external - bad */ |
||||
/* parameter declarations naming convention - bad */ |
||||
function foobar(uint Count, uint Number) returns (uint) { |
||||
/* parameter use naming convention - bad */ |
||||
foo (Number); |
||||
/* parameter use naming convention - bad */ |
||||
return (Count+Number); |
||||
} |
||||
|
||||
/* explicitly public, can be made external - bad */ |
||||
/* view but modifies state - bad */ |
||||
/* parameter declarations naming convention - bad */ |
||||
/* parameter use passed to modifier naming convention - bad */ |
||||
function bar(uint Count) public view mod (Count) returns(uint) { |
||||
/* Use of state variable naming convention - bad */ |
||||
/* Use of parameter naming convention - bad */ |
||||
SV_count += Count; |
||||
/* Use of state variable naming convention - bad */ |
||||
return (SV_count); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
@ -1,121 +0,0 @@ |
||||
//pragma solidity ^0.4.24; |
||||
|
||||
import "./external_function_import.sol"; |
||||
|
||||
contract ContractWithFunctionCalledSuper is ContractWithFunctionCalled { |
||||
function callWithSuper() public { |
||||
uint256 i = 0; |
||||
} |
||||
} |
||||
|
||||
contract ContractWithFunctionNotCalled { |
||||
|
||||
modifier mod (uint c) { |
||||
require (c > 0); |
||||
_; |
||||
} |
||||
|
||||
// With parameter and return |
||||
function funcNotCalled5(uint _i) |
||||
public returns (uint) { |
||||
return(_i + 10); |
||||
} |
||||
|
||||
// With no visibility specifier which is ok until solc 0.5.0 |
||||
function funcNotCalled4() { |
||||
} |
||||
|
||||
function funcNotCalled3() public |
||||
returns (uint a) |
||||
{ |
||||
a = 100; |
||||
} |
||||
|
||||
function funcNotCalled2() public { |
||||
} |
||||
|
||||
function funcNotCalled() public { |
||||
} |
||||
|
||||
function my_func() internal returns(bool) { |
||||
return true; |
||||
} |
||||
|
||||
/* Cannot be converted to external because parameter i is written to in function and so cannot be in calldata */ |
||||
function test4(uint i) public returns(uint){ |
||||
i += 1; |
||||
return(i); |
||||
} |
||||
|
||||
/* public with modifier */ |
||||
function test5(uint number) public mod (number) returns(uint){ |
||||
return(number); |
||||
} |
||||
|
||||
/* implicit with modifier */ |
||||
function test6(uint number) mod (number) returns(uint){ |
||||
return(number); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract ContractWithFunctionNotCalled2 is ContractWithFunctionCalledSuper { |
||||
function funcNotCalled() public { |
||||
uint256 i = 0; |
||||
address three = address(new ContractWithFunctionNotCalled()); |
||||
three.call(abi.encode(bytes4(keccak256("helloTwo()")))); |
||||
super.callWithSuper(); |
||||
ContractWithFunctionCalled c = new ContractWithFunctionCalled(); |
||||
c.funcCalled(); |
||||
} |
||||
} |
||||
|
||||
contract InternalCall { |
||||
|
||||
function() returns(uint) ptr; |
||||
|
||||
function set_test1() external{ |
||||
ptr = test1; |
||||
} |
||||
|
||||
function set_test2() external{ |
||||
ptr = test2; |
||||
} |
||||
|
||||
function test1() public returns(uint){ |
||||
return 1; |
||||
} |
||||
|
||||
function test2() public returns(uint){ |
||||
return 2; |
||||
} |
||||
|
||||
function test3() public returns(uint){ |
||||
return 3; |
||||
} |
||||
|
||||
function exec() external returns(uint){ |
||||
return ptr(); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract publicKeywordTest { |
||||
|
||||
modifier publicMod() { |
||||
_; |
||||
} |
||||
|
||||
function test1(uint k) public{ |
||||
} |
||||
|
||||
function test2() publicMod { |
||||
} |
||||
|
||||
function test3() publicMod public { |
||||
} |
||||
|
||||
function test4(uint k)public{ |
||||
} |
||||
|
||||
} |
@ -1,55 +0,0 @@ |
||||
// This tests against false-positives. This test should output no recommendations from the external-function detector. |
||||
|
||||
|
||||
contract ContractWithBaseFunctionCalled { |
||||
function getsCalledByBase() public; |
||||
function callsOverrideMe() external { |
||||
getsCalledByBase(); |
||||
} |
||||
} |
||||
|
||||
|
||||
contract DerivingContractWithBaseCalled is ContractWithBaseFunctionCalled { |
||||
function getsCalledByBase() public { |
||||
// This should not be recommended to be marked external because it is called by the base class. |
||||
} |
||||
} |
||||
|
||||
|
||||
// All the contracts below should not recommend changing to external since inherited contracts have dynamic calls. |
||||
contract ContractWithDynamicCall { |
||||
function() returns(uint) ptr; |
||||
|
||||
function test1() public returns(uint){ |
||||
return 1; |
||||
} |
||||
|
||||
function test2() public returns(uint){ |
||||
return 2; |
||||
} |
||||
|
||||
function setTest1() external{ |
||||
ptr = test1; |
||||
} |
||||
|
||||
function setTest2() external{ |
||||
ptr = test2; |
||||
} |
||||
|
||||
function exec() external returns(uint){ |
||||
return ptr(); |
||||
} |
||||
} |
||||
|
||||
contract DerivesFromDynamicCall is ContractWithDynamicCall{ |
||||
function getsCalledDynamically() public returns (uint){ |
||||
// This should not be recommended because it is called dynamically. |
||||
return 3; |
||||
} |
||||
function setTest3() public { |
||||
// This should not be recommended because we inherit from a contract that calls dynamically, and we cannot be |
||||
// sure it did not somehow call this function. |
||||
|
||||
ptr = getsCalledDynamically; |
||||
} |
||||
} |
@ -1,7 +0,0 @@ |
||||
// This file is imported by external_function.sol |
||||
|
||||
contract ContractWithFunctionCalled { |
||||
function funcCalled() external { |
||||
uint256 i = 0; |
||||
} |
||||
} |
@ -1,108 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract naming { |
||||
|
||||
enum Numbers {ONE, TWO} |
||||
enum numbers {ONE, TWO} |
||||
|
||||
numbers nums = numbers.TWO; |
||||
|
||||
uint constant MY_CONSTANT = 1; |
||||
uint constant MY_other_CONSTANT = 2; |
||||
|
||||
uint Var_One = 1; uint varTwo = 2; |
||||
|
||||
struct test { |
||||
uint a; |
||||
} |
||||
|
||||
struct Test { |
||||
uint a; |
||||
} |
||||
|
||||
test t; |
||||
|
||||
event Event_(uint); |
||||
event event_(uint); |
||||
|
||||
uint Number2; |
||||
|
||||
function getOne(bytes32 b) view public returns(uint) { |
||||
return MY_other_CONSTANT; |
||||
} |
||||
|
||||
function getOne(uint i) view public returns(numbers) { |
||||
numbers num; |
||||
num = numbers.ONE; |
||||
return(num); |
||||
} |
||||
|
||||
function getOne() view public returns(uint) |
||||
{ |
||||
uint naming; |
||||
naming = GetOne(naming); |
||||
event_(naming); |
||||
return 1; |
||||
} |
||||
|
||||
function GetOne(uint i) view public returns (uint) |
||||
{ |
||||
return (1 + Number2); |
||||
} |
||||
|
||||
function setInt(uint number1, uint Number2) public |
||||
{ |
||||
uint i = number1 + Number2; |
||||
} |
||||
|
||||
|
||||
modifier CantDo() { |
||||
_; |
||||
} |
||||
|
||||
modifier canDo() { |
||||
_; |
||||
} |
||||
} |
||||
|
||||
contract Test { |
||||
naming n; |
||||
|
||||
function foo() { |
||||
n.GetOne(10); |
||||
} |
||||
} |
||||
|
||||
contract T { |
||||
uint private _myPrivateVar; |
||||
uint _myPublicVar; |
||||
|
||||
modifier ModifierTest() { |
||||
_; |
||||
} |
||||
|
||||
modifier modifierTestContractTypes(naming m1) { |
||||
naming m2; |
||||
_; |
||||
} |
||||
|
||||
function functionTestModifier(uint i) public ModifierTest returns(uint) { |
||||
return _myPrivateVar; |
||||
} |
||||
|
||||
function functionTestContractTypes(naming n1) public returns(naming) { |
||||
naming n2; |
||||
return(n2); |
||||
} |
||||
|
||||
function test(uint _unused, uint _used) public returns(uint){ |
||||
return _used; |
||||
} |
||||
|
||||
|
||||
uint k = 1; |
||||
|
||||
uint constant M = 1; |
||||
|
||||
uint l = 1; |
||||
} |
@ -1,51 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
/* contract definitione */ |
||||
contract one { |
||||
/* contract declaration as state variable */ |
||||
three k; |
||||
|
||||
function foo(uint i) { |
||||
/* contract declaration as local variable */ |
||||
three l; |
||||
l.foo(10); |
||||
k.foo(10); |
||||
} |
||||
} |
||||
|
||||
/* contract definitione */ |
||||
contract Two { |
||||
/* contract declaration as state variable */ |
||||
one m; |
||||
|
||||
function foo() { |
||||
/* contract declaration as local variable */ |
||||
one n; |
||||
n.foo(10); |
||||
m.foo(100); |
||||
} |
||||
|
||||
} |
||||
|
||||
/* contract definitione */ |
||||
contract three { |
||||
/* contract declaration as state variable */ |
||||
Two o; |
||||
|
||||
/* contract as function return value */ |
||||
function foo(uint i) returns (one) { |
||||
/* contract declaration as local variable */ |
||||
Two p; |
||||
p.foo(); |
||||
o.foo(); |
||||
/* new contract object */ |
||||
one r = new one(); |
||||
return(r); |
||||
} |
||||
|
||||
/* contract as function parameter */ |
||||
function foobar(one q) { |
||||
q.foo(10); |
||||
} |
||||
} |
||||
|
@ -1,53 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract A { |
||||
|
||||
/* enum definition - bad */ |
||||
enum e {ONE, TWO} |
||||
|
||||
/* enum declaration - bad */ |
||||
e e1; |
||||
|
||||
function foo() { |
||||
/* enum use - bad */ |
||||
e1 = e.ONE; |
||||
} |
||||
} |
||||
|
||||
contract B { |
||||
|
||||
/* enum definition - good */ |
||||
enum E {ONE, TWO} |
||||
|
||||
/* enum definition - good */ |
||||
E e1; |
||||
|
||||
function foo() { |
||||
/* enum use - good */ |
||||
e1 = E.ONE; |
||||
} |
||||
|
||||
} |
||||
|
||||
contract C { |
||||
|
||||
/* enum definition - bad */ |
||||
enum e {ONE, TWO} |
||||
|
||||
/* enum declaration - bad */ |
||||
e e1; |
||||
|
||||
/* enum as parameter and return value - bad */ |
||||
function foo(e eA) returns (e) { |
||||
e e2 = eA; |
||||
return (e2); |
||||
} |
||||
} |
||||
|
||||
contract D is C { |
||||
/* enum as parameter and return value - bad */ |
||||
function foo(e eA) returns (e) { |
||||
e e2 = eA; |
||||
return (e2); |
||||
} |
||||
} |
@ -1,40 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract One { |
||||
/* event declaration - bad */ |
||||
event e(uint); |
||||
|
||||
function foo(uint i) { |
||||
/* event call - bad */ |
||||
e(i); |
||||
} |
||||
} |
||||
|
||||
contract Two { |
||||
/* event declaration - good */ |
||||
event E(uint); |
||||
|
||||
function foo(uint i) { |
||||
/* event call - good */ |
||||
E(i); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract Three { |
||||
/* event declaration - bad */ |
||||
event e(uint); |
||||
|
||||
function foo(uint i) { |
||||
/* event call with emit - bad */ |
||||
emit e(i); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract Four is Three { |
||||
function foo(uint i) { |
||||
/* event call with emit - bad */ |
||||
emit e(i); |
||||
} |
||||
} |
@ -1,33 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract A { |
||||
|
||||
/* function definition - bad */ |
||||
function Foo() { |
||||
/* function call - bad */ |
||||
uint i = Foobar(10); |
||||
} |
||||
|
||||
/* function definition - bad */ |
||||
function Foobar(uint i) returns (uint) { |
||||
return (1+10); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract B { |
||||
/* function definition - good */ |
||||
function foo() { |
||||
/* function call - good */ |
||||
uint i = foobar(10); |
||||
} |
||||
|
||||
/* function definition - good */ |
||||
function foobar(uint i) returns (uint) { |
||||
A a; |
||||
/* function call - bad */ |
||||
return (a.Foobar(10) + i); |
||||
} |
||||
} |
||||
|
||||
|
@ -1,53 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract A { |
||||
|
||||
/* modifier definition - good */ |
||||
modifier one() { |
||||
_; |
||||
} |
||||
|
||||
/* modifier use - good */ |
||||
function foo() one { |
||||
} |
||||
} |
||||
|
||||
contract B { |
||||
/* modifier definition - bad */ |
||||
modifier One() { |
||||
_; |
||||
} |
||||
|
||||
/* modifier use - bad */ |
||||
function foo () One { |
||||
} |
||||
|
||||
} |
||||
|
||||
contract C { |
||||
|
||||
/* modifier definition - good */ |
||||
modifier one() { |
||||
_; |
||||
} |
||||
|
||||
/* modifier definition - bad */ |
||||
modifier Two() { |
||||
_; |
||||
} |
||||
|
||||
/* modifier uses - good and bad */ |
||||
function foo() one Two returns (uint) { |
||||
/* Local variable with same name as bad modifier name from contract B */ |
||||
uint One; |
||||
return(One); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract D is C { |
||||
/* modifier uses - good and bad */ |
||||
function foo() one Two returns (uint) { |
||||
} |
||||
} |
||||
|
@ -1,47 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract A { |
||||
|
||||
/* parameter declaration - bad */ |
||||
function foo(uint Count) { |
||||
/* parameter use - bad */ |
||||
uint i = Count; |
||||
} |
||||
|
||||
/* parameter declarations - bad */ |
||||
function foobar(uint Count, uint Number) returns (uint) { |
||||
/* parameter declarations - bad */ |
||||
return (Count+Number); |
||||
} |
||||
|
||||
modifier mod (uint c) { |
||||
require (c > 100); |
||||
_; |
||||
} |
||||
|
||||
/* parameter declarations - bad */ |
||||
/* function parameter passed to modifier */ |
||||
function bar(uint Count) mod (Count) returns(uint) { |
||||
/* parameter declarations - bad */ |
||||
return (Count); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
contract B { |
||||
|
||||
mapping(address => uint256) balances; |
||||
|
||||
/* parameter declarations - bad */ |
||||
function bar(address _to, address _from) returns (uint){ |
||||
uint i; |
||||
/* parameter use - bad */ |
||||
i = balances[_to]; |
||||
/* parameter use - bad */ |
||||
balances[_from] = 100; |
||||
return(i); |
||||
} |
||||
} |
||||
|
||||
|
@ -1,37 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract A { |
||||
/* State variable declaration constant - good */ |
||||
uint constant NUMBER = 100; |
||||
/* State variable declaration private - good */ |
||||
uint private count = 100; |
||||
/* State variable declaration non-constant non-private - good */ |
||||
uint maxnum = 999; |
||||
|
||||
function foo() { |
||||
/* State variable uses - good */ |
||||
uint i = NUMBER + count + maxnum; |
||||
} |
||||
} |
||||
|
||||
contract B { |
||||
/* State variable declaration constant - bad */ |
||||
uint constant number = 100; |
||||
/* State variable declaration private - bad */ |
||||
uint private Count = 100; |
||||
/* State variable declaration non-constant non-private - good */ |
||||
uint Maxnum = 999; |
||||
function foo() { |
||||
/* State variable uses - bad */ |
||||
uint i = number + Count + Maxnum; |
||||
Count += i; |
||||
} |
||||
} |
||||
|
||||
contract C is B { |
||||
function foo() { |
||||
/* State variable uses - bad */ |
||||
uint i = number + Maxnum; |
||||
} |
||||
} |
||||
|
@ -1,58 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
pragma experimental ABIEncoderV2; |
||||
|
||||
contract A { |
||||
|
||||
/* struct definition - bad */ |
||||
struct s { |
||||
uint i; |
||||
} |
||||
|
||||
/* struct declaration - bad */ |
||||
s s1; |
||||
|
||||
function foo() { |
||||
s1.i = 10; |
||||
} |
||||
} |
||||
|
||||
contract B { |
||||
|
||||
/* struct definition - good */ |
||||
struct S { |
||||
uint i; |
||||
} |
||||
|
||||
/* struct definition - good */ |
||||
S s1; |
||||
|
||||
function foo() { |
||||
s1.i = 10; |
||||
} |
||||
|
||||
} |
||||
|
||||
contract C { |
||||
|
||||
/* struct definition - bad */ |
||||
struct s { |
||||
uint i; |
||||
} |
||||
|
||||
/* struct declaration - bad */ |
||||
s s1; |
||||
|
||||
/* struct as parameter and return value - bad */ |
||||
function foo(s sA) returns (s) { |
||||
s1.i = sA.i; |
||||
return (s1); |
||||
} |
||||
} |
||||
|
||||
contract D is C { |
||||
/* struct as parameter and return value - bad */ |
||||
function foo(s sA) returns (s) { |
||||
s1.i = sA.i; |
||||
return (s1); |
||||
} |
||||
} |
@ -1 +0,0 @@ |
||||
pragma solidity ^0.4.23; |
@ -1,5 +0,0 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
import "./pragma.0.4.23.sol"; |
||||
|
||||
contract Test{} |
@ -1 +0,0 @@ |
||||
pragma solidity ^0.5.2; |
@ -1,5 +0,0 @@ |
||||
pragma solidity ^0.5.4; |
||||
|
||||
import "./pragma.0.5.2.sol"; |
||||
|
||||
contract Test{} |
@ -1,5 +0,0 @@ |
||||
// The version pragma below should get flagged by the detector |
||||
pragma solidity ^0.4.23; |
||||
contract Contract{ |
||||
|
||||
} |
@ -1,5 +0,0 @@ |
||||
// The version pragma below should get flagged by the detector |
||||
pragma solidity >=0.4.0 <0.6.0; |
||||
contract Contract{ |
||||
|
||||
} |
@ -1,5 +0,0 @@ |
||||
// The version pragma below should get flagged by the detector |
||||
pragma solidity >=0.4.0 <0.4.25; |
||||
contract Contract{ |
||||
|
||||
} |
@ -1,5 +0,0 @@ |
||||
// The version pragma below should get flagged by the detector |
||||
pragma solidity ^0.5.1; |
||||
contract Contract{ |
||||
|
||||
} |
@ -1,4 +0,0 @@ |
||||
contract C { |
||||
//领 |
||||
uint sv; |
||||
} |
@ -1,13 +0,0 @@ |
||||
//pragma solidity ^0.4.24; |
||||
|
||||
contract A{ |
||||
address unused ; |
||||
address used; |
||||
} |
||||
|
||||
contract B is A{ |
||||
|
||||
function () external{ |
||||
used = address(0); |
||||
} |
||||
} |
@ -1,42 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestDetectorCombinations(unittest.TestCase): |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testDataFile1 = "detector_combinations.sol" |
||||
testFilePath1 = testDataDir+testDataFile1 |
||||
|
||||
def setUp(self): |
||||
outFD1 = open(self.testFilePath1+".out","w") |
||||
errFD1 = open(self.testFilePath1+".err","w") |
||||
p1 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test',self.testFilePath1], stdout=outFD1,stderr=errFD1) |
||||
p1.wait() |
||||
outFD1.close() |
||||
errFD1.close() |
||||
|
||||
def tearDown(self): |
||||
p1 = subprocess.Popen(['rm','-f',self.testFilePath1+'.out',self.testFilePath1+'.err',self.testFilePath1+'.format']) |
||||
p1.wait() |
||||
|
||||
def test_detector_combinations(self): |
||||
errFD1 = open(self.testFilePath1+".err","r") |
||||
errFD1_lines = errFD1.readlines() |
||||
errFD1.close() |
||||
for i in range(len(errFD1_lines)): |
||||
errFD1_lines[i] = errFD1_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath1+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Number of Slither results: 12"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Number of patches: 18"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Overlapping patch won't be applied!"), 3) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:xDetector: unused-state"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:xDetector: constable-states"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:xDetector: naming-convention (state variable declaration)"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (state variable declaration)"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (state variable uses)"), 3) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (parameter declaration)"), 4) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (parameter uses)"), 6) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: external-function"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: constant-function"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: solc-version"), 1) |
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,80 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestExternalFunctions(unittest.TestCase): |
||||
testDataFile1 = "external_function.sol" |
||||
testDataFile2 = "external_function_2.sol" |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testFilePath1 = testDataDir+testDataFile1 |
||||
testFilePath2 = testDataDir+testDataFile2 |
||||
|
||||
def setUp(self): |
||||
outFD1 = open(self.testFilePath1+".out","w") |
||||
errFD1 = open(self.testFilePath1+".err","w") |
||||
p1 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','external-function',self.testFilePath1], stdout=outFD1,stderr=errFD1) |
||||
p1.wait() |
||||
outFD2 = open(self.testFilePath2+".out","w") |
||||
errFD2 = open(self.testFilePath2+".err","w") |
||||
p2 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','external-function',self.testFilePath2], stdout=outFD2,stderr=errFD2) |
||||
p2.wait() |
||||
outFD1.close() |
||||
errFD1.close() |
||||
outFD2.close() |
||||
errFD2.close() |
||||
|
||||
def tearDown(self): |
||||
p1 = subprocess.Popen(['rm','-f',self.testFilePath1+'.out',self.testFilePath1+'.err',self.testFilePath1+'.format']) |
||||
p1.wait() |
||||
p2 = subprocess.Popen(['rm','-f',self.testFilePath2+'.out',self.testFilePath2+'.err',self.testFilePath2+'.format']) |
||||
p2.wait() |
||||
|
||||
def test_external_function(self): |
||||
errFD1 = open(self.testFilePath1+".err","r") |
||||
errFD1_lines = errFD1.readlines() |
||||
for i in range(len(errFD1_lines)): |
||||
errFD1_lines[i] = errFD1_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath1+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD1_lines[0],"INFO:Slither.Format:Number of Slither results: 13") |
||||
self.assertEqual(errFD1_lines[1],"INFO:Slither.Format:Number of patches: 12") |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: external-function"), 12) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: public"), 9) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: external"), 9) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 384"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 390"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 562"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 568"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 642"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 648"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 685"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 691"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 1022"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 1028"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 1305"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 1311"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 2197"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 2203"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 2275"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 2281"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 2315"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 2321"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string:"), 3) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: external"), 3) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 524"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 524"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 1142"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 1142"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 2228"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 2228"), 1) |
||||
errFD1.close() |
||||
|
||||
errFD2 = open(self.testFilePath2+".err","r") |
||||
errFD2_lines = errFD2.readlines() |
||||
for i in range(len(errFD2_lines)): |
||||
errFD2_lines[i] = errFD2_lines[i].strip() |
||||
self.assertFalse(os.path.isfile(self.testFilePath2+".format"),"Patched .format file _is_ created?!") |
||||
self.assertEqual(errFD2_lines[0],"INFO:Slither.Format:Number of Slither results: 0") |
||||
self.assertEqual(errFD2_lines[1],"INFO:Slither.Format:Number of patches: 0") |
||||
errFD2.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,409 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestNamingConvention(unittest.TestCase): |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testDataFile1 = "naming_convention_contract.sol" |
||||
testDataFile2 = "naming_convention_modifier.sol" |
||||
testDataFile3 = "naming_convention_structure.sol" |
||||
testDataFile4 = "naming_convention_enum.sol" |
||||
testDataFile5 = "naming_convention_event.sol" |
||||
testDataFile6 = "naming_convention_function.sol" |
||||
testDataFile7 = "naming_convention_parameter.sol" |
||||
testDataFile8 = "naming_convention_state_variable.sol" |
||||
testFilePath1 = testDataDir+testDataFile1 |
||||
testFilePath2 = testDataDir+testDataFile2 |
||||
testFilePath3 = testDataDir+testDataFile3 |
||||
testFilePath4 = testDataDir+testDataFile4 |
||||
testFilePath5 = testDataDir+testDataFile5 |
||||
testFilePath6 = testDataDir+testDataFile6 |
||||
testFilePath7 = testDataDir+testDataFile7 |
||||
testFilePath8 = testDataDir+testDataFile8 |
||||
|
||||
def setUp(self): |
||||
outFD1 = open(self.testFilePath1+".out","w") |
||||
errFD1 = open(self.testFilePath1+".err","w") |
||||
p1 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath1], stdout=outFD1,stderr=errFD1) |
||||
p1.wait() |
||||
outFD1.close() |
||||
errFD1.close() |
||||
|
||||
outFD2 = open(self.testFilePath2+".out","w") |
||||
errFD2 = open(self.testFilePath2+".err","w") |
||||
p2 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath2], stdout=outFD2,stderr=errFD2) |
||||
p2.wait() |
||||
outFD2.close() |
||||
errFD2.close() |
||||
|
||||
outFD3 = open(self.testFilePath3+".out","w") |
||||
errFD3 = open(self.testFilePath3+".err","w") |
||||
p3 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath3], stdout=outFD3,stderr=errFD3) |
||||
p3.wait() |
||||
outFD3.close() |
||||
errFD3.close() |
||||
|
||||
outFD4 = open(self.testFilePath4+".out","w") |
||||
errFD4 = open(self.testFilePath4+".err","w") |
||||
p4 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath4], stdout=outFD4,stderr=errFD4) |
||||
p4.wait() |
||||
outFD4.close() |
||||
errFD4.close() |
||||
|
||||
outFD5 = open(self.testFilePath5+".out","w") |
||||
errFD5 = open(self.testFilePath5+".err","w") |
||||
p5 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath5], stdout=outFD5,stderr=errFD5) |
||||
p5.wait() |
||||
outFD5.close() |
||||
errFD5.close() |
||||
|
||||
outFD6 = open(self.testFilePath6+".out","w") |
||||
errFD6 = open(self.testFilePath6+".err","w") |
||||
p6 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath6], stdout=outFD6,stderr=errFD6) |
||||
p6.wait() |
||||
outFD6.close() |
||||
errFD6.close() |
||||
|
||||
outFD7 = open(self.testFilePath7+".out","w") |
||||
errFD7 = open(self.testFilePath7+".err","w") |
||||
p7 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath7], stdout=outFD7,stderr=errFD7) |
||||
p7.wait() |
||||
outFD7.close() |
||||
errFD7.close() |
||||
|
||||
outFD8 = open(self.testFilePath8+".out","w") |
||||
errFD8 = open(self.testFilePath8+".err","w") |
||||
p8 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','naming-convention',self.testFilePath8], stdout=outFD8,stderr=errFD8) |
||||
p8.wait() |
||||
outFD8.close() |
||||
errFD8.close() |
||||
|
||||
def tearDown(self): |
||||
p1 = subprocess.Popen(['rm','-f',self.testFilePath1+'.out',self.testFilePath1+'.err',self.testFilePath1+'.format']) |
||||
p1.wait() |
||||
p2 = subprocess.Popen(['rm','-f',self.testFilePath2+'.out',self.testFilePath2+'.err',self.testFilePath2+'.format']) |
||||
p2.wait() |
||||
p3 = subprocess.Popen(['rm','-f',self.testFilePath3+'.out',self.testFilePath3+'.err',self.testFilePath3+'.format']) |
||||
p3.wait() |
||||
p4 = subprocess.Popen(['rm','-f',self.testFilePath4+'.out',self.testFilePath4+'.err',self.testFilePath4+'.format']) |
||||
p4.wait() |
||||
p5 = subprocess.Popen(['rm','-f',self.testFilePath5+'.out',self.testFilePath5+'.err',self.testFilePath5+'.format']) |
||||
p5.wait() |
||||
p6 = subprocess.Popen(['rm','-f',self.testFilePath6+'.out',self.testFilePath6+'.err',self.testFilePath6+'.format']) |
||||
p6.wait() |
||||
p7 = subprocess.Popen(['rm','-f',self.testFilePath7+'.out',self.testFilePath7+'.err',self.testFilePath7+'.format']) |
||||
p7.wait() |
||||
p8 = subprocess.Popen(['rm','-f',self.testFilePath8+'.out',self.testFilePath8+'.err',self.testFilePath8+'.format']) |
||||
p8.wait() |
||||
|
||||
def test_naming_convention_contract(self): |
||||
errFD1 = open(self.testFilePath1+".err","r") |
||||
errFD1_lines = errFD1.readlines() |
||||
errFD1.close() |
||||
for i in range(len(errFD1_lines)): |
||||
errFD1_lines[i] = errFD1_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath1+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD1_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD1_lines[1],"INFO:Slither.Format:Number of patches: 10") |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (contract definition)"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (contract state variable)"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (contract function variable)"), 5) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: naming-convention (contract new object)"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: contract one"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: contract One"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 53"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 65"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: three k"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: Three k"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 117"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 124"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: three l"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: Three l"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 206"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 213"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: one m"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: One m"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 343"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 348"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: one n"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: One n"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 423"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 428"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: contract three"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: contract Three"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 498"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 512"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: one"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: One"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 646"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 649"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: one r"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: One r"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 773"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 779"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: one q"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: One q"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 871"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 876"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: new one()"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: new One()"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 781"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 788"), 1) |
||||
|
||||
def test_naming_convention_modifier(self): |
||||
errFD2 = open(self.testFilePath2+".err","r") |
||||
errFD2_lines = errFD2.readlines() |
||||
errFD2.close() |
||||
for i in range(len(errFD2_lines)): |
||||
errFD2_lines[i] = errFD2_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath2+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD2_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD2_lines[1],"INFO:Slither.Format:Number of patches: 5") |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Detector: naming-convention (modifier definition)"), 2) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Detector: naming-convention (modifier uses)"), 3) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: modifier One"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string: modifier one"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 215"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 227"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: () One"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string: () one"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 288"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 295"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: modifier Two"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string: modifier two"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 423"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 435"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: () one Two returns"), 2) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string: () one two returns"), 2) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 503"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 522"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 718"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 737"), 1) |
||||
|
||||
def test_naming_convention_structure(self): |
||||
errFD3 = open(self.testFilePath3+".err","r") |
||||
errFD3_lines = errFD3.readlines() |
||||
errFD3.close() |
||||
for i in range(len(errFD3_lines)): |
||||
errFD3_lines[i] = errFD3_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath3+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD3_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD3_lines[1],"INFO:Slither.Format:Number of patches: 8") |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Detector: naming-convention (struct definition)"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Detector: naming-convention (struct use)"), 6) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Old string: struct s { uint i; }"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:New string: struct S { uint i; }"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 108"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 134"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 434"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 460"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Old string: s s1"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:New string: S s1"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 171"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 175"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 497"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 501"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Old string: s sA"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:New string: S sA"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 570"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 574"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 715"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 719"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Old string: s"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:New string: S"), 2) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 585"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 586"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 730"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 731"), 1) |
||||
|
||||
def test_naming_convention_enum(self): |
||||
errFD4 = open(self.testFilePath4+".err","r") |
||||
errFD4_lines = errFD4.readlines() |
||||
errFD4.close() |
||||
for i in range(len(errFD4_lines)): |
||||
errFD4_lines[i] = errFD4_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath4+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD4_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD4_lines[1],"INFO:Slither.Format:Number of patches: 11") |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Detector: naming-convention (enum definition)"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Detector: naming-convention (enum use)"), 9) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: enum e {ONE, TWO}"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: enum E {ONE, TWO}"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 73"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 90"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 426"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 443"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: e e1"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: E e1"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 125"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 129"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 478"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 482"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: e eA"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: E eA"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 549"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 553"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 690"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 694"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: e e2 = eA"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: E e2 = eA"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 573"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 582"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 714"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 723"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: e.ONE"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: E.ONE"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 186"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 192"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: e"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: E"), 2) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 564"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 565"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 705"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 706"), 1) |
||||
|
||||
def test_naming_convention_event(self): |
||||
errFD5 = open(self.testFilePath5+".err","r") |
||||
errFD5_lines = errFD5.readlines() |
||||
errFD5.close() |
||||
for i in range(len(errFD5_lines)): |
||||
errFD5_lines[i] = errFD5_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath5+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD5_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD5_lines[1],"INFO:Slither.Format:Number of patches: 5") |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Detector: naming-convention (event definition)"), 2) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Detector: naming-convention (event calls)"), 3) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Old string: event e(uint);"), 2) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:New string: event E(uint);"), 2) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location start: 75"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location end: 89"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location start: 148"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location end: 152"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Old string: e(i)"), 3) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:New string: E(i)"), 3) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location start: 148"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location end: 152"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location start: 438"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location end: 442"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location start: 550"), 1) |
||||
self.assertEqual(errFD5_lines.count("INFO:Slither.Format:Location end: 554"), 1) |
||||
|
||||
def test_naming_convention_function(self): |
||||
errFD6 = open(self.testFilePath6+".err","r") |
||||
errFD6_lines = errFD6.readlines() |
||||
errFD6.close() |
||||
for i in range(len(errFD6_lines)): |
||||
errFD6_lines[i] = errFD6_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath6+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD6_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD6_lines[1],"INFO:Slither.Format:Number of patches: 4") |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Detector: naming-convention (function definition)"), 2) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Detector: naming-convention (function calls)"), 2) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Old string: function Foo"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:New string: function foo"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location start: 76"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location end: 88"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Old string: function Foobar"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:New string: function foobar"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location start: 189"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location end: 204"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Old string: Foobar"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:New string: foobar"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location start: 136"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location end: 142"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Old string: a.Foobar(10)"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:New string: a.foobar(10)"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location start: 516"), 1) |
||||
self.assertEqual(errFD6_lines.count("INFO:Slither.Format:Location end: 528"), 1) |
||||
|
||||
def test_naming_convention_parameter(self): |
||||
errFD7 = open(self.testFilePath7+".err","r") |
||||
errFD7_lines = errFD7.readlines() |
||||
errFD7.close() |
||||
for i in range(len(errFD7_lines)): |
||||
errFD7_lines[i] = errFD7_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath7+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD7_lines[0],"INFO:Slither.Format:Number of Slither results: 6") |
||||
self.assertEqual(errFD7_lines[1],"INFO:Slither.Format:Number of patches: 12") |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Detector: naming-convention (parameter declaration)"), 6) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Detector: naming-convention (parameter uses)"), 6) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: uint Count"), 3) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: uint _Count"), 3) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 91"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 101"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 215"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 225"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: Count"), 3) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: _Count"), 3) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 148"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 153"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 308"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 313"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 489"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 499"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 580"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 585"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: Count)"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: _Count)"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 506"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 512"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: uint Number"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: uint _Number"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 227"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 238"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: Number"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: _Number"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 314"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 320"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: address _to"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: address _To"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 708"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 719"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: address _from"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: address _From"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 721"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 734"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: _to"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: _To"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location start: 811"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Location end: 814"), 1) |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:Old string: _from"), 1, "Index variables of writes are not captured by node._expression_vars_read of Slither") |
||||
self.assertEqual(errFD7_lines.count("INFO:Slither.Format:New string: _From"), 1) |
||||
|
||||
def test_naming_convention_state_variable(self): |
||||
errFD8 = open(self.testFilePath8+".err","r") |
||||
errFD8_lines = errFD8.readlines() |
||||
errFD8.close() |
||||
for i in range(len(errFD8_lines)): |
||||
errFD8_lines[i] = errFD8_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath8+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD8_lines[0],"INFO:Slither.Format:Number of Slither results: 3") |
||||
self.assertEqual(errFD8_lines[1],"INFO:Slither.Format:Number of patches: 9") |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Detector: naming-convention (state variable declaration)"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Detector: naming-convention (state variable uses)"), 6) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Old string: number"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:New string: NUMBER"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 469"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 475"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 716"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 722"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 850"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 856"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Old string: Count"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:New string: count"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 547"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 552"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 725"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 730"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 745"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 750"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Old string: Maxnum"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:New string: maxnum"), 3) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 634"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 640"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 733"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 739"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location start: 859"), 1) |
||||
self.assertEqual(errFD8_lines.count("INFO:Slither.Format:Location end: 865"), 1) |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,71 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestPragma(unittest.TestCase): |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testDataFile1 = "pragma.0.4.24.sol" |
||||
testImportFile1 = "pragma.0.4.23.sol" |
||||
testFilePath1 = testDataDir+testDataFile1 |
||||
testImportFilePath1 = testDataDir+testImportFile1 |
||||
testDataFile2 = "pragma.0.5.4.sol" |
||||
testImportFile2 = "pragma.0.5.2.sol" |
||||
testFilePath2 = testDataDir+testDataFile2 |
||||
testImportFilePath2 = testDataDir+testImportFile2 |
||||
|
||||
def setUp(self): |
||||
outFD1 = open(self.testFilePath1+".out","w") |
||||
errFD1 = open(self.testFilePath1+".err","w") |
||||
p1 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','pragma',self.testFilePath1], stdout=outFD1,stderr=errFD1) |
||||
p1.wait() |
||||
outFD1.close() |
||||
errFD1.close() |
||||
|
||||
outFD2 = open(self.testFilePath2+".out","w") |
||||
errFD2 = open(self.testFilePath2+".err","w") |
||||
my_env = os.environ.copy() |
||||
my_env["SOLC_VERSION"] = "0.5.4" |
||||
p2 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','pragma',self.testFilePath2], stdout=outFD2,stderr=errFD2, env=my_env) |
||||
p2.wait() |
||||
outFD2.close() |
||||
errFD2.close() |
||||
|
||||
def tearDown(self): |
||||
p1 = subprocess.Popen(['rm','-f',self.testFilePath1+'.out',self.testFilePath1+'.err',self.testFilePath1+'.format',self.testImportFilePath1+'.format']) |
||||
p1.wait() |
||||
|
||||
p2 = subprocess.Popen(['rm','-f',self.testFilePath2+'.out',self.testFilePath2+'.err',self.testFilePath2+'.format',self.testImportFilePath2+'.format']) |
||||
p2.wait() |
||||
|
||||
def test_pragma(self): |
||||
errFD1 = open(self.testFilePath1+".err","r") |
||||
errFD1_lines = errFD1.readlines() |
||||
for i in range(len(errFD1_lines)): |
||||
errFD1_lines[i] = errFD1_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath1+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD1_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD1_lines[1],"INFO:Slither.Format:Number of patches: 2") |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: pragma"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: pragma solidity ^0.4.23;"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: pragma solidity ^0.4.24;"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: pragma solidity 0.4.25;"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 0"), 2) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 24"), 2) |
||||
errFD1.close() |
||||
|
||||
errFD2 = open(self.testFilePath2+".err","r") |
||||
errFD2_lines = errFD2.readlines() |
||||
for i in range(len(errFD2_lines)): |
||||
errFD2_lines[i] = errFD2_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath2+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD2_lines[0],"INFO:Slither.Format:Number of Slither results: 2") |
||||
self.assertEqual(errFD2_lines[1],"INFO:Slither.Format:Number of patches: 2") |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Detector: pragma"), 2) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: pragma solidity ^0.5.4;"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: pragma solidity ^0.5.2;"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string: pragma solidity 0.5.3;"), 2) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 0"), 2) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 23"), 2) |
||||
errFD2.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,116 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestSolcVersion(unittest.TestCase): |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testDataFile1 = "solc_version_incorrect1.sol" |
||||
testFilePath1 = testDataDir+testDataFile1 |
||||
testDataFile2 = "solc_version_incorrect2.sol" |
||||
testFilePath2 = testDataDir+testDataFile2 |
||||
testDataFile3 = "solc_version_incorrect3.sol" |
||||
testFilePath3 = testDataDir+testDataFile3 |
||||
testDataFile4 = "solc_version_incorrect4.sol" |
||||
testFilePath4 = testDataDir+testDataFile4 |
||||
|
||||
def setUp(self): |
||||
outFD1 = open(self.testFilePath1+".out","w") |
||||
errFD1 = open(self.testFilePath1+".err","w") |
||||
p1 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','solc-version',self.testFilePath1], stdout=outFD1,stderr=errFD1) |
||||
p1.wait() |
||||
outFD1.close() |
||||
errFD1.close() |
||||
|
||||
outFD2 = open(self.testFilePath2+".out","w") |
||||
errFD2 = open(self.testFilePath2+".err","w") |
||||
p2 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','solc-version',self.testFilePath2], stdout=outFD2,stderr=errFD2) |
||||
p2.wait() |
||||
outFD2.close() |
||||
errFD2.close() |
||||
|
||||
outFD3 = open(self.testFilePath3+".out","w") |
||||
errFD3 = open(self.testFilePath3+".err","w") |
||||
my_env = os.environ.copy() |
||||
my_env["SOLC_VERSION"] = "0.4.24" |
||||
p3 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','solc-version',self.testFilePath3], stdout=outFD3,stderr=errFD3, env=my_env) |
||||
p3.wait() |
||||
outFD3.close() |
||||
errFD3.close() |
||||
|
||||
outFD4 = open(self.testFilePath4+".out","w") |
||||
errFD4 = open(self.testFilePath4+".err","w") |
||||
my_env = os.environ.copy() |
||||
my_env["SOLC_VERSION"] = "0.5.2" |
||||
p4 = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','solc-version',self.testFilePath4], stdout=outFD4,stderr=errFD4, env=my_env) |
||||
p4.wait() |
||||
outFD4.close() |
||||
errFD4.close() |
||||
|
||||
def tearDown(self): |
||||
p1 = subprocess.Popen(['rm','-f',self.testFilePath1+'.out',self.testFilePath1+'.err',self.testFilePath1+'.format']) |
||||
p1.wait() |
||||
p2 = subprocess.Popen(['rm','-f',self.testFilePath2+'.out',self.testFilePath2+'.err',self.testFilePath2+'.format']) |
||||
p2.wait() |
||||
p3 = subprocess.Popen(['rm','-f',self.testFilePath3+'.out',self.testFilePath3+'.err',self.testFilePath3+'.format']) |
||||
p3.wait() |
||||
p4 = subprocess.Popen(['rm','-f',self.testFilePath4+'.out',self.testFilePath4+'.err',self.testFilePath4+'.format']) |
||||
p4.wait() |
||||
|
||||
def test_solc_version(self): |
||||
errFD1 = open(self.testFilePath1+".err","r") |
||||
errFD1_lines = errFD1.readlines() |
||||
for i in range(len(errFD1_lines)): |
||||
errFD1_lines[i] = errFD1_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath1+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD1_lines[0],"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD1_lines[1],"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Detector: solc-version"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Old string: pragma solidity ^0.4.23;"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:New string: pragma solidity 0.4.25;"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location start: 63"), 1) |
||||
self.assertEqual(errFD1_lines.count("INFO:Slither.Format:Location end: 87"), 1) |
||||
errFD1.close() |
||||
|
||||
errFD2 = open(self.testFilePath2+".err","r") |
||||
errFD2_lines = errFD2.readlines() |
||||
for i in range(len(errFD2_lines)): |
||||
errFD2_lines[i] = errFD2_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath2+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD2_lines[0],"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD2_lines[1],"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Detector: solc-version"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Old string: pragma solidity >=0.4.0 <0.6.0;"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:New string: pragma solidity 0.5.3;"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location start: 63"), 1) |
||||
self.assertEqual(errFD2_lines.count("INFO:Slither.Format:Location end: 94"), 1) |
||||
errFD2.close() |
||||
|
||||
errFD3 = open(self.testFilePath3+".err","r") |
||||
errFD3_lines = errFD3.readlines() |
||||
for i in range(len(errFD3_lines)): |
||||
errFD3_lines[i] = errFD3_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath3+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD3_lines[0],"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD3_lines[1],"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Detector: solc-version"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Old string: pragma solidity >=0.4.0 <0.4.25;"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:New string: pragma solidity 0.4.25;"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location start: 63"), 1) |
||||
self.assertEqual(errFD3_lines.count("INFO:Slither.Format:Location end: 95"), 1) |
||||
errFD3.close() |
||||
|
||||
errFD4 = open(self.testFilePath4+".err","r") |
||||
errFD4_lines = errFD4.readlines() |
||||
for i in range(len(errFD4_lines)): |
||||
errFD4_lines[i] = errFD4_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath4+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD4_lines[0],"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD4_lines[1],"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Detector: solc-version"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Old string: pragma solidity ^0.5.1;"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:New string: pragma solidity 0.5.3;"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location start: 63"), 1) |
||||
self.assertEqual(errFD4_lines.count("INFO:Slither.Format:Location end: 86"), 1) |
||||
errFD4.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,37 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestUnicode(unittest.TestCase): |
||||
testDataFile = "unicode.sol" |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testFilePath = testDataDir+testDataFile |
||||
|
||||
def setUp(self): |
||||
outFD = open(self.testFilePath+".out","w") |
||||
errFD = open(self.testFilePath+".err","w") |
||||
p = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test',self.testFilePath], stdout=outFD,stderr=errFD) |
||||
p.wait() |
||||
outFD.close() |
||||
errFD.close() |
||||
|
||||
def tearDown(self): |
||||
p = subprocess.Popen(['rm','-f',self.testFilePath+'.out',self.testFilePath+'.err',self.testFilePath+'.format']) |
||||
p.wait() |
||||
|
||||
def test_constable_states(self): |
||||
errFD = open(self.testFilePath+".err","r") |
||||
errFD_lines = errFD.readlines() |
||||
for i in range(len(errFD_lines)): |
||||
errFD_lines[i] = errFD_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD_lines[0].rstrip(),"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD_lines[1].rstrip(),"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Detector: constable-states"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: uint sv"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string: uint constant sv"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 23"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 30"), 1) |
||||
errFD.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
@ -1,37 +0,0 @@ |
||||
import unittest |
||||
import subprocess, os, sys |
||||
|
||||
class TestUnusedStateVars(unittest.TestCase): |
||||
testDataFile = "unused_state.sol" |
||||
testDataDir = "./slither_format/tests/test_data/" |
||||
testFilePath = testDataDir+testDataFile |
||||
|
||||
def setUp(self): |
||||
outFD = open(self.testFilePath+".out","w") |
||||
errFD = open(self.testFilePath+".err","w") |
||||
p = subprocess.Popen(['python3', '-m', 'slither_format','--verbose-test','--detect','unused-state',self.testFilePath], stdout=outFD,stderr=errFD) |
||||
p.wait() |
||||
outFD.close() |
||||
errFD.close() |
||||
|
||||
def tearDown(self): |
||||
p = subprocess.Popen(['rm','-f',self.testFilePath+'.out',self.testFilePath+'.err',self.testFilePath+'.format']) |
||||
p.wait() |
||||
|
||||
def test_unused_state_vars(self): |
||||
errFD = open(self.testFilePath+".err","r") |
||||
errFD_lines = errFD.readlines() |
||||
for i in range(len(errFD_lines)): |
||||
errFD_lines[i] = errFD_lines[i].strip() |
||||
self.assertTrue(os.path.isfile(self.testFilePath+".format"),"Patched .format file is not created?!") |
||||
self.assertEqual(errFD_lines[0].rstrip(),"INFO:Slither.Format:Number of Slither results: 1") |
||||
self.assertEqual(errFD_lines[1].rstrip(),"INFO:Slither.Format:Number of patches: 1") |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Detector: unused-state"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Old string: address unused ;"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:New string:"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location start: 44"), 1) |
||||
self.assertEqual(errFD_lines.count("INFO:Slither.Format:Location end: 63"), 1) |
||||
errFD.close() |
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
Loading…
Reference in new issue