Last active
August 30, 2018 07:15
-
-
Save 3esmit/00b79987e284aec80ad931fc7b9211f9 to your computer and use it in GitHub Desktop.
Example of a ethereum Off chain Multi channel Token Bank ERC23 ERC20 ERC223 MiniMe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "./TokenBank.sol"; | |
pragma solidity ^0.4.9; | |
/** | |
* @title MultiChannel | |
* @author Ricardo Guilherme Schmidt <3esmit> | |
* MultiChannel is a ERC20 and ETH bank that allows multiple offchain transactions. | |
**/ | |
contract MultiChannel is TokenBank { | |
function confirmTransactions(uint8 [] vs, bytes32 [] rs, bytes32 [] ss, address [] tokens, address [] senders, address [] receivers, uint [] values){ | |
uint len = vs.length; | |
for (uint i = 0; i < len; i++){ | |
confirmTransaction(vs[i],rs[i],ss[i],tokens[i],senders[i],receivers[i],values[i]); | |
} | |
} | |
function confirmTransaction(uint8 v, bytes32 r, bytes32 s, address _token, address _sender, address _receiver, uint _value) constant returns (bool){ | |
require(ecrecover(sha3(_token, _receiver, _value), v, r, s) == _sender); //valid signature | |
return withdraw(_token, _receiver, _value, _sender); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ECR23 standard token interface | |
pragma solidity ^0.4.11; | |
contract ERC20 { | |
uint256 public totalSupply; | |
function balanceOf(address who) constant returns (uint256); | |
function allowance(address owner, address spender) constant returns (uint256); | |
function transfer(address to, uint256 value) returns (bool ok); | |
function transferFrom(address from, address to, uint256 value) returns (bool ok); | |
function approve(address spender, uint256 value) returns (bool ok); | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval(address indexed owner, address indexed spender, uint256 value); | |
} | |
contract ApproveAndCallFallBack { | |
function receiveApproval(address from, uint256 _amount, address _token, bytes _data); | |
} | |
contract ERC23Receiver { | |
function tokenFallback(address _from, uint _value, bytes _data); | |
} | |
contract ERC23 is ERC20 { | |
uint256 public decimals; | |
string public name; | |
string public symbol; | |
event Transfer(address indexed from, address indexed to, uint256 value, bytes data); | |
function transfer(address _to, uint _value, bytes _data) returns (bool ok); | |
} | |
contract Token is ERC23 { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "./Token.sol"; | |
pragma solidity ^0.4.11; | |
/** | |
* @title TokenBank | |
* @author Ricardo Guilherme Schmidt <3esmit> | |
* Abstract contract for deposit and withdraw of ETH and ERC20/23 Tokens, with MiniMe token support. | |
**/ | |
contract TokenBank is ERC23Receiver, ApproveAndCallFallBack { | |
event Withdrawn(address token, address reciever, uint amount); | |
event Deposited(address token, address sender, uint value); | |
mapping (address => mapping (address => uint)) public deposits; | |
mapping (address => uint) public tokenBalances; | |
address[] public tokens; | |
uint public nonce; | |
/** | |
* @notice deposit ether in bank | |
* @param _data might be used by child implementations | |
**/ | |
function depositEther(bytes _data) payable { | |
_deposited(msg.sender, msg.value, 0x0, _data); | |
} | |
/** | |
* @notice deposit a ERC20 token. The amount of deposit is the allowance set to this contract. | |
* @param _token the token contract address | |
* @param _data might be used by child implementations | |
**/ | |
function depositToken(address _token, bytes _data){ | |
address sender = msg.sender; | |
uint amount = ERC20(_token).allowance(sender, this); | |
deposit(sender, amount, _token, _data); | |
} | |
/** | |
* @notice deposit a ERC20 token. The amount of deposit is the allowance set to this contract. | |
* @param _token the token contract address | |
* @param _data might be used by child implementations | |
**/ | |
function deposit(address _from, uint256 _amount, address _token, bytes _data) { | |
if(_from == address(this)) return; | |
uint _nonce = nonce; | |
ERC20 token = ERC20(_token); | |
if(!token.transferFrom(_from, this, _amount)) throw; | |
if(nonce == _nonce){ //ERC23 not executed _deposited tokenFallback by | |
_deposited(_from, _amount, _token, _data); | |
} | |
} | |
/** | |
* @notice watches for balance in a token contract | |
* @param _tokenAddr the token contract address | |
**/ | |
function watch(address _tokenAddr) { | |
uint oldBal = tokenBalances[_tokenAddr]; | |
uint newBal = ERC20(_tokenAddr).balanceOf(this); | |
if(newBal > oldBal){ | |
_deposited(0x0,newBal-oldBal,_tokenAddr,new bytes(0)); | |
} | |
} | |
/** | |
* @notice refunds a deposit. | |
* @param _token the token you want to refund | |
**/ | |
function refund(address _token) returns (bool) { | |
address _sender = msg.sender; | |
withdraw(_token, _sender, deposits[_sender][_token], _sender); | |
return true; | |
} | |
/** | |
* @notice ERC23 Token fallback | |
* @param _from address incoming token | |
* @param _amount incoming amount | |
**/ | |
function tokenFallback(address _from, uint _amount, bytes _data) { | |
_deposited(_from, _amount, msg.sender, _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){ | |
deposit(_from, _amount, _token, _data); | |
} | |
/** | |
* @dev register the deposit to refundings | |
**/ | |
function _deposited(address _sender, uint _amount, address _tokenAddr, bytes _data) | |
internal { | |
Deposited(_tokenAddr, _sender, _amount); | |
nonce++; | |
if(_tokenAddr != 0x0){ | |
if(tokenBalances[_tokenAddr] == 0){ | |
tokens.push(_tokenAddr); | |
tokenBalances[_tokenAddr] = ERC20(_tokenAddr).balanceOf(this); | |
}else{ | |
tokenBalances[_tokenAddr] += _amount; | |
} | |
} | |
deposits[_sender][_tokenAddr] += _amount; | |
} | |
/** | |
* @dev withdraw token amount to dest | |
**/ | |
function withdraw(address _tokenAddr, address _dest, uint _amount, address _consumer) | |
internal returns (bool){ | |
Withdrawn(_tokenAddr, _dest, _amount); | |
if(_consumer != 0x0) { | |
require(deposits[_consumer][_tokenAddr] >= _amount); | |
deposits[_consumer][_tokenAddr] -= _amount; | |
} | |
if(_tokenAddr == 0x0){ | |
_dest.transfer(_amount); | |
return true; | |
} else { | |
tokenBalances[_tokenAddr] -= _amount; | |
ERC20 token = ERC20(_tokenAddr); | |
token.approve(this, 0); | |
if(token.approve(this, _amount)){ | |
return token.transferFrom(this, _dest, _amount); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment