zoukankan      html  css  js  c++  java
  • 【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、如果验签通过了,证明是合法订单

  • 相关阅读:
    响应式设计工作总结
    首页性能指标
    前端工作小结
    html5、css3小应用
    循环滚动实例
    程序员修炼之道笔记(转)
    一个操作系统的实现(1)
    scrum role
    一个操作系统的实现(3)
    awk&sed story
  • 原文地址:https://www.cnblogs.com/hongpxiaozhu/p/8891937.html
Copyright © 2011-2022 走看看