Add SB Curated (copied from the smartbugs repository).

This commit is contained in:
Joao F. Ferreira
2022-11-23 09:07:09 +00:00
parent 03da27c72a
commit 254a3b20c1
156 changed files with 17228 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 54
*/
pragma solidity ^0.4.19;
contract PERSONAL_BANK
{
mapping (address=>uint256) public balances;
uint public MinSum = 1 ether;
LogFile Log = LogFile(0x0486cF65A2F2F3A392CBEa398AFB7F5f0B72FF46);
bool intitalized;
function SetMinSum(uint _val)
public
{
if(intitalized)revert();
MinSum = _val;
}
function SetLogFile(address _log)
public
{
if(intitalized)revert();
Log = LogFile(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Deposit()
public
payable
{
balances[msg.sender]+= msg.value;
Log.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
if(balances[msg.sender]>=MinSum && balances[msg.sender]>=_am)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
Log.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Deposit();
}
}
contract LogFile
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,74 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 38
*/
pragma solidity ^0.4.19;
contract PrivateBank
{
mapping (address => uint) public balances;
uint public MinDeposit = 1 ether;
Log TransferLog;
function PrivateBank(address _log)
{
TransferLog = Log(_log);
}
function Deposit()
public
payable
{
if(msg.value >= MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am)
{
if(_am<=balances[msg.sender])
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,97 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 55
*/
pragma solidity ^0.4.19;
contract ACCURAL_DEPOSIT
{
mapping (address=>uint256) public balances;
uint public MinSum = 1 ether;
LogFile Log = LogFile(0x0486cF65A2F2F3A392CBEa398AFB7F5f0B72FF46);
bool intitalized;
function SetMinSum(uint _val)
public
{
if(intitalized)revert();
MinSum = _val;
}
function SetLogFile(address _log)
public
{
if(intitalized)revert();
Log = LogFile(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Deposit()
public
payable
{
balances[msg.sender]+= msg.value;
Log.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
if(balances[msg.sender]>=MinSum && balances[msg.sender]>=_am)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
Log.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Deposit();
}
}
contract LogFile
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,96 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 54
*/
pragma solidity ^0.4.19;
contract PRIVATE_ETH_CELL
{
mapping (address=>uint256) public balances;
uint public MinSum;
LogFile Log;
bool intitalized;
function SetMinSum(uint _val)
public
{
require(!intitalized);
MinSum = _val;
}
function SetLogFile(address _log)
public
{
require(!intitalized);
Log = LogFile(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Deposit()
public
payable
{
balances[msg.sender]+= msg.value;
Log.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
if(balances[msg.sender]>=MinSum && balances[msg.sender]>=_am)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
Log.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Deposit();
}
}
contract LogFile
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,96 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 54
*/
pragma solidity ^0.4.19;
contract BANK_SAFE
{
mapping (address=>uint256) public balances;
uint public MinSum;
LogFile Log;
bool intitalized;
function SetMinSum(uint _val)
public
{
if(intitalized)throw;
MinSum = _val;
}
function SetLogFile(address _log)
public
{
if(intitalized)throw;
Log = LogFile(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Deposit()
public
payable
{
balances[msg.sender]+= msg.value;
Log.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
if(balances[msg.sender]>=MinSum && balances[msg.sender]>=_am)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
Log.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Deposit();
}
}
contract LogFile
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,100 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 94
*/
pragma solidity ^0.4.19;
contract Ownable
{
address newOwner;
address owner = msg.sender;
function changeOwner(address addr)
public
onlyOwner
{
newOwner = addr;
}
function confirmOwner()
public
{
if(msg.sender==newOwner)
{
owner=newOwner;
}
}
modifier onlyOwner
{
if(owner == msg.sender)_;
}
}
contract Token is Ownable
{
address owner = msg.sender;
function WithdrawToken(address token, uint256 amount,address to)
public
onlyOwner
{
token.call(bytes4(sha3("transfer(address,uint256)")),to,amount);
}
}
contract TokenBank is Token
{
uint public MinDeposit;
mapping (address => uint) public Holders;
///Constructor
function initTokenBank()
public
{
owner = msg.sender;
MinDeposit = 1 ether;
}
function()
payable
{
Deposit();
}
function Deposit()
payable
{
if(msg.value>MinDeposit)
{
Holders[msg.sender]+=msg.value;
}
}
function WitdrawTokenToHolder(address _to,address _token,uint _amount)
public
onlyOwner
{
if(Holders[_to]>0)
{
Holders[_to]=0;
WithdrawToken(_token,_amount,_to);
}
}
function WithdrawToHolder(address _addr, uint _wei)
public
onlyOwner
payable
{
if(Holders[_addr]>0)
{
// <yes> <report> REENTRANCY
if(_addr.call.value(_wei)())
{
Holders[_addr]-=_wei;
}
}
}
}

View File

@@ -0,0 +1,85 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 29
*/
pragma solidity ^0.4.25;
contract U_BANK
{
function Put(uint _unlockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
acc.unlockTime = _unlockTime>now?_unlockTime:now;
LogFile.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
LogFile.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
Log LogFile;
uint public MinSum = 2 ether;
function U_BANK(address log) public{
LogFile = Log(log);
}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,88 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 52
*/
pragma solidity ^0.4.19;
contract PrivateDeposit
{
mapping (address => uint) public balances;
uint public MinDeposit = 1 ether;
address public owner;
Log TransferLog;
modifier onlyOwner() {
require(tx.origin == owner);
_;
}
function PrivateDeposit()
{
owner = msg.sender;
TransferLog = new Log();
}
function setLog(address _lib) onlyOwner
{
TransferLog = Log(_lib);
}
function Deposit()
public
payable
{
if(msg.value >= MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am)
{
if(_am<=balances[msg.sender])
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,85 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 29
*/
pragma solidity ^0.4.25;
contract W_WALLET
{
function Put(uint _unlockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
acc.unlockTime = _unlockTime>now?_unlockTime:now;
LogFile.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
LogFile.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
Log LogFile;
uint public MinSum = 1 ether;
function W_WALLET(address log) public{
LogFile = Log(log);
}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,77 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 41
*/
pragma solidity ^0.4.19;
contract ETH_VAULT
{
mapping (address => uint) public balances;
Log TransferLog;
uint public MinDeposit = 1 ether;
function ETH_VAULT(address _log)
public
{
TransferLog = Log(_log);
}
function Deposit()
public
payable
{
if(msg.value > MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am)
public
payable
{
if(_am<=balances[msg.sender])
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,85 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 29
*/
pragma solidity ^0.4.25;
contract X_WALLET
{
function Put(uint _unlockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
acc.unlockTime = _unlockTime>now?_unlockTime:now;
LogFile.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
LogFile.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
Log LogFile;
uint public MinSum = 1 ether;
function X_WALLET(address log) public{
LogFile = Log(log);
}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,80 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 44
*/
pragma solidity ^0.4.19;
contract ETH_FUND
{
mapping (address => uint) public balances;
uint public MinDeposit = 1 ether;
Log TransferLog;
uint lastBlock;
function ETH_FUND(address _log)
public
{
TransferLog = Log(_log);
}
function Deposit()
public
payable
{
if(msg.value > MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
lastBlock = block.number;
}
}
function CashOut(uint _am)
public
payable
{
if(_am<=balances[msg.sender]&&block.number>lastBlock)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,104 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 63
*/
pragma solidity ^0.4.19;
contract PENNY_BY_PENNY
{
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
uint public MinSum;
LogFile Log;
bool intitalized;
function SetMinSum(uint _val)
public
{
if(intitalized)throw;
MinSum = _val;
}
function SetLogFile(address _log)
public
{
if(intitalized)throw;
Log = LogFile(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Put(uint _lockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
if(now+_lockTime>acc.unlockTime)acc.unlockTime=now+_lockTime;
Log.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
Log.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
}
contract LogFile
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,95 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 54
*/
pragma solidity ^0.4.19;
contract DEP_BANK
{
mapping (address=>uint256) public balances;
uint public MinSum;
LogFile Log;
bool intitalized;
function SetMinSum(uint _val)
public
{
if(intitalized)throw;
MinSum = _val;
}
function SetLogFile(address _log)
public
{
if(intitalized)throw;
Log = LogFile(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Deposit()
public
payable
{
balances[msg.sender]+= msg.value;
Log.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
if(balances[msg.sender]>=MinSum && balances[msg.sender]>=_am)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
Log.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Deposit();
}
}
contract LogFile
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,76 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 40
*/
pragma solidity ^0.4.19;
contract Private_Bank
{
mapping (address => uint) public balances;
uint public MinDeposit = 1 ether;
Log TransferLog;
function Private_Bank(address _log)
{
TransferLog = Log(_log);
}
function Deposit()
public
payable
{
if(msg.value > MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am)
public
payable
{
if(_am<=balances[msg.sender])
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,74 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 38
*/
pragma solidity ^0.4.19;
contract PrivateBank
{
mapping (address => uint) public balances;
uint public MinDeposit = 1 ether;
Log TransferLog;
function PrivateBank(address _lib)
{
TransferLog = Log(_lib);
}
function Deposit()
public
payable
{
if(msg.value >= MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am)
{
if(_am<=balances[msg.sender])
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,77 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 41
*/
pragma solidity ^0.4.19;
contract ETH_VAULT
{
mapping (address => uint) public balances;
uint public MinDeposit = 1 ether;
Log TransferLog;
function ETH_VAULT(address _log)
public
{
TransferLog = Log(_log);
}
function Deposit()
public
payable
{
if(msg.value > MinDeposit)
{
balances[msg.sender]+=msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am)
public
payable
{
if(_am<=balances[msg.sender])
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,104 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 63
*/
pragma solidity ^0.4.19;
contract MONEY_BOX
{
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
uint public MinSum;
Log LogFile;
bool intitalized;
function SetMinSum(uint _val)
public
{
if(intitalized)throw;
MinSum = _val;
}
function SetLogFile(address _log)
public
{
if(intitalized)throw;
LogFile = Log(_log);
}
function Initialized()
public
{
intitalized = true;
}
function Put(uint _lockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
if(now+_lockTime>acc.unlockTime)acc.unlockTime=now+_lockTime;
LogFile.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
LogFile.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,85 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 29
*/
pragma solidity ^0.4.25;
contract WALLET
{
function Put(uint _unlockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
acc.unlockTime = _unlockTime>now?_unlockTime:now;
LogFile.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
LogFile.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
Log LogFile;
uint public MinSum = 1 ether;
function WALLET(address log) public{
LogFile = Log(log);
}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

View File

@@ -0,0 +1,85 @@
/*
* @source: etherscan.io
* @author: -
* @vulnerable_at_lines: 29
*/
pragma solidity ^0.4.25;
contract MY_BANK
{
function Put(uint _unlockTime)
public
payable
{
var acc = Acc[msg.sender];
acc.balance += msg.value;
acc.unlockTime = _unlockTime>now?_unlockTime:now;
LogFile.AddMessage(msg.sender,msg.value,"Put");
}
function Collect(uint _am)
public
payable
{
var acc = Acc[msg.sender];
if( acc.balance>=MinSum && acc.balance>=_am && now>acc.unlockTime)
{
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_am)())
{
acc.balance-=_am;
LogFile.AddMessage(msg.sender,_am,"Collect");
}
}
}
function()
public
payable
{
Put(0);
}
struct Holder
{
uint unlockTime;
uint balance;
}
mapping (address => Holder) public Acc;
Log LogFile;
uint public MinSum = 1 ether;
function MY_BANK(address log) public{
LogFile = Log(log);
}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

26
dataset/reentrancy/README.md Executable file
View File

@@ -0,0 +1,26 @@
# Reentrancy
Also known as or related to race to empty, recursive call vulnerability, call to the unknown.
The Reentrancy attack, probably the most famous Ethereum vulnerability,surprised everyone when discovered for the first time. It was first unveiled during a multimillion dollar heist which led to a hard fork of Ethereum. Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract or the use of a low level function with an external address.
Loss: estimated at 3.5M ETH (~50M USD at the time)
## Attack Scenario
A smart contract tracks the balance of a number of external addresses and allows users to retrieve funds with its public withdraw() function.
A malicious smart contract uses the withdraw() function to retrieve its entire balance.
The victim contract executes the call.value(amount)() low level function to send the ether to the malicious contract before updating the balance of the malicious contract.
The malicious contract has a payable fallback() function that accepts the funds and then calls back into the victim contract's withdraw() function.
This second execution triggers a transfer of funds: remember, the balance of the malicious contract still hasn't been updated from the first withdrawal. As a result, the malicious contract successfully withdraws its entire balance a second time.
## Examples
The following function contains a function vulnerable to a reentrancy attack. When the low level call() function sends ether to the msg.sender address, it becomes vulnerable; if the address is a smart contract, the payment will trigger its fallback function with what's left of the transaction gas:
```
function withdraw(uint _amount) {
require(balances[msg.sender] >= _amount);
msg.sender.call.value(_amount)();
balances[msg.sender] -= _amount;
}
````
## References
Taken from [DASP TOP10](https://dasp.co/)

View File

@@ -0,0 +1,24 @@
/*
* @source: https://github.com/seresistvanandras/EthBench/blob/master/Benchmark/Simple/reentrant.sol
* @author: -
* @vulnerable_at_lines: 21
*/
pragma solidity ^0.4.0;
contract EtherBank{
mapping (address => uint) userBalances;
function getBalance(address user) constant returns(uint) {
return userBalances[user];
}
function addToBalance() {
userBalances[msg.sender] += msg.value;
}
function withdrawBalance() {
uint amountToWithdraw = userBalances[msg.sender];
// <yes> <report> REENTRANCY
if (!(msg.sender.call.value(amountToWithdraw)())) { throw; }
userBalances[msg.sender] = 0;
}
}

View File

@@ -0,0 +1,31 @@
/*
* @source: https://github.com/sigp/solidity-security-blog
* @author: Suhabe Bugrara
* @vulnerable_at_lines: 27
*/
//added pragma version
pragma solidity ^0.4.0;
contract EtherStore {
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;
function depositFunds() public payable {
balances[msg.sender] += msg.value;
}
function withdrawFunds (uint256 _weiToWithdraw) public {
require(balances[msg.sender] >= _weiToWithdraw);
// limit the withdrawal
require(_weiToWithdraw <= withdrawalLimit);
// limit the time allowed to withdraw
require(now >= lastWithdrawTime[msg.sender] + 1 weeks);
// <yes> <report> REENTRANCY
require(msg.sender.call.value(_weiToWithdraw)());
balances[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = now;
}
}

View File

@@ -0,0 +1,49 @@
/*
* @source: https://github.com/SmartContractSecurity/SWC-registry/blob/master/test_cases/reentracy/modifier_reentrancy.sol
* @author: -
* @vulnerable_at_lines: 15
*/
pragma solidity ^0.4.24;
contract ModifierEntrancy {
mapping (address => uint) public tokenBalance;
string constant name = "Nu Token";
//If a contract has a zero balance and supports the token give them some token
// <yes> <report> REENTRANCY
function airDrop() hasNoBalance supportsToken public{
tokenBalance[msg.sender] += 20;
}
//Checks that the contract responds the way we want
modifier supportsToken() {
require(keccak256(abi.encodePacked("Nu Token")) == Bank(msg.sender).supportsToken());
_;
}
//Checks that the caller has a zero balance
modifier hasNoBalance {
require(tokenBalance[msg.sender] == 0);
_;
}
}
contract Bank{
function supportsToken() external pure returns(bytes32){
return(keccak256(abi.encodePacked("Nu Token")));
}
}
contract attack{ //An example of a contract that breaks the contract above.
bool hasBeenCalled;
function supportsToken() external returns(bytes32){
if(!hasBeenCalled){
hasBeenCalled = true;
ModifierEntrancy(msg.sender).airDrop();
}
return(keccak256(abi.encodePacked("Nu Token")));
}
function call(address token) public{
ModifierEntrancy(token).airDrop();
}
}

View File

@@ -0,0 +1,32 @@
/*
* @source: https://ethernaut.zeppelin.solutions/level/0xf70706db003e94cfe4b5e27ffd891d5c81b39488
* @author: Alejandro Santander
* @vulnerable_at_lines: 24
*/
pragma solidity ^0.4.18;
contract Reentrance {
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] += msg.value;
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
// <yes> <report> REENTRANCY
if(msg.sender.call.value(_amount)()) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
function() public payable {}
}

View File

@@ -0,0 +1,31 @@
/*
* @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/
* @author: consensys
* @vulnerable_at_lines: 28
*/
pragma solidity ^0.4.0;
contract Reentrancy_bonus{
// INSECURE
mapping (address => uint) private userBalances;
mapping (address => bool) private claimedBonus;
mapping (address => uint) private rewardsForA;
function withdrawReward(address recipient) public {
uint amountToWithdraw = rewardsForA[recipient];
rewardsForA[recipient] = 0;
(bool success, ) = recipient.call.value(amountToWithdraw)("");
require(success);
}
function getFirstWithdrawalBonus(address recipient) public {
require(!claimedBonus[recipient]); // Each recipient should only be able to claim the bonus once
rewardsForA[recipient] += 100;
// <yes> <report> REENTRANCY
withdrawReward(recipient); // At this point, the caller will be able to execute getFirstWithdrawalBonus again.
claimedBonus[recipient] = true;
}
}

View File

@@ -0,0 +1,28 @@
/*
* @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/
* @author: consensys
* @vulnerable_at_lines: 24
*/
pragma solidity ^0.4.0;
contract Reentrancy_cross_function {
// INSECURE
mapping (address => uint) private userBalances;
function transfer(address to, uint amount) {
if (userBalances[msg.sender] >= amount) {
userBalances[to] += amount;
userBalances[msg.sender] -= amount;
}
}
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
// <yes> <report> REENTRANCY
(bool success, ) = msg.sender.call.value(amountToWithdraw)(""); // At this point, the caller's code is executed, and can call transfer()
require(success);
userBalances[msg.sender] = 0;
}
}

View File

@@ -0,0 +1,28 @@
/*
* @source: https://github.com/ConsenSys/evm-analyzer-benchmark-suite
* @author: Suhabe Bugrara
* @vulnerable_at_lines: 18
*/
pragma solidity ^0.4.19;
contract ReentrancyDAO {
mapping (address => uint) credit;
uint balance;
function withdrawAll() public {
uint oCredit = credit[msg.sender];
if (oCredit > 0) {
balance -= oCredit;
// <yes> <report> REENTRANCY
bool callResult = msg.sender.call.value(oCredit)();
require (callResult);
credit[msg.sender] = 0;
}
}
function deposit() public payable {
credit[msg.sender] += msg.value;
balance += msg.value;
}
}

View File

@@ -0,0 +1,21 @@
/*
* @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/
* @author: consensys
* @vulnerable_at_lines: 17
*/
pragma solidity ^0.4.0;
contract Reentrancy_insecure {
// INSECURE
mapping (address => uint) private userBalances;
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
// <yes> <report> REENTRANCY
(bool success, ) = msg.sender.call.value(amountToWithdraw)(""); // At this point, the caller's code is executed, and can call withdrawBalance again
require(success);
userBalances[msg.sender] = 0;
}
}

View File

@@ -0,0 +1,29 @@
/*
* @source: https://github.com/trailofbits/not-so-smart-contracts/blob/master/reentrancy/Reentrancy.sol
* @author: -
* @vulnerable_at_lines: 24
*/
pragma solidity ^0.4.15;
contract Reentrance {
mapping (address => uint) userBalance;
function getBalance(address u) constant returns(uint){
return userBalance[u];
}
function addToBalance() payable{
userBalance[msg.sender] += msg.value;
}
function withdrawBalance(){
// send userBalance[msg.sender] ethers to msg.sender
// if mgs.sender is a contract, it will call its fallback function
// <yes> <report> REENTRANCY
if( ! (msg.sender.call.value(userBalance[msg.sender])() ) ){
throw;
}
userBalance[msg.sender] = 0;
}
}

View File

@@ -0,0 +1,27 @@
/*
* @source: http://blockchain.unica.it/projects/ethereum-survey/attacks.html#simpledao
* @author: -
* @vulnerable_at_lines: 19
*/
pragma solidity ^0.4.2;
contract SimpleDAO {
mapping (address => uint) public credit;
function donate(address to) payable {
credit[to] += msg.value;
}
function withdraw(uint amount) {
if (credit[msg.sender]>= amount) {
// <yes> <report> REENTRANCY
bool res = msg.sender.call.value(amount)();
credit[msg.sender]-=amount;
}
}
function queryCredit(address to) returns (uint){
return credit[to];
}
}

View File

@@ -0,0 +1,896 @@
/*
* @source: https://github.com/trailofbits/not-so-smart-contracts/blob/master/reentrancy/SpankChain_source_code/SpankChain_Payment.sol
* @author: -
* @vulnerable_at_lines: 426,430
*/
// https://etherscan.io/address/0xf91546835f756da0c10cfa0cda95b15577b84aa7#code
pragma solidity ^0.4.23;
// produced by the Solididy File Flattener (c) David Appleton 2018
// contact : dave@akomba.com
// released under Apache 2.0 licence
contract Token {
/* This is a slight change to the ERC20 base standard.
function totalSupply() constant returns (uint256 supply);
is replaced with:
uint256 public totalSupply;
This automatically creates a getter function for the totalSupply.
This is moved to the base contract since public getter functions are not
currently recognised as an implementation of the matching abstract
function by the compiler.
*/
/// total amount of tokens
uint256 public totalSupply;
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) public constant returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _value) public returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint256 _value) public returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) public constant returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
library ECTools {
// @dev Recovers the address which has signed a message
// @thanks https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
function recoverSigner(bytes32 _hashedMsg, string _sig) public pure returns (address) {
require(_hashedMsg != 0x00);
// need this for test RPC
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, _hashedMsg));
if (bytes(_sig).length != 132) {
return 0x0;
}
bytes32 r;
bytes32 s;
uint8 v;
bytes memory sig = hexstrToBytes(substring(_sig, 2, 132));
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
if (v < 27) {
v += 27;
}
if (v < 27 || v > 28) {
return 0x0;
}
return ecrecover(prefixedHash, v, r, s);
}
// @dev Verifies if the message is signed by an address
function isSignedBy(bytes32 _hashedMsg, string _sig, address _addr) public pure returns (bool) {
require(_addr != 0x0);
return _addr == recoverSigner(_hashedMsg, _sig);
}
// @dev Converts an hexstring to bytes
function hexstrToBytes(string _hexstr) public pure returns (bytes) {
uint len = bytes(_hexstr).length;
require(len % 2 == 0);
bytes memory bstr = bytes(new string(len / 2));
uint k = 0;
string memory s;
string memory r;
for (uint i = 0; i < len; i += 2) {
s = substring(_hexstr, i, i + 1);
r = substring(_hexstr, i + 1, i + 2);
uint p = parseInt16Char(s) * 16 + parseInt16Char(r);
bstr[k++] = uintToBytes32(p)[31];
}
return bstr;
}
// @dev Parses a hexchar, like 'a', and returns its hex value, in this case 10
function parseInt16Char(string _char) public pure returns (uint) {
bytes memory bresult = bytes(_char);
// bool decimals = false;
if ((bresult[0] >= 48) && (bresult[0] <= 57)) {
return uint(bresult[0]) - 48;
} else if ((bresult[0] >= 65) && (bresult[0] <= 70)) {
return uint(bresult[0]) - 55;
} else if ((bresult[0] >= 97) && (bresult[0] <= 102)) {
return uint(bresult[0]) - 87;
} else {
revert();
}
}
// @dev Converts a uint to a bytes32
// @thanks https://ethereum.stackexchange.com/questions/4170/how-to-convert-a-uint-to-bytes-in-solidity
function uintToBytes32(uint _uint) public pure returns (bytes b) {
b = new bytes(32);
assembly {mstore(add(b, 32), _uint)}
}
// @dev Hashes the signed message
// @ref https://github.com/ethereum/go-ethereum/issues/3731#issuecomment-293866868
function toEthereumSignedMessage(string _msg) public pure returns (bytes32) {
uint len = bytes(_msg).length;
require(len > 0);
bytes memory prefix = "\x19Ethereum Signed Message:\n";
return keccak256(abi.encodePacked(prefix, uintToString(len), _msg));
}
// @dev Converts a uint in a string
function uintToString(uint _uint) public pure returns (string str) {
uint len = 0;
uint m = _uint + 0;
while (m != 0) {
len++;
m /= 10;
}
bytes memory b = new bytes(len);
uint i = len - 1;
while (_uint != 0) {
uint remainder = _uint % 10;
_uint = _uint / 10;
b[i--] = byte(48 + remainder);
}
str = string(b);
}
// @dev extract a substring
// @thanks https://ethereum.stackexchange.com/questions/31457/substring-in-solidity
function substring(string _str, uint _startIndex, uint _endIndex) public pure returns (string) {
bytes memory strBytes = bytes(_str);
require(_startIndex <= _endIndex);
require(_startIndex >= 0);
require(_endIndex <= strBytes.length);
bytes memory result = new bytes(_endIndex - _startIndex);
for (uint i = _startIndex; i < _endIndex; i++) {
result[i - _startIndex] = strBytes[i];
}
return string(result);
}
}
contract StandardToken is Token {
function transfer(address _to, uint256 _value) public returns (bool success) {
//Default assumes totalSupply can't be over max (2^256 - 1).
//If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
//Replace the if with this one instead.
//require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
//same as above. Replace this line with the following if you want to protect against wrapping uints.
//require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]);
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
function balanceOf(address _owner) public constant returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
}
contract HumanStandardToken is StandardToken {
/* Public variables of the token */
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name; //fancy name: eg Simon Bucks
uint8 public decimals; //How many decimals to show. ie. There could 1000 base units with 3 decimals. Meaning 0.980 SBX = 980 base units. It's like comparing 1 wei to 1 ether.
string public symbol; //An identifier: eg SBX
string public version = 'H0.1'; //human 0.1 standard. Just an arbitrary versioning scheme.
constructor(
uint256 _initialAmount,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol
) public {
balances[msg.sender] = _initialAmount; // Give the creator all initial tokens
totalSupply = _initialAmount; // Update total supply
name = _tokenName; // Set the name for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
}
/* Approves and then calls the receiving contract */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
//call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
require(_spender.call(bytes4(bytes32(keccak256("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData));
return true;
}
}
contract LedgerChannel {
string public constant NAME = "Ledger Channel";
string public constant VERSION = "0.0.1";
uint256 public numChannels = 0;
event DidLCOpen (
bytes32 indexed channelId,
address indexed partyA,
address indexed partyI,
uint256 ethBalanceA,
address token,
uint256 tokenBalanceA,
uint256 LCopenTimeout
);
event DidLCJoin (
bytes32 indexed channelId,
uint256 ethBalanceI,
uint256 tokenBalanceI
);
event DidLCDeposit (
bytes32 indexed channelId,
address indexed recipient,
uint256 deposit,
bool isToken
);
event DidLCUpdateState (
bytes32 indexed channelId,
uint256 sequence,
uint256 numOpenVc,
uint256 ethBalanceA,
uint256 tokenBalanceA,
uint256 ethBalanceI,
uint256 tokenBalanceI,
bytes32 vcRoot,
uint256 updateLCtimeout
);
event DidLCClose (
bytes32 indexed channelId,
uint256 sequence,
uint256 ethBalanceA,
uint256 tokenBalanceA,
uint256 ethBalanceI,
uint256 tokenBalanceI
);
event DidVCInit (
bytes32 indexed lcId,
bytes32 indexed vcId,
bytes proof,
uint256 sequence,
address partyA,
address partyB,
uint256 balanceA,
uint256 balanceB
);
event DidVCSettle (
bytes32 indexed lcId,
bytes32 indexed vcId,
uint256 updateSeq,
uint256 updateBalA,
uint256 updateBalB,
address challenger,
uint256 updateVCtimeout
);
event DidVCClose(
bytes32 indexed lcId,
bytes32 indexed vcId,
uint256 balanceA,
uint256 balanceB
);
struct Channel {
//TODO: figure out if it's better just to split arrays by balances/deposits instead of eth/erc20
address[2] partyAddresses; // 0: partyA 1: partyI
uint256[4] ethBalances; // 0: balanceA 1:balanceI 2:depositedA 3:depositedI
uint256[4] erc20Balances; // 0: balanceA 1:balanceI 2:depositedA 3:depositedI
uint256[2] initialDeposit; // 0: eth 1: tokens
uint256 sequence;
uint256 confirmTime;
bytes32 VCrootHash;
uint256 LCopenTimeout;
uint256 updateLCtimeout; // when update LC times out
bool isOpen; // true when both parties have joined
bool isUpdateLCSettling;
uint256 numOpenVC;
HumanStandardToken token;
}
// virtual-channel state
struct VirtualChannel {
bool isClose;
bool isInSettlementState;
uint256 sequence;
address challenger; // Initiator of challenge
uint256 updateVCtimeout; // when update VC times out
// channel state
address partyA; // VC participant A
address partyB; // VC participant B
address partyI; // LC hub
uint256[2] ethBalances;
uint256[2] erc20Balances;
uint256[2] bond;
HumanStandardToken token;
}
mapping(bytes32 => VirtualChannel) public virtualChannels;
mapping(bytes32 => Channel) public Channels;
function createChannel(
bytes32 _lcID,
address _partyI,
uint256 _confirmTime,
address _token,
uint256[2] _balances // [eth, token]
)
public
payable
{
require(Channels[_lcID].partyAddresses[0] == address(0), "Channel has already been created.");
require(_partyI != 0x0, "No partyI address provided to LC creation");
require(_balances[0] >= 0 && _balances[1] >= 0, "Balances cannot be negative");
// Set initial ledger channel state
// Alice must execute this and we assume the initial state
// to be signed from this requirement
// Alternative is to check a sig as in joinChannel
Channels[_lcID].partyAddresses[0] = msg.sender;
Channels[_lcID].partyAddresses[1] = _partyI;
if(_balances[0] != 0) {
require(msg.value == _balances[0], "Eth balance does not match sent value");
Channels[_lcID].ethBalances[0] = msg.value;
}
if(_balances[1] != 0) {
Channels[_lcID].token = HumanStandardToken(_token);
require(Channels[_lcID].token.transferFrom(msg.sender, this, _balances[1]),"CreateChannel: token transfer failure");
Channels[_lcID].erc20Balances[0] = _balances[1];
}
Channels[_lcID].sequence = 0;
Channels[_lcID].confirmTime = _confirmTime;
// is close flag, lc state sequence, number open vc, vc root hash, partyA...
//Channels[_lcID].stateHash = keccak256(uint256(0), uint256(0), uint256(0), bytes32(0x0), bytes32(msg.sender), bytes32(_partyI), balanceA, balanceI);
Channels[_lcID].LCopenTimeout = now + _confirmTime;
Channels[_lcID].initialDeposit = _balances;
emit DidLCOpen(_lcID, msg.sender, _partyI, _balances[0], _token, _balances[1], Channels[_lcID].LCopenTimeout);
}
function LCOpenTimeout(bytes32 _lcID) public {
require(msg.sender == Channels[_lcID].partyAddresses[0] && Channels[_lcID].isOpen == false);
require(now > Channels[_lcID].LCopenTimeout);
if(Channels[_lcID].initialDeposit[0] != 0) {
// <yes> <report> REENTRANCY
Channels[_lcID].partyAddresses[0].transfer(Channels[_lcID].ethBalances[0]);
}
if(Channels[_lcID].initialDeposit[1] != 0) {
// <yes> <report> REENTRANCY
require(Channels[_lcID].token.transfer(Channels[_lcID].partyAddresses[0], Channels[_lcID].erc20Balances[0]),"CreateChannel: token transfer failure");
}
emit DidLCClose(_lcID, 0, Channels[_lcID].ethBalances[0], Channels[_lcID].erc20Balances[0], 0, 0);
// only safe to delete since no action was taken on this channel
delete Channels[_lcID];
}
function joinChannel(bytes32 _lcID, uint256[2] _balances) public payable {
// require the channel is not open yet
require(Channels[_lcID].isOpen == false);
require(msg.sender == Channels[_lcID].partyAddresses[1]);
if(_balances[0] != 0) {
require(msg.value == _balances[0], "state balance does not match sent value");
Channels[_lcID].ethBalances[1] = msg.value;
}
if(_balances[1] != 0) {
require(Channels[_lcID].token.transferFrom(msg.sender, this, _balances[1]),"joinChannel: token transfer failure");
Channels[_lcID].erc20Balances[1] = _balances[1];
}
Channels[_lcID].initialDeposit[0]+=_balances[0];
Channels[_lcID].initialDeposit[1]+=_balances[1];
// no longer allow joining functions to be called
Channels[_lcID].isOpen = true;
numChannels++;
emit DidLCJoin(_lcID, _balances[0], _balances[1]);
}
// additive updates of monetary state
// TODO check this for attack vectors
function deposit(bytes32 _lcID, address recipient, uint256 _balance, bool isToken) public payable {
require(Channels[_lcID].isOpen == true, "Tried adding funds to a closed channel");
require(recipient == Channels[_lcID].partyAddresses[0] || recipient == Channels[_lcID].partyAddresses[1]);
//if(Channels[_lcID].token)
if (Channels[_lcID].partyAddresses[0] == recipient) {
if(isToken) {
require(Channels[_lcID].token.transferFrom(msg.sender, this, _balance),"deposit: token transfer failure");
Channels[_lcID].erc20Balances[2] += _balance;
} else {
require(msg.value == _balance, "state balance does not match sent value");
Channels[_lcID].ethBalances[2] += msg.value;
}
}
if (Channels[_lcID].partyAddresses[1] == recipient) {
if(isToken) {
require(Channels[_lcID].token.transferFrom(msg.sender, this, _balance),"deposit: token transfer failure");
Channels[_lcID].erc20Balances[3] += _balance;
} else {
require(msg.value == _balance, "state balance does not match sent value");
Channels[_lcID].ethBalances[3] += msg.value;
}
}
emit DidLCDeposit(_lcID, recipient, _balance, isToken);
}
// TODO: Check there are no open virtual channels, the client should have cought this before signing a close LC state update
function consensusCloseChannel(
bytes32 _lcID,
uint256 _sequence,
uint256[4] _balances, // 0: ethBalanceA 1:ethBalanceI 2:tokenBalanceA 3:tokenBalanceI
string _sigA,
string _sigI
)
public
{
// assume num open vc is 0 and root hash is 0x0
//require(Channels[_lcID].sequence < _sequence);
require(Channels[_lcID].isOpen == true);
uint256 totalEthDeposit = Channels[_lcID].initialDeposit[0] + Channels[_lcID].ethBalances[2] + Channels[_lcID].ethBalances[3];
uint256 totalTokenDeposit = Channels[_lcID].initialDeposit[1] + Channels[_lcID].erc20Balances[2] + Channels[_lcID].erc20Balances[3];
require(totalEthDeposit == _balances[0] + _balances[1]);
require(totalTokenDeposit == _balances[2] + _balances[3]);
bytes32 _state = keccak256(
abi.encodePacked(
_lcID,
true,
_sequence,
uint256(0),
bytes32(0x0),
Channels[_lcID].partyAddresses[0],
Channels[_lcID].partyAddresses[1],
_balances[0],
_balances[1],
_balances[2],
_balances[3]
)
);
require(Channels[_lcID].partyAddresses[0] == ECTools.recoverSigner(_state, _sigA));
require(Channels[_lcID].partyAddresses[1] == ECTools.recoverSigner(_state, _sigI));
Channels[_lcID].isOpen = false;
if(_balances[0] != 0 || _balances[1] != 0) {
Channels[_lcID].partyAddresses[0].transfer(_balances[0]);
Channels[_lcID].partyAddresses[1].transfer(_balances[1]);
}
if(_balances[2] != 0 || _balances[3] != 0) {
require(Channels[_lcID].token.transfer(Channels[_lcID].partyAddresses[0], _balances[2]),"happyCloseChannel: token transfer failure");
require(Channels[_lcID].token.transfer(Channels[_lcID].partyAddresses[1], _balances[3]),"happyCloseChannel: token transfer failure");
}
numChannels--;
emit DidLCClose(_lcID, _sequence, _balances[0], _balances[1], _balances[2], _balances[3]);
}
// Byzantine functions
function updateLCstate(
bytes32 _lcID,
uint256[6] updateParams, // [sequence, numOpenVc, ethbalanceA, ethbalanceI, tokenbalanceA, tokenbalanceI]
bytes32 _VCroot,
string _sigA,
string _sigI
)
public
{
Channel storage channel = Channels[_lcID];
require(channel.isOpen);
require(channel.sequence < updateParams[0]); // do same as vc sequence check
require(channel.ethBalances[0] + channel.ethBalances[1] >= updateParams[2] + updateParams[3]);
require(channel.erc20Balances[0] + channel.erc20Balances[1] >= updateParams[4] + updateParams[5]);
if(channel.isUpdateLCSettling == true) {
require(channel.updateLCtimeout > now);
}
bytes32 _state = keccak256(
abi.encodePacked(
_lcID,
false,
updateParams[0],
updateParams[1],
_VCroot,
channel.partyAddresses[0],
channel.partyAddresses[1],
updateParams[2],
updateParams[3],
updateParams[4],
updateParams[5]
)
);
require(channel.partyAddresses[0] == ECTools.recoverSigner(_state, _sigA));
require(channel.partyAddresses[1] == ECTools.recoverSigner(_state, _sigI));
// update LC state
channel.sequence = updateParams[0];
channel.numOpenVC = updateParams[1];
channel.ethBalances[0] = updateParams[2];
channel.ethBalances[1] = updateParams[3];
channel.erc20Balances[0] = updateParams[4];
channel.erc20Balances[1] = updateParams[5];
channel.VCrootHash = _VCroot;
channel.isUpdateLCSettling = true;
channel.updateLCtimeout = now + channel.confirmTime;
// make settlement flag
emit DidLCUpdateState (
_lcID,
updateParams[0],
updateParams[1],
updateParams[2],
updateParams[3],
updateParams[4],
updateParams[5],
_VCroot,
channel.updateLCtimeout
);
}
// supply initial state of VC to "prime" the force push game
function initVCstate(
bytes32 _lcID,
bytes32 _vcID,
bytes _proof,
address _partyA,
address _partyB,
uint256[2] _bond,
uint256[4] _balances, // 0: ethBalanceA 1:ethBalanceI 2:tokenBalanceA 3:tokenBalanceI
string sigA
)
public
{
require(Channels[_lcID].isOpen, "LC is closed.");
// sub-channel must be open
require(!virtualChannels[_vcID].isClose, "VC is closed.");
// Check time has passed on updateLCtimeout and has not passed the time to store a vc state
require(Channels[_lcID].updateLCtimeout < now, "LC timeout not over.");
// prevent rentry of initializing vc state
require(virtualChannels[_vcID].updateVCtimeout == 0);
// partyB is now Ingrid
bytes32 _initState = keccak256(
abi.encodePacked(_vcID, uint256(0), _partyA, _partyB, _bond[0], _bond[1], _balances[0], _balances[1], _balances[2], _balances[3])
);
// Make sure Alice has signed initial vc state (A/B in oldState)
require(_partyA == ECTools.recoverSigner(_initState, sigA));
// Check the oldState is in the root hash
require(_isContained(_initState, _proof, Channels[_lcID].VCrootHash) == true);
virtualChannels[_vcID].partyA = _partyA; // VC participant A
virtualChannels[_vcID].partyB = _partyB; // VC participant B
virtualChannels[_vcID].sequence = uint256(0);
virtualChannels[_vcID].ethBalances[0] = _balances[0];
virtualChannels[_vcID].ethBalances[1] = _balances[1];
virtualChannels[_vcID].erc20Balances[0] = _balances[2];
virtualChannels[_vcID].erc20Balances[1] = _balances[3];
virtualChannels[_vcID].bond = _bond;
virtualChannels[_vcID].updateVCtimeout = now + Channels[_lcID].confirmTime;
virtualChannels[_vcID].isInSettlementState = true;
emit DidVCInit(_lcID, _vcID, _proof, uint256(0), _partyA, _partyB, _balances[0], _balances[1]);
}
//TODO: verify state transition since the hub did not agree to this state
// make sure the A/B balances are not beyond ingrids bonds
// Params: vc init state, vc final balance, vcID
function settleVC(
bytes32 _lcID,
bytes32 _vcID,
uint256 updateSeq,
address _partyA,
address _partyB,
uint256[4] updateBal, // [ethupdateBalA, ethupdateBalB, tokenupdateBalA, tokenupdateBalB]
string sigA
)
public
{
require(Channels[_lcID].isOpen, "LC is closed.");
// sub-channel must be open
require(!virtualChannels[_vcID].isClose, "VC is closed.");
require(virtualChannels[_vcID].sequence < updateSeq, "VC sequence is higher than update sequence.");
require(
virtualChannels[_vcID].ethBalances[1] < updateBal[1] && virtualChannels[_vcID].erc20Balances[1] < updateBal[3],
"State updates may only increase recipient balance."
);
require(
virtualChannels[_vcID].bond[0] == updateBal[0] + updateBal[1] &&
virtualChannels[_vcID].bond[1] == updateBal[2] + updateBal[3],
"Incorrect balances for bonded amount");
// Check time has passed on updateLCtimeout and has not passed the time to store a vc state
// virtualChannels[_vcID].updateVCtimeout should be 0 on uninitialized vc state, and this should
// fail if initVC() isn't called first
// require(Channels[_lcID].updateLCtimeout < now && now < virtualChannels[_vcID].updateVCtimeout);
require(Channels[_lcID].updateLCtimeout < now); // for testing!
bytes32 _updateState = keccak256(
abi.encodePacked(
_vcID,
updateSeq,
_partyA,
_partyB,
virtualChannels[_vcID].bond[0],
virtualChannels[_vcID].bond[1],
updateBal[0],
updateBal[1],
updateBal[2],
updateBal[3]
)
);
// Make sure Alice has signed a higher sequence new state
require(virtualChannels[_vcID].partyA == ECTools.recoverSigner(_updateState, sigA));
// store VC data
// we may want to record who is initiating on-chain settles
virtualChannels[_vcID].challenger = msg.sender;
virtualChannels[_vcID].sequence = updateSeq;
// channel state
virtualChannels[_vcID].ethBalances[0] = updateBal[0];
virtualChannels[_vcID].ethBalances[1] = updateBal[1];
virtualChannels[_vcID].erc20Balances[0] = updateBal[2];
virtualChannels[_vcID].erc20Balances[1] = updateBal[3];
virtualChannels[_vcID].updateVCtimeout = now + Channels[_lcID].confirmTime;
emit DidVCSettle(_lcID, _vcID, updateSeq, updateBal[0], updateBal[1], msg.sender, virtualChannels[_vcID].updateVCtimeout);
}
function closeVirtualChannel(bytes32 _lcID, bytes32 _vcID) public {
// require(updateLCtimeout > now)
require(Channels[_lcID].isOpen, "LC is closed.");
require(virtualChannels[_vcID].isInSettlementState, "VC is not in settlement state.");
require(virtualChannels[_vcID].updateVCtimeout < now, "Update vc timeout has not elapsed.");
require(!virtualChannels[_vcID].isClose, "VC is already closed");
// reduce the number of open virtual channels stored on LC
Channels[_lcID].numOpenVC--;
// close vc flags
virtualChannels[_vcID].isClose = true;
// re-introduce the balances back into the LC state from the settled VC
// decide if this lc is alice or bob in the vc
if(virtualChannels[_vcID].partyA == Channels[_lcID].partyAddresses[0]) {
Channels[_lcID].ethBalances[0] += virtualChannels[_vcID].ethBalances[0];
Channels[_lcID].ethBalances[1] += virtualChannels[_vcID].ethBalances[1];
Channels[_lcID].erc20Balances[0] += virtualChannels[_vcID].erc20Balances[0];
Channels[_lcID].erc20Balances[1] += virtualChannels[_vcID].erc20Balances[1];
} else if (virtualChannels[_vcID].partyB == Channels[_lcID].partyAddresses[0]) {
Channels[_lcID].ethBalances[0] += virtualChannels[_vcID].ethBalances[1];
Channels[_lcID].ethBalances[1] += virtualChannels[_vcID].ethBalances[0];
Channels[_lcID].erc20Balances[0] += virtualChannels[_vcID].erc20Balances[1];
Channels[_lcID].erc20Balances[1] += virtualChannels[_vcID].erc20Balances[0];
}
emit DidVCClose(_lcID, _vcID, virtualChannels[_vcID].erc20Balances[0], virtualChannels[_vcID].erc20Balances[1]);
}
// todo: allow ethier lc.end-user to nullify the settled LC state and return to off-chain
function byzantineCloseChannel(bytes32 _lcID) public {
Channel storage channel = Channels[_lcID];
// check settlement flag
require(channel.isOpen, "Channel is not open");
require(channel.isUpdateLCSettling == true);
require(channel.numOpenVC == 0);
require(channel.updateLCtimeout < now, "LC timeout over.");
// if off chain state update didnt reblance deposits, just return to deposit owner
uint256 totalEthDeposit = channel.initialDeposit[0] + channel.ethBalances[2] + channel.ethBalances[3];
uint256 totalTokenDeposit = channel.initialDeposit[1] + channel.erc20Balances[2] + channel.erc20Balances[3];
uint256 possibleTotalEthBeforeDeposit = channel.ethBalances[0] + channel.ethBalances[1];
uint256 possibleTotalTokenBeforeDeposit = channel.erc20Balances[0] + channel.erc20Balances[1];
if(possibleTotalEthBeforeDeposit < totalEthDeposit) {
channel.ethBalances[0]+=channel.ethBalances[2];
channel.ethBalances[1]+=channel.ethBalances[3];
} else {
require(possibleTotalEthBeforeDeposit == totalEthDeposit);
}
if(possibleTotalTokenBeforeDeposit < totalTokenDeposit) {
channel.erc20Balances[0]+=channel.erc20Balances[2];
channel.erc20Balances[1]+=channel.erc20Balances[3];
} else {
require(possibleTotalTokenBeforeDeposit == totalTokenDeposit);
}
// reentrancy
uint256 ethbalanceA = channel.ethBalances[0];
uint256 ethbalanceI = channel.ethBalances[1];
uint256 tokenbalanceA = channel.erc20Balances[0];
uint256 tokenbalanceI = channel.erc20Balances[1];
channel.ethBalances[0] = 0;
channel.ethBalances[1] = 0;
channel.erc20Balances[0] = 0;
channel.erc20Balances[1] = 0;
if(ethbalanceA != 0 || ethbalanceI != 0) {
channel.partyAddresses[0].transfer(ethbalanceA);
channel.partyAddresses[1].transfer(ethbalanceI);
}
if(tokenbalanceA != 0 || tokenbalanceI != 0) {
require(
channel.token.transfer(channel.partyAddresses[0], tokenbalanceA),
"byzantineCloseChannel: token transfer failure"
);
require(
channel.token.transfer(channel.partyAddresses[1], tokenbalanceI),
"byzantineCloseChannel: token transfer failure"
);
}
channel.isOpen = false;
numChannels--;
emit DidLCClose(_lcID, channel.sequence, ethbalanceA, ethbalanceI, tokenbalanceA, tokenbalanceI);
}
function _isContained(bytes32 _hash, bytes _proof, bytes32 _root) internal pure returns (bool) {
bytes32 cursor = _hash;
bytes32 proofElem;
for (uint256 i = 64; i <= _proof.length; i += 32) {
assembly { proofElem := mload(add(_proof, i)) }
if (cursor < proofElem) {
cursor = keccak256(abi.encodePacked(cursor, proofElem));
} else {
cursor = keccak256(abi.encodePacked(proofElem, cursor));
}
}
return cursor == _root;
}
//Struct Getters
function getChannel(bytes32 id) public view returns (
address[2],
uint256[4],
uint256[4],
uint256[2],
uint256,
uint256,
bytes32,
uint256,
uint256,
bool,
bool,
uint256
) {
Channel memory channel = Channels[id];
return (
channel.partyAddresses,
channel.ethBalances,
channel.erc20Balances,
channel.initialDeposit,
channel.sequence,
channel.confirmTime,
channel.VCrootHash,
channel.LCopenTimeout,
channel.updateLCtimeout,
channel.isOpen,
channel.isUpdateLCSettling,
channel.numOpenVC
);
}
function getVirtualChannel(bytes32 id) public view returns(
bool,
bool,
uint256,
address,
uint256,
address,
address,
address,
uint256[2],
uint256[2],
uint256[2]
) {
VirtualChannel memory virtualChannel = virtualChannels[id];
return(
virtualChannel.isClose,
virtualChannel.isInSettlementState,
virtualChannel.sequence,
virtualChannel.challenger,
virtualChannel.updateVCtimeout,
virtualChannel.partyA,
virtualChannel.partyB,
virtualChannel.partyI,
virtualChannel.ethBalances,
virtualChannel.erc20Balances,
virtualChannel.bond
);
}
}