【0x】 0x.js入门

今天我们来介绍一个以太坊的一个智能合约(不太懂智能合约的可以自行百度)0x。

0x协议是一个去中心化的交易智能合约,它可以实现币种与币种之间的定价交易。

实现0x协议的交易所有DDEX(https://www.ddex.io/trade/DAI-ETH),radarrelay(https://app.radarrelay.com/DAI/WETH)

(绝对不是打广告,纯粹学习)

https://0xproject.com/pdfs/0x_white_paper.pdf

上面是0x的白皮书,0x团队也出了自己的代币:ZRX

 

https://0xproject.com/wiki

0x的文档

https://0xproject.com/docs/0x.js

0x的API文档

 

https://chat.0xproject.com/channel/general

0x的开发团队的聊天室,里面的大佬会回答你的问题,有问题可以直接去问他们。

 

我将作为一个纯客户的角度来讲解一下,如何利用代码来实现自动挂单和填单。

因为0x的工作包是js写的,所以没办法只能使用nodejs去去做这个事。

 

ddex_submitOrder.js

let ethereumjsutil = require("ethereumjs-util");
let hashPersonalMessage = ethereumjsutil.hashPersonalMessage;
let ecsign = ethereumjsutil.ecsign;
let toRpcSig = ethereumjsutil.toRpcSig;
let toBuffer = ethereumjsutil.toBuffer;
let privateToAddress = ethereumjsutil.privateToAddress;

async function post(data, options) {
    let https = require('https');
    let result = "";
    return new Promise(function (resolve, reject) {
        let req = https.request(options, function (res) {
            res.setEncoding('utf8');
            res.on('data', function (chunk) {
                result += chunk;
            });
            res.on('end', function () {
                resolve(result);
            });
        });
        req.on('error', (e) => {
            reject(e);
        });

        let json = JSON.stringify(data);
        req.write(json);
        req.end();
    });
}

/**
 *
 * @param privateKey
 * @param amount
 * @param price
 * @param side
 * @param marketId
 * @returns {Promise<string>}
 */
async function submitDdexOrder(privateKey,amount,price,side,marketId) {
    try{
        let message = "HYDRO-AUTHENTICATION@" + new Date().getTime();
        let address = "0x" + privateToAddress(privateKey).toString("hex");
        let shaAuth = hashPersonalMessage(toBuffer(message))
        let ecdsaSignatureAuth = ecsign(shaAuth, toBuffer(privateKey))
        let signatureAuth = toRpcSig(ecdsaSignatureAuth.v, ecdsaSignatureAuth.r, ecdsaSignatureAuth.s)
        let ddexSignature = address + '#' + message + '#' + signatureAuth
        let buildOptions = {
            host: 'api.ddex.io',
            port: 443,
            path: '/v2/orders/build',
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Hydro-Authentication': ddexSignature
            }
        };
        let buildData = {
            amount: amount,
            price: price,
            side: side,
            marketId: marketId
        };
        let orderResult = await post(buildData, buildOptions);
        let orderJson = JSON.parse(orderResult);
        if (orderResult && orderJson.status === 0) {
            //给我未签名的订单签名
            let unsignOrder = orderJson.data.order;
            let orderId = unsignOrder.id;
            let shaOrder = hashPersonalMessage(toBuffer(orderId));
            let ecdsaSignatureOrder = ecsign(shaOrder, toBuffer(privateKey));
            let signatureOrder = toRpcSig(ecdsaSignatureOrder.v, ecdsaSignatureOrder.r, ecdsaSignatureOrder.s);

            //提交订单的请求地址
            let orderOptions = {
                host: 'api.ddex.io',
                port: 443,
                path: '/v2/orders',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Hydro-Authentication': ddexSignature
                }
            };
            let orderReq = {
                orderId: orderId,
                signature: signatureOrder
            };
            let placeOrderResult = await post(orderReq, orderOptions);
            let placeOrderJson = JSON.parse(placeOrderResult);
            if(placeOrderResult && placeOrderJson.status === 0){
                return orderId;
            }else{
                throw new Error(placeOrderResult);
            }
        } else {
            throw new Error(orderResult);
        }
    }catch (e){
        throw e;
    }
    return "";
}

module.exports = {
    submitDdexOrder
}

 

radarrelay_fillOrder.js

