0xProject/0x-monorepo

general: Exchange fillOrder function fails.

PaoloRollo opened this issue · 3 comments

Expected Behavior

Maker creates a new Order and signs it; Taker retrieves the Order, checks if the signature is valid and then proceeds to fill it.

Current Behavior

Maker correctly creates a new Order and signs it; Taker correctly retrieves the Order and checks if the signature is valid. The error is in the last part, when he proceeds to fill the Order.

Steps to Reproduce (for bugs)

I've downloaded latest Ganache snapshot and ran it using docker. I've given approval for both maker and taker on their respective ERC20Token (ZRX and WETH). Proxies are registered on the Exchange and vice-versa.

Maker code

let maker = '0x5409ED021D9299bf6814279A6A1411A7e866A631';
let taker = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';

const contractAddresses = {
    assetProxyOwner: "0x8d42e38980ce74736c21c059b2240df09958d3c8",
    coordinator: "0x0d8b0dd11f5d34ed41d556def5f841900d5b1c6b",
    coordinatorRegistry: "0x1941ff73d1154774d87521d2d0aaad5d19c8df60",
    devUtils: "0x38ef19fdf8e8415f18c307ed71967e19aac28ba1",
    dutchAuction: "0xa31e64ea55b9b6bbb9d6a676738e9a5b23149f84",
    erc20Proxy: "0x1dc4c1cefef38a777b15aa20260a54e584b16c48",
    erc721Proxy: "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401",
    erc1155Proxy: "0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8",
    etherToken: "0x0b1ba0af832d7c05fd64161e0db78e85978e8082",
    exchange: "0x48bacb9266a570d521063ef5dd96e61686dbe788",
    forwarder: "0xaa86dda78e9434aca114b6676fc742a18d15a1cc",
    multiAssetProxy: "0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db",
    orderValidator: "0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29",
    staticCallProxy: "0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f",
    zrxToken: "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
};

const etherTokenAddress = contractAddresses.etherToken;

const makerAssetData = assetDataUtils.encodeERC20AssetData(contractAddresses.zrxToken);
const takerAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress);
const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), DECIMALS);
const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.1), DECIMALS);

const order = {
    makerAddress: maker,
    takerAddress: NULL_ADDRESS,
    senderAddress: NULL_ADDRESS,
    feeRecipientAddress: NULL_ADDRESS,
    expirationTimeSeconds: 1575240044,
    salt: 1234567890,
    makerAssetAmount: 1,
    takerAssetAmount: 10,
    makerFee: 0,
    takerFee: 0,
    makerAssetData: makerAssetData,
    takerAssetData: takerAssetData,
};

const provider = ('ethereum' in window) ? window['ethereum'] : Web3.givenProvider;
const web3 = new Web3(provider);

const exchangeContract = new web3.eth.Contract(exchangeABI, exchangeAddress);
const erc20ProxyContract = new web3.eth.Contract(erc20ProxyABI, erc20ProxyAddress);
const erc721ProxyContract = new web3.eth.Contract(erc721ProxyABI, erc721ProxyAddress);
const devUtilsContract = new web3.eth.Contract(devUtilsABI, devUtilsAddress);
const wethContract = new web3.eth.Contract(wethABI, contractAddresses.etherToken);
const zrxContract = new web3.eth.Contract(zrxABI, contractAddresses.zrxToken);

let orderHashHex = "";
let signature = "";

exchangeContract.methods.getOrderInfo(order).call({}).then((res) => {
    orderHashHex = res.orderHash;
    web3.eth.sign(orderHashHex, maker).then((result) => {
        console.log(result);
        signature = result;
    });
});

Taker code

let maker = '0x5409ED021D9299bf6814279A6A1411A7e866A631';
let taker = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
const contractAddresses = {
    assetProxyOwner: "0x8d42e38980ce74736c21c059b2240df09958d3c8",
    coordinator: "0x0d8b0dd11f5d34ed41d556def5f841900d5b1c6b",
    coordinatorRegistry: "0x1941ff73d1154774d87521d2d0aaad5d19c8df60",
    devUtils: "0x38ef19fdf8e8415f18c307ed71967e19aac28ba1",
    dutchAuction: "0xa31e64ea55b9b6bbb9d6a676738e9a5b23149f84",
    erc20Proxy: "0x1dc4c1cefef38a777b15aa20260a54e584b16c48",
    erc721Proxy: "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401",
    erc1155Proxy: "0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8",
    etherToken: "0x0b1ba0af832d7c05fd64161e0db78e85978e8082",
    exchange: "0x48bacb9266a570d521063ef5dd96e61686dbe788",
    forwarder: "0xaa86dda78e9434aca114b6676fc742a18d15a1cc",
    multiAssetProxy: "0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db",
    orderValidator: "0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29",
    staticCallProxy: "0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f",
    zrxToken: "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
};

