contract Refunder is
    Ownable,
    OnlySolo,
    IAutoTrader
{
    using Types for Types.Wei;

    // ============ Constants ============

    bytes32 constant FILE = "Refunder";

    // ============ Events ============

    event LogGiverAdded(
        address giver
    );

    event LogGiverRemoved(
        address giver
    );

    event LogRefund(
        Account.Info account,
        uint256 marketId,
        uint256 amount
    );

    // ============ Storage ============

    // the addresses that are able to give funds
    mapping (address => bool) public g_givers;

    // ============ Constructor ============

    constructor (
        address soloMargin,
        address[] memory givers
    )
        public
        OnlySolo(soloMargin)
    {
        for (uint256 i = 0; i < givers.length; i++) {
            g_givers[givers[i]] = true;
        }
    }

    // ============ Owner Functions ============

    function addGiver(
        address giver
    )
        external
        onlyOwner
    {
        emit LogGiverAdded(giver);
        g_givers[giver] = true;
    }

    function removeGiver(
        address giver
    )
        external
        onlyOwner
    {
        emit LogGiverRemoved(giver);
        g_givers[giver] = false;
    }

    // ============ Only-Solo Functions ============

    function getTradeCost(
        uint256 inputMarketId,
        uint256 /* outputMarketId */,
        Account.Info memory makerAccount,
        Account.Info memory takerAccount,
        Types.Par memory /* oldInputPar */,
        Types.Par memory /* newInputPar */,
        Types.Wei memory inputWei,
        bytes memory /* data */
    )
        public
        onlySolo(msg.sender)
        returns (Types.AssetAmount memory)
    {
        Require.that(
            g_givers[takerAccount.owner],
            FILE,
            "Giver not approved",
            takerAccount.owner
        );

        Require.that(
            inputWei.isPositive(),
            FILE,
            "Refund must be positive"
        );

        emit LogRefund(
            makerAccount,
            inputMarketId,
            inputWei.value
        );

        return Types.AssetAmount({
            sign: false,
            denomination: Types.AssetDenomination.Par,
            ref: Types.AssetReference.Delta,
            value: 0
        });
    }
}
/**
 * @title Refunder
 * @author dYdX
 *
 * Allows refunding a user for some amount of tokens for some market.
 */
function getTradeCost(
    uint256 inputMarketId,
    uint256 /* outputMarketId */,
    Account.Info memory makerAccount,
    Account.Info memory takerAccount,
    Types.Par memory /* oldInputPar */,
    Types.Par memory /* newInputPar */,
    Types.Wei memory inputWei,
    bytes memory /* data */
)
    public
    onlySolo(msg.sender)
    returns (Types.AssetAmount memory)
{
    Require.that(
        g_givers[takerAccount.owner],
        FILE,
        "Giver not approved",
        takerAccount.owner
    );

    Require.that(
        inputWei.isPositive(),
        FILE,
        "Refund must be positive"
    );

    emit LogRefund(
        makerAccount,
        inputMarketId,
        inputWei.value
    );

    return Types.AssetAmount({
        sign: false,
        denomination: Types.AssetDenomination.Par,
        ref: Types.AssetReference.Delta,
        value: 0
    });
}

// ============ Only-Solo Functions ============