DCIPs/assets/eip-5528/EscrowContractAccount.sol

172 lines
5.5 KiB
Solidity

pragma solidity ^0.4.24;
import "./ERC20Mockup.sol";
contract ErcEscrowAccount {
struct BalanceData {
uint256 seller;
uint256 buyer;
}
enum State { Inited, Running, Success, Failed }
struct EscrowStatus {
uint256 numberOfBuyer;
uint256 fundTotal;
uint256 fundFilled;
State state;
}
mapping(address => BalanceData) _balances;
address _addrSeller;
address _addrBuyer;
address _addrEscrow;
address _addrCreator;
EscrowStatus _status;
constructor(uint256 fundAmount, address sellerContract, address buyerContract) {
//require(sellerContract.code.length > 0, "seller is not contract");
//require(buyerContract.code.length > 0, "buyer is not contract");
_addrBuyer = buyerContract;
_addrSeller = sellerContract;
_status.numberOfBuyer = 0;
_status.fundTotal = fundAmount;
_status.fundFilled = 0;
_addrEscrow = address(this);
_addrCreator = msg.sender;
_status.state = State.Inited;
}
function helper_bigInt256(uint256 _u256Val) public view returns (uint256) {
return _u256Val;
}
function helper_numberOfBuyers() public view returns (uint256) {
return _status.numberOfBuyer;
}
function _updateRunningState() {
if(_status.state == State.Running){
if(_status.numberOfBuyer == 2){
_status.state = State.Success;
}
}
}
function escrowStatus() public view returns (string) {
if(_status.state == State.Inited){
return "init";
}else if(_status.state == State.Running){
return "Running";
}else if(_status.state == State.Success){
return "Success";
}else if(_status.state == State.Failed){
return "Failed";
}
return "unknown state";
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account].buyer;
}
function escrowBalanceOf(address account) public view returns (uint256 o_buyer, uint256 o_seller) {
o_buyer = _balances[account].buyer;
o_seller = _balances[account].seller;
}
function escrowFund(address to, uint256 amount) public returns (bool) {
require(amount > 0, "amount is too small");
if(msg.sender == _addrSeller){
require(_status.state == State.Inited, "must be init state");
require(to == _addrCreator, "to is only with creator");
require(amount == _status.fundTotal, "amount must be total fund");
require(_status.fundFilled == 0, "fund filled must be zero");
_status.fundFilled = amount;
_balances[to].seller = _balances[to].seller + amount;
_balances[to].buyer = 0;
_status.state = State.Running;
}else if(msg.sender == _addrBuyer){
require(_status.state == State.Running, "must be running state");
require(_status.fundTotal > 0, "escrow might be not started or already finished");
require(_status.fundFilled == _status.fundTotal, "fund does not filled yet");
// TODO: this logic is only for 1:1 exchange rate
require(amount <= _balances[_addrCreator].seller, "no more token left to exchange");
_balances[_addrCreator].seller = _balances[_addrCreator].seller - amount;
_balances[_addrCreator].buyer = _balances[_addrCreator].buyer + amount;
if(_balances[to].seller == 0){
_status.numberOfBuyer = _status.numberOfBuyer + 1;
}
_balances[to].seller = _balances[to].seller + amount;
_balances[to].buyer = _balances[to].buyer + amount;
_updateRunningState();
}else{
require(false, "Todo other cases");
}
return true;
}
function escrowRefund(address to, uint256 amount) public returns (bool) {
require(amount > 0, "amount is too small");
require(_status.state == State.Running || _status.state == State.Failed, "must be running state to refund");
require(msg.sender == _addrBuyer, "must be buyer contract to refund");
require(_balances[to].buyer >= amount, "buyer fund is not enough to refund");
_balances[to].buyer = _balances[to].buyer - amount;
_balances[to].seller = _balances[to].seller - amount;
_balances[_addrCreator].seller = _balances[_addrCreator].seller + amount;
_balances[_addrCreator].buyer = _balances[_addrCreator].buyer - amount;
if(_balances[to].buyer == 0){
_status.numberOfBuyer = _status.numberOfBuyer - 1;
}
_updateRunningState();
return true;
}
function escrowWithdraw() public returns (bool) {
address from = msg.sender;
if(from == _addrCreator){
if(_status.state == State.Success){
ERC20Mockup(_addrBuyer).transfer(from, _balances[from].buyer);
ERC20Mockup(_addrSeller).transfer(from, _balances[from].seller);
}else if(_status.state == State.Failed){
ERC20Mockup(_addrSeller).transfer(from, _status.fundFilled);
}else{
require(false, "invalid state for seller withdraw");
}
}else{
require(_status.state == State.Success, "withdraw is only in success, otherwise use refund");
ERC20Mockup(_addrSeller).transfer(from, _balances[from].seller);
}
delete _balances[from];
return true;
}
}