const etherTokenAddress = contractAddresses.etherToken;

const makerAssetData = assetDataUtils.encodeERC20AssetData(contractAddresses.zrxToken);
const takerAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress);
const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), DECIMALS);
const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.1), DECIMALS);

const order = {
    makerAddress: maker,
    takerAddress: NULL_ADDRESS,
    senderAddress: NULL_ADDRESS,
    feeRecipientAddress: NULL_ADDRESS,
    expirationTimeSeconds: 1575240044,
    salt: 1234567890,
    makerAssetAmount: 1,
    takerAssetAmount: 10,
    makerFee: 0,
    takerFee: 0,
    makerAssetData: makerAssetData,
    takerAssetData: takerAssetData,
};

const provider = ('ethereum' in window) ? window['ethereum'] : Web3.givenProvider;
const web3 = new Web3(provider);

const exchangeContract = new web3.eth.Contract(exchangeABI, exchangeAddress);
const erc20ProxyContract = new web3.eth.Contract(erc20ProxyABI, erc20ProxyAddress);
const erc721ProxyContract = new web3.eth.Contract(erc721ProxyABI, erc721ProxyAddress);
const devUtilsContract = new web3.eth.Contract(devUtilsABI, devUtilsAddress);
const wethContract = new web3.eth.Contract(wethABI, contractAddresses.etherToken);
const zrxContract = new web3.eth.Contract(zrxABI, contractAddresses.zrxToken);

let orderHashHex = "";
let signature = PREVIOUSLY_GENERATED_SIGNATURE;

exchangeContract.methods.getOrderInfo(order).call({}).then((res) => {
    orderHashHex = res.orderHash;
    exchangeContract.methods.isValidSignature(orderHashHex, maker, signature).call({}).then((res) => {
        if (res) {
            exchangeContract.methods.fillOrder(order, 10, signature).send({from: taker, value: 0, gas: 1000000, gasPrice: 0}).then(console.log);
        }
    });
});

The error that i'm getting is the following (Ganache):

ganache_1  |   Transaction: 0x54283efb9107ea600743a67e529700ba05feb4ffe8efd9f5d13807525f2ec62e
ganache_1  |   Gas usage: 63486
ganache_1  |   Block Number: 67
ganache_1  |   Block Time: Sun Dec 01 2019 17:14:14 GMT+0000 (Coordinated Universal Time)
ganache_1  |   Runtime Error: revert

In browser console:

{
  "transactionHash": "0xabcc20bc59bf98a1178d4b0b525711efa2fefcb237ff5266a7ed44d21beacf39",
  "transactionIndex": 0,
  "blockHash": "0x9bd0217e1b97aedb96392a137f6396b6e4f6c7fb5ba440a9d0aedf61f94c5184",
  "blockNumber": 68,
  "gasUsed": 63486,
  "cumulativeGasUsed": 63486,
  "contractAddress": null,
  "status": false,
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "events": {}
}

Context

I'm trying to simply let a Maker create and Order and then let the Taker fill it.

Your Environment

Package Version
xorg/ganache-cli latest
Network
ganache

EDIT: Updated for correct ganache image usage.

dekz commented

@PaoloRollo in 0x we use an encoded signature to allow for different types of signatures. There are a range of valid signature implementations (EIP712, standard ec sign, "contract" signatures). So the last byte needs to represent what the signature is.

You can find the details here in the v2 specification. Basically you need to append a 0x03 to the end of your signature hex.

With different wallet providers it is also ambiguous to the encoding of v,r,s or r,s,v parameters, so this may need to be split and re-arranged. Here is the relevant code where we perform this in our libraries.

Thank you very much @dekz . That was my problem. I switched the signing function from the basic web3.eth.sign to the 0x.js one by using the following code:

const providerEngine = new Web3ProviderEngine();
    providerEngine.addProvider(new RPCSubprovider('http://localhost:8545'));
    providerEngine.start();

signatureUtils.ecSignHashAsync(providerEngine, orderHashHex, maker).then((res) => {
        console.log(res);
    })

And it worked just fine. You can close this issue :)

dekz commented

no worries!