mirror of
https://github.com/status-im/gitpivot.git
synced 2026-08-30 10:01:12 +00:00
135 lines
3.9 KiB
Solidity
135 lines
3.9 KiB
Solidity
pragma solidity ^0.4.17;
|
|
|
|
import "./ERC223.sol";
|
|
import "./MiniMeToken.sol";
|
|
import "./TokenReceiver.sol";
|
|
|
|
|
|
/**
|
|
* @title TokenLedger
|
|
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
|
* Abstract contract for tracking token deposits.
|
|
* Token transfers that did not approved and called `receiveApproval` can be tracked by updateInternalBalance
|
|
**/
|
|
contract TokenLedger is TokenReceiver, ApproveAndCallFallBack {
|
|
|
|
event Withdrawn(address indexed token, address indexed reciever, uint value);
|
|
event Deposited(address indexed token, address indexed sender, uint value, bytes data);
|
|
event Transfer(address indexed token, address indexed sender, address indexed receiver, uint value);
|
|
mapping (address => mapping (address => uint)) public deposits;
|
|
mapping (address => uint) public tokenBalances;
|
|
|
|
address[] public tokens;
|
|
|
|
uint public nonce;
|
|
|
|
/**
|
|
* @notice watches for balance in a token contract
|
|
* @param _token the token contract address
|
|
**/
|
|
function updateInternalBalance(address _token)
|
|
public
|
|
returns (uint newBal)
|
|
{
|
|
uint oldBal = tokenBalances[_token];
|
|
newBal = ERC20(_token).balanceOf(this);
|
|
require(newBal != oldBal);
|
|
if (newBal > oldBal) {
|
|
register(_token, address(this), newBal - oldBal, new bytes(0));
|
|
} else {
|
|
tokenBalances[_token] = newBal;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice ERC23 Token fallback
|
|
* @param _from address incoming token
|
|
* @param _amount incoming amount
|
|
**/
|
|
function tokenFallback(address _from, uint _amount, bytes _data)
|
|
public
|
|
returns (bool)
|
|
{
|
|
register(msg.sender, _from, _amount, _data);
|
|
}
|
|
|
|
/**
|
|
* @notice Called MiniMeToken approvesAndCall to this contract, calls deposit.
|
|
* @param _from address incoming token
|
|
* @param _amount incoming amount
|
|
* @param _token the token contract address
|
|
* @param _data (might be used by child classes)
|
|
*/
|
|
function receiveApproval(
|
|
address _from,
|
|
uint256 _amount,
|
|
address _token,
|
|
bytes _data
|
|
)
|
|
public
|
|
{
|
|
uint _nonce = nonce;
|
|
ERC20 token = ERC20(_token);
|
|
if (!token.transferFrom(_from, this, _amount)) {
|
|
revert();
|
|
}
|
|
if (nonce == _nonce) { //ERC23 not executed _deposited tokenFallback by
|
|
register(_token, _from, _amount, _data);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @dev register the deposit in a internal balance (for child contract use)
|
|
**/
|
|
function register(
|
|
address _token,
|
|
address _sender,
|
|
uint _amount,
|
|
bytes _data
|
|
)
|
|
internal
|
|
{
|
|
require(_token != 0x0);
|
|
Deposited(_token, _sender, _amount, _data);
|
|
nonce++;
|
|
if (tokenBalances[_token] == 0) {
|
|
tokens.push(_token);
|
|
tokenBalances[_token] = ERC20(_token).balanceOf(this);
|
|
} else {
|
|
tokenBalances[_token] += _amount;
|
|
}
|
|
deposits[_token][_sender] += _amount;
|
|
}
|
|
|
|
/**
|
|
* @dev transfers the internal deposit balance of `_from` to `_to`
|
|
*/
|
|
function transfer(address _token, address _from, address _to, uint _amount)
|
|
internal
|
|
{
|
|
require(deposits[_token][_from] >= _amount);
|
|
Transfer(_token, _from, _to, _amount);
|
|
deposits[_token][_from] -= _amount;
|
|
deposits[_token][_to] += _amount;
|
|
}
|
|
|
|
/**
|
|
* @dev withdraw token amount to dest
|
|
**/
|
|
function withdraw(address _token, address _dest, uint _amount, address _consumer)
|
|
internal
|
|
returns (bool)
|
|
{
|
|
require(tokenBalances[_token] >= _amount);
|
|
if (_consumer != 0x0) {
|
|
require(deposits[_token][_consumer] >= _amount);
|
|
deposits[_token][_consumer] -= _amount;
|
|
}
|
|
Withdrawn(_token, _dest, _amount);
|
|
tokenBalances[_token] -= _amount;
|
|
return ERC20(_token).transfer(_dest, _amount);
|
|
}
|
|
|
|
}
|