var Zerojs = require("0x.js");
var HDWalletProvider = require("truffle-hdwallet-provider");
var connnect = require("@0xproject/connect");
var HttpClient = connnect.HttpClient;
var ZeroEx = Zerojs.ZeroEx;
var BigNumber = require("@0xproject/utils").BigNumber;

/**
 * fillOrder
 * @param mnemonic wallet mnemonic
 * @param clientUrl geth client node
 * @param relayerApiUrl relayerApiUrl eg:https://api.radarrelay.com/0x/v0/
 * @param baseTokenAddress the token you have
 * @param quoteTokenAddress the token address you want to transfer
 * @param fillOrderAmount how much base token you want to fill
 * @returns {Promise<string>}
 */
async function fillOrder(mnemonic, clientUrl, relayerApiUrl, baseTokenAddress, quoteTokenAddress, networkId,fillOrderAmount) {
    return new Promise(async function (resolve, reject) {
        try {
            let provider = new HDWalletProvider(mnemonic, clientUrl);
            let configs = {
                networkId: networkId,
            };
            let zeroEx = new ZeroEx(provider, configs);
            let accounts = await zeroEx.getAvailableAddressesAsync();
            let makerAddress = accounts[0];
            let relayerClient = new HttpClient(relayerApiUrl);
            let DECIMALS = 18;
            let orderbookRequest = {
                baseTokenAddress: baseTokenAddress,
                quoteTokenAddress: quoteTokenAddress
            };
            let orderbookResponse = await relayerClient.getOrderbookAsync(orderbookRequest);
            let sortedBids = orderbookResponse.bids.sort((orderA, orderB) => {
                const orderRateA = new BigNumber(orderA.takerTokenAmount).div(new BigNumber(orderA.makerTokenAmount));
                const orderRateB = new BigNumber(orderB.takerTokenAmount).div(new BigNumber(orderB.makerTokenAmount));
                return orderRateB.comparedTo(orderRateA);
            });
            let foa = ZeroEx.toBaseUnitAmount(new BigNumber(fillOrderAmount), DECIMALS);
            let bidToFill = sortedBids[sortedBids.length - 1];
            let fillTxHash = await zeroEx.exchange.fillOrderAsync(bidToFill, foa, true, makerAddress);
            let result = await zeroEx.awaitTransactionMinedAsync(fillTxHash, 1000, 1800000);
            if (result.logs) {
                await zeroEx.exchange.throwLogErrorsAsErrors(result.logs);
            }
            resolve(fillTxHash);
        } catch (e) {
            reject(e);
        }
    });
}

/**
 * ETH WETH 1:1
 * @param mnemonic wallet mnemonic
 * @param wethTokenAddress the addres of weth
 * @param ethAmount how much eth you want to exchange
 * @returns {Promise<string>}
 */
async function exchangeWETH(mnemonic, clientUrl, wethTokenAddress, ethAmount, networkId) {
    return new Promise(async function (resolve, reject) {
        try {
            let provider = new HDWalletProvider(mnemonic, clientUrl);
            let configs = {
                networkId: networkId,
            };
            let zeroEx = new ZeroEx(provider, configs);
            let DECIMALS = 18;
            //ETH WETH
            let accounts = await zeroEx.getAvailableAddressesAsync();
            let makerAddress = accounts[0];

            const ethToConvert = ZeroEx.toBaseUnitAmount(new BigNumber(ethAmount), DECIMALS);
            let depositTxHash = await zeroEx.etherToken.depositAsync(wethTokenAddress, ethToConvert, makerAddress);
            let result = await zeroEx.awaitTransactionMinedAsync(depositTxHash, 1000, 1800000);
            if (result.logs) {
                await zeroEx.exchange.throwLogErrorsAsErrors(result.logs);
            }
            resolve(depositTxHash);
        } catch (e) {
            reject(e);
        }
    });
}


module.exports = {
    fillOrder,
    exchangeWETH
}

 

radarrelay_submitOrder.js

var Zerojs = require("0x.js");
var HDWalletProvider = require("truffle-hdwallet-provider");
var connnect = require("@0xproject/connect");
var HttpClient = connnect.HttpClient;
var ZeroEx = Zerojs.ZeroEx;
var BigNumber = require("@0xproject/utils").BigNumber;

/**
 *
 * @param mnemonic wallet mnemonic
 * @param clientUrl geth client node
 * @param relayerApiUrl relayerApiUrl eg:https://api.radarrelay.com/0x/v0/
 * @param makerTokenAddress the token you have
 * @param takerTokenAddress the token address you want to buy
 * @param makerTokenAmount how much token you want to sell
 * @param takerTokenAmount how much token you want to buy
 * @param unixExpireTime ExpireTime unix timestamps
 * @returns {Promise<string>}
 */
