【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
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、如果验签通过了,证明是合法订单

浙公网安备 33010602011771号