contract DAIHardFactory {
    event NewTrade(uint id, address tradeAddress, bool indexed initiatorIsPayer);

    ERC20Interface public daiContract;
    address payable public devFeeAddress;

    constructor(ERC20Interface _daiContract, address payable _devFeeAddress)
    public {
        daiContract = _daiContract;
        devFeeAddress = _devFeeAddress;
    }

    struct CreationInfo {
        address address_;
        uint blocknum;
    }

    CreationInfo[] public createdTrades;

    function getBuyerDeposit(uint tradeAmount)
    public
    pure
    returns (uint buyerDeposit) {
        return tradeAmount / 3;
    }

    function getDevFee(uint tradeAmount)
    public
    pure
    returns (uint devFee) {
        return tradeAmount / 100;
    }

    function getExtraFees(uint tradeAmount)
    public
    pure
    returns (uint buyerDeposit, uint devFee) {
        return (getBuyerDeposit(tradeAmount), getDevFee(tradeAmount));
    }

    /*
    The Solidity compiler can't handle much stack depth,
    so we have to pack some args together in annoying ways...
    Hence the 'uintArgs'. Here is its layout:
    0 - daiAmount
    1 - pokeReward
    2 - autorecallInterval
    3 - autoabortInterval
    4 - autoreleaseInterval
    */

    function openDAIHardTrade(address payable _initiator, bool initiatorIsBuyer, uint[5] calldata uintArgs, string calldata _totalPrice, string calldata _fiatTransferMethods, string calldata _commPubkey)
    external
    returns (DAIHardTrade) {
        uint transferAmount;
        uint[6] memory newUintArgs; // Note that this structure is not the same as the above comment describes. See below in DAIHardTrade.open.

        if (initiatorIsBuyer) {
            transferAmount = getBuyerDeposit(uintArgs[0]) + uintArgs[1] + getDevFee(uintArgs[0]);
            newUintArgs = [uintArgs[0], uintArgs[1], getDevFee(uintArgs[0]), uintArgs[2], uintArgs[3], uintArgs[4]];
        }
        else {
            transferAmount = uintArgs[0] + uintArgs[1] + getDevFee(uintArgs[0]);
            newUintArgs = [getBuyerDeposit(uintArgs[0]), uintArgs[1], getDevFee(uintArgs[0]), uintArgs[2], uintArgs[3], uintArgs[4]];
        }

        //create the new trade and add its creationInfo to createdTrades
        DAIHardTrade newTrade = new DAIHardTrade(daiContract, devFeeAddress);
        createdTrades.push(CreationInfo(address(newTrade), block.number));
        emit NewTrade(createdTrades.length - 1, address(newTrade), initiatorIsBuyer);

        //transfer DAI to the trade and open it
        require(daiContract.transferFrom(msg.sender, address(newTrade), transferAmount), "Token transfer failed. Did you call approve() on the DAI contract?");
        newTrade.open(_initiator, initiatorIsBuyer, newUintArgs, _totalPrice, _fiatTransferMethods, _commPubkey);
    }

    function getNumTrades()
    external
    view
    returns (uint num) {
        return createdTrades.length;
    }
}
function openDAIHardTrade(address payable _initiator, bool initiatorIsBuyer, uint[5] calldata uintArgs, string calldata _totalPrice, string calldata _fiatTransferMethods, string calldata _commPubkey)
external
returns (DAIHardTrade) {
    uint transferAmount;
    uint[6] memory newUintArgs; // Note that this structure is not the same as the above comment describes. See below in DAIHardTrade.open.

    if (initiatorIsBuyer) {
        transferAmount = getBuyerDeposit(uintArgs[0]) + uintArgs[1] + getDevFee(uintArgs[0]);
        newUintArgs = [uintArgs[0], uintArgs[1], getDevFee(uintArgs[0]), uintArgs[2], uintArgs[3], uintArgs[4]];
    }
    else {
        transferAmount = uintArgs[0] + uintArgs[1] + getDevFee(uintArgs[0]);
        newUintArgs = [getBuyerDeposit(uintArgs[0]), uintArgs[1], getDevFee(uintArgs[0]), uintArgs[2], uintArgs[3], uintArgs[4]];
    }

    //create the new trade and add its creationInfo to createdTrades
    DAIHardTrade newTrade = new DAIHardTrade(daiContract, devFeeAddress);
    createdTrades.push(CreationInfo(address(newTrade), block.number));
    emit NewTrade(createdTrades.length - 1, address(newTrade), initiatorIsBuyer);

    //transfer DAI to the trade and open it
    require(daiContract.transferFrom(msg.sender, address(newTrade), transferAmount), "Token transfer failed. Did you call approve() on the DAI contract?");
    newTrade.open(_initiator, initiatorIsBuyer, newUintArgs, _totalPrice, _fiatTransferMethods, _commPubkey);
}

/*
 The Solidity compiler can't handle much stack depth,
 so we have to pack some args together in annoying ways...
 Hence the 'uintArgs'. Here is its layout:
 0 - daiAmount
 1 - pokeReward
 2 - autorecallInterval
 3 - autoabortInterval
 4 - autoreleaseInterval
 */