async function submitOrder(mnemonic, clientUrl, relayerApiUrl, makerTokenAddress, takerTokenAddress, makerTokenAmount, takerTokenAmount, unixExpireTime, networkId) {
    return new Promise(async function (resolve, reject) {
        try {
            let provider = new HDWalletProvider(mnemonic, clientUrl);
            let configs = {
                networkId: networkId,
            };
            let zeroEx = new ZeroEx(provider, configs);
            let relayerClient = new HttpClient(relayerApiUrl);
            let EXCHANGE_ADDRESS = await zeroEx.exchange.getContractAddress();
            let DECIMALS = 18;
            let addresses = await zeroEx.getAvailableAddressesAsync();
            let ownerAddress = addresses[0];
            let mta = ZeroEx.toBaseUnitAmount(new BigNumber(makerTokenAmount), DECIMALS);
            let tta = ZeroEx.toBaseUnitAmount(new BigNumber(takerTokenAmount), DECIMALS);
            const feesRequest = {
                exchangeContractAddress: EXCHANGE_ADDRESS,
                maker: ownerAddress,
                taker: ZeroEx.NULL_ADDRESS,
                makerTokenAddress: makerTokenAddress,
                takerTokenAddress: takerTokenAddress,
                makerTokenAmount:mta,
                takerTokenAmount:tta,
                expirationUnixTimestampSec: new BigNumber(unixExpireTime),
                salt: ZeroEx.generatePseudoRandomSalt(),
            };
            let feesResponse = await relayerClient.getFeesAsync(feesRequest);
            let order = {
                ...feesRequest,
                ...feesResponse,
            };
            let orderHash = ZeroEx.getOrderHashHex(order);
            let ecSignature = await zeroEx.signOrderHashAsync(orderHash, ownerAddress, false);
            let signedOrder = {
                ...order,
                ecSignature,
            };
            await relayerClient.submitOrderAsync(signedOrder);
            resolve(orderHash);
        } catch (e) {
            reject(e);
        }
    });
}

module.exports = {
    submitOrder
}

 

test.js

let mnemonic = "xxx xxx xxxx xxxxxxx  xxxxx";
let wethContractAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
let relayerApiUrl = "https://api.radarrelay.com/0x/v0/";
let WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
let DAI_ADDRESS = "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359";
let clientUrl = "https://mainnet.infura.io/xxxxxxxxxxx";
let privateKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

async function testExchangeWeth(){
    try{
        let dtx = await exchangeWETH(mnemonic,clientUrl,wethContractAddress,"0.001",1);
        console.info(dtx);
    }catch (e){
        console.error(e);
    }
}

async function testFillRadarOrder(){
    try{
        let fillOrderAmount = "0.005";
        let net = 1;
        let dtx = await require("./radarrelay_fillOrder").fillOrder(mnemonic,clientUrl,relayerApiUrl,WETH_ADDRESS,DAI_ADDRESS,net,fillOrderAmount);
        console.info(dtx);
    }catch (e){
        console.error(e);
    }
}

async function testSubmitOrder(){
    try{
        let dtx = await require("./radarrelay_submitOrder").submitOrder(mnemonic,clientUrl,relayerApiUrl,WETH_ADDRESS,DAI_ADDRESS,0.001,50,1525513767,1);
        console.info(dtx);
    }catch (e){
        console.error(e);
    }
}

async function testDdexOrder(){
    try{
        let orderId = await require("./ddex_submitOrder").submitDdexOrder(privateKey,5,0.0013184,"buy","DAI-ETH");
        console.info(dtx);
    }catch (e){
        console.error(e);
    }
}

 

 

注意

1、选择的HDWalletProvider一定要选0x团队改过的。官网版本不能用,官方签名是不合法的。

2、选择好正确的网络ID和网络地址

3、我这里的都是生产环境的地址,测试环境的币种合约地址自己找,请做实验的时候再次确认几个币种的合约地址是否正确。

4、order整体结构就是这样,要仔细核对里面的参数是否输入正确

5、如果验签通过了,证明是合法订单

 

posted @ 2018-08-28 10:35  红p小猪  阅读(1313)  评论(0编辑  收藏  举报