今天咱們來介紹一個以太坊的一個智能合約(不太懂智能合約的能夠自行百度)0x。node
0x協議是一個去中心化的交易智能合約,它能夠實現幣種與幣種之間的訂價交易。json
實現0x協議的交易全部DDEX(https://www.ddex.io/trade/DAI-ETH),radarrelay(https://app.radarrelay.com/DAI/WETH)api
(絕對不是打廣告,純粹學習)網絡
https://0xproject.com/pdfs/0x_white_paper.pdfapp
上面是0x的白皮書,0x團隊也出了本身的代幣:ZRXdom
https://0xproject.com/wikiasync
0x的文檔ide
https://0xproject.com/docs/0x.jspost
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); } }
注意
一、選擇的HDWalletProvider必定要選0x團隊改過的。官網版本不能用,官方簽名是不合法的。
二、選擇好正確的網絡ID和網絡地址
三、我這裏的都是生產環境的地址,測試環境的幣種合約地址本身找,請作實驗的時候再次確認幾個幣種的合約地址是否正確。
四、order總體結構就是這樣,要仔細覈對裏面的參數是否輸入正確
五、若是驗籤經過了,證實是合法訂單