When I try to fill an order with funds from a contract I get the following generic error:

Error: Transaction: 0x1d3161cd7f318c3b0b28fc34b2c6bca0cbf4efdb3b11fcf7ec3af7c9adfd821b exited with an error (status 0). Reason given: TRANSFER_FAILED. Please check that the transaction: - satisfies all conditions set by Solidity require statements. - does not trigger a Solidity revert statement.

I've got the following contract:

pragma solidity >=0.4.24;

Exchange exchange;
EthForERC20Token crowdsale;
WrapERC20Token wrapERC20Token;

    address _exchangeAddress
    // The local 0x exchange intstance
    exchange = Exchange(_exchangeAddress);
    // Grand unlimited allownace to the exchange contract.
    wrapERC20Token = new WrapERC20Token(address(exchange)); 

function fillOrder (
    Exchange.Order memory _order, 
    uint256 _assetFillAmount,
    bytes memory _signature
    exchange.fillOrder(_order,_assetFillAmount, _signature);

function getWrappedERC20Address() 
returns(address) {
    return address(wrapERC20Token);

I tested and the contract owns enough of the WrappedERC20Token which is just an ERC20 token with the option to pre-approve an address with unlimited allowance.

My 0x order creation is as follows:

const wrappedShareAddress = await contract.getWrappedShareAddress();
const maker = accounts[0];
const makerAssetData = zeroX.assetDataUtils.encodeERC20AssetData(etherToken);
const takerAssetData = zeroX.assetDataUtils.encodeERC20AssetData(wrappedShareAddress);
const contractWrappers = new zeroX.ContractWrappers(providerEngine, { networkId: 50 });

const order = {
            exchangeAddress: exchange,
            makerAddress: maker.toLowerCase(),
            takerAddress: NULL_ADDRESS,
            senderAddress: NULL_ADDRESS,
            feeRecipientAddress: NULL_ADDRESS,
            expirationTimeSeconds: (1581437362).toString(),
            salt: zeroX.generatePseudoRandomSalt().toString(),
            makerAssetAmount: new zeroX.BigNumber("5e17").toFixed(),
            takerAssetAmount: new zeroX.BigNumber("5e17").toFixed(),
            makerFee: new zeroX.BigNumber("0").toFixed(),
        takerFee: new zeroX.BigNumber("0").toFixed(),
        // console.log(order);
        // Generate the order hash and sign it
        const orderHashHex = zeroX.orderHashUtils.getOrderHashHex(order);
    signature = await zeroX.signatureUtils.ecSignHashAsync(providerEngine, orderHashHex, maker);
        signedOrder = {...order, signature};
    const makerWETHApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(

        await toTxhash.mineTx(makerWETHApprovalTxHash);

        const makerWETHDepositTxHash = await contractWrappers.etherToken.depositAsync(
            new zeroX.BigNumber("2e18"),

        await toTxhash.mineTx(makerWETHDepositTxHash);

Then I call the smart contract function using:

    const res = await contract.fillOrder(
        new zeroX.BigNumber("5e17").toFixed(),
        {from: maker, value: new zeroX.BigNumber("1e18").toFixed()}
  • 1
    It is not wise to use 10 ** 18 in Javascript, since it is larger (much larger) than the maximum safe integer. Use "2e18" instead of 2 * 10 ** 18, or "5e17" instead of 0.5 * 10 ** 18, or "1e18" instead of 10 ** 18, etc. If you need to utilize values that are "more complicated", then require("bignumber.js") and use BigNumber objects wherever needed. You can convert such object to a full-precision string via the toFixed() function. – goodvibration Feb 12 at 13:49
  • 1
    You do realize that .toString() is redundant in the expression ("5e17").toString(), yes? – goodvibration Feb 12 at 13:58
  • Was still busy editing, thanks for the comments. – jasper Feb 12 at 13:59
  • 1
    Also, why did you use new for the initialization of wrapERC20Token but not for the initialization of exchange? Since you have no require or revert statements in your code, this is a good candidate for your transaction failure (later in your code, when you call exchange.fillOrder, for example). – goodvibration Feb 12 at 14:01
  • 1
    P.S.: the string returned by new zeroX.BigNumber("5e17").toFixed() is "500000000000000000". Although it is different from the string "5e17", when converted back to a BigNumber instance, they will yield the same object. And when you call fillOrder, this string is eventually converted to such an object. So you may as well use the simplest notation possible, which is "5e17". I meant for you to use toFixed() when handling a value returned from some contract function, since toString() may convert it to scientific notation, and then you might end up "losing some digits". – goodvibration Feb 12 at 14:08

Your contract needs to approve the 0x ERC20Proxy to move your ERC20 tokens.

For example, take a look at the Forwarder contract which does this in the constructor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.