fully functioning general pair marketmaker

This commit is contained in:
vixidev99
2022-01-06 19:39:35 +05:30
parent 3a40c16d82
commit bdfeb1101e
4 changed files with 134 additions and 39 deletions

View File

@@ -1,14 +0,0 @@
ZIGZAG_WS_URL=wss://zigzag-exchange.herokuapp.com
ETH_PRIVKEY=myprivkey
# mainnet or rinkeby
ETH_NETWORK=mainnet
# See https://github.com/ZigZagExchange/backend/README.md for up to date Chain IDs
# 1 = zksync-mainnet, 1000 = zksync-rinkeby
CHAIN_ID=1
MIN_DOLLAR_SIZE=0
MAX_DOLLAR_SIZE=1000000
# Comma separated list of supported pairs you want to market make for
PAIR_WHITELIST=ETH-USDT,ETH-USDC

View File

@@ -14,4 +14,6 @@ If your hosting service requires you to pass in configs via environment variable
cat config.json | tr -d ' ' | tr -d '\n' cat config.json | tr -d ' ' | tr -d '\n'
``` ```
and set it to the value of the `MM_CONFIG` environment variable to override the config file and set it to the value of the `MM_CONFIG` environment variable to override the config file.
You can also override the private key in the config file with the `ETH_PRIVKEY` environment variable.

View File

@@ -1,16 +1,107 @@
{ {
"eth_privkey": "aaaaaaaaaa.......", "ethPrivKey": "aaaa....",
"zigzag_chain_id": 1000, "zigzagChainId": 1000,
"zigzag_ws_url": "wss://zigzag-exchange.herokuapp.com", "zigzagWsUrl": "wss://zigzag-exchange.herokuapp.com",
"pairs": { "pairs": {
"ETH-USDC": { "ETH-USDC": {
"priceFeedPrimary": "cryptowatch:6631", "priceFeedPrimary": "cryptowatch:6631",
"priceFeedSecondary": null, "priceFeedSecondary": null,
"slippageRate": 1e-9, "slippageRate": 1e-5,
"active": true, "active": true,
"maxSize": 100, "maxSize": 100,
"minSize": 0.0003, "minSize": 0.0003,
"minSpread": 0.0005 "minSpread": 0.0005,
"active": true
},
"ETH-USDT": {
"priceFeedPrimary": "cryptowatch:588",
"priceFeedSecondary": null,
"slippageRate": 1e-5,
"active": true,
"maxSize": 100,
"minSize": 0.0003,
"minSpread": 0.0005,
"active": true
},
"ETH-DAI": {
"priceFeedPrimary": "cryptowatch:63533",
"priceFeedSecondary": null,
"slippageRate": 1e-5,
"active": true,
"maxSize": 100,
"minSize": 0.0003,
"minSpread": 0.0005,
"active": true
},
"ETH-FRAX": {
"priceFeedPrimary": "cryptowatch:6631",
"priceFeedSecondary": null,
"slippageRate": 1e-5,
"active": true,
"maxSize": 100,
"minSize": 0.0003,
"minSpread": 0.0005,
"active": false
},
"WBTC-USDT": {
"priceFeedPrimary": "cryptowatch:579",
"priceFeedSecondary": null,
"slippageRate": 1e-4,
"active": true,
"maxSize": 10,
"minSize": 0.00003,
"minSpread": 0.0005,
"active": false
},
"WBTC-USDC": {
"priceFeedPrimary": "cryptowatch:6630",
"priceFeedSecondary": null,
"slippageRate": 1e-4,
"active": true,
"maxSize": 10,
"minSize": 0.00003,
"minSpread": 0.0005,
"active": false
},
"WBTC-DAI": {
"priceFeedPrimary": "cryptowatch:63532",
"priceFeedSecondary": null,
"slippageRate": 1e-4,
"active": true,
"maxSize": 10,
"minSize": 0.00003,
"minSpread": 0.0005,
"active": false
},
"USDC-USDT": {
"priceFeedPrimary": "cryptowatch:6636",
"priceFeedSecondary": null,
"slippageRate": 1e-9,
"active": true,
"maxSize": 100000,
"minSize": 1,
"minSpread": 0.0003,
"active": true
},
"DAI-USDT": {
"priceFeedPrimary": "cryptowatch:63349",
"priceFeedSecondary": null,
"slippageRate": 1e-9,
"active": true,
"maxSize": 100000,
"minSize": 1,
"minSpread": 0.0003,
"active": true
},
"DAI-USDC": {
"priceFeedPrimary": "cryptowatch:61485",
"priceFeedSecondary": null,
"slippageRate": 1e-9,
"active": true,
"maxSize": 100000,
"minSize": 1,
"minSpread": 0.0003,
"active": true
} }
} }
} }

View File

@@ -16,8 +16,14 @@ else {
const mmConfigFile = fs.readFileSync("config.json", "utf8"); const mmConfigFile = fs.readFileSync("config.json", "utf8");
MM_CONFIG = JSON.parse(mmConfigFile); MM_CONFIG = JSON.parse(mmConfigFile);
} }
console.log(MM_CONFIG); let activePairs = [];
const activePairs = Object.keys(MM_CONFIG.pairs).join(','); for (let marketId in MM_CONFIG.pairs) {
const pair = MM_CONFIG.pairs[marketId];
if (pair.active) {
activePairs.push(marketId);
}
}
console.log("ACTIVE PAIRS", activePairs);
// Initiate fill loop // Initiate fill loop
let ORDER_BROADCASTING = false; let ORDER_BROADCASTING = false;
@@ -32,7 +38,7 @@ let syncWallet, ethersProvider, syncProvider, ethWallet,
ethersProvider = ethers.getDefaultProvider(ETH_NETWORK); ethersProvider = ethers.getDefaultProvider(ETH_NETWORK);
try { try {
syncProvider = await zksync.getDefaultProvider(ETH_NETWORK); syncProvider = await zksync.getDefaultProvider(ETH_NETWORK);
ethWallet = new ethers.Wallet(MM_CONFIG.ethPrivKey); ethWallet = new ethers.Wallet(process.env.ETH_PRIVKEY || MM_CONFIG.ethPrivKey);
syncWallet = await zksync.Wallet.fromEthSigner(ethWallet, syncProvider); syncWallet = await zksync.Wallet.fromEthSigner(ethWallet, syncProvider);
if (!(await syncWallet.isSigningKeySet())) { if (!(await syncWallet.isSigningKeySet())) {
console.log("setting sign key"); console.log("setting sign key");
@@ -52,9 +58,13 @@ const SPOT_PRICES = {};
const OPEN_ORDERS = {}; const OPEN_ORDERS = {};
// Get markets info // Get markets info
const markets_url = `https://zigzag-markets.herokuapp.com/markets?chainid=${CHAIN_ID}&id=${activePairs}` const activePairsText = activePairs.join(',');
const markets_url = `https://zigzag-markets.herokuapp.com/markets?chainid=${CHAIN_ID}&id=${activePairsText}`
const markets = await fetch(markets_url).then(r => r.json()); const markets = await fetch(markets_url).then(r => r.json());
console.log(markets); if (markets.error) {
console.error(markets);
throw new Error(markets.error);
}
const MARKETS = {}; const MARKETS = {};
for (let i in markets) { for (let i in markets) {
const market = markets[i]; const market = markets[i];
@@ -72,8 +82,10 @@ function onWsOpen() {
zigzagws.on('close', onWsClose); zigzagws.on('close', onWsClose);
fillOrdersInterval = setInterval(fillOpenOrders, 5000); fillOrdersInterval = setInterval(fillOpenOrders, 5000);
for (let market in MM_CONFIG.pairs) { for (let market in MM_CONFIG.pairs) {
const msg = {op:"subscribemarket", args:[CHAIN_ID, market]}; if (MM_CONFIG.pairs[market].active) {
zigzagws.send(JSON.stringify(msg)); const msg = {op:"subscribemarket", args:[CHAIN_ID, market]};
zigzagws.send(JSON.stringify(msg));
}
} }
} }
@@ -139,6 +151,7 @@ function isOrderFillable(order) {
const mmConfig = MM_CONFIG.pairs[market_id]; const mmConfig = MM_CONFIG.pairs[market_id];
if (chainid != CHAIN_ID) return { fillable: false, reason: "badchain" } if (chainid != CHAIN_ID) return { fillable: false, reason: "badchain" }
if (!market) return { fillable: false, reason: "badmarket" } if (!market) return { fillable: false, reason: "badmarket" }
if (!mmConfig.active) return { fillable: false, reason: "inactivemarket" }
const baseQuantity = order[5]; const baseQuantity = order[5];
const quoteQuantity = order[6]; const quoteQuantity = order[6];
@@ -164,10 +177,10 @@ function isOrderFillable(order) {
return { fillable: false, reason: e.message } return { fillable: false, reason: e.message }
} }
if (side == 's' && price > quote.hardPrice) { if (side == 's' && price > quote.quotePrice) {
return { fillable: false, reason: "badprice" }; return { fillable: false, reason: "badprice" };
} }
else if (side == 'b' && price < quote.hardPrice) { else if (side == 'b' && price < quote.quotePrice) {
return { fillable: false, reason: "badprice" }; return { fillable: false, reason: "badprice" };
} }
@@ -205,34 +218,37 @@ async function sendfillrequest(orderreceipt) {
const baseCurrency = market.baseAssetId; const baseCurrency = market.baseAssetId;
const quoteCurrency = market.quoteAssetId; const quoteCurrency = market.quoteAssetId;
const side = orderreceipt[3]; const side = orderreceipt[3];
let price = orderreceipt[4];
const baseQuantity = orderreceipt[5]; const baseQuantity = orderreceipt[5];
const quoteQuantity = orderreceipt[6]; const quoteQuantity = orderreceipt[6];
let tokenSell, tokenBuy, sellQuantity; const quote = genquote(chainId, market_id, side, baseQuantity);
let tokenSell, tokenBuy, sellQuantity, buyQuantity;
if (side === "b") { if (side === "b") {
tokenSell = market.baseAssetId; tokenSell = market.baseAssetId;
tokenBuy = market.quoteAssetId; tokenBuy = market.quoteAssetId;
sellQuantity = baseQuantity.toFixed(market.baseAsset.decimals); // Add 1 bip to to protect against rounding errors
sellQuantity = (baseQuantity * 1.0001).toFixed(market.baseAsset.decimals);
buyQuantity = quote.quoteQuantity.toFixed(market.quoteAsset.decimals);
} else if (side === "s") { } else if (side === "s") {
tokenSell = market.quoteAssetId; tokenSell = market.quoteAssetId;
tokenBuy = market.baseAssetId; tokenBuy = market.baseAssetId;
sellQuantity = quoteQuantity.toFixed(market.quoteAsset.decimals); // Add 1 bip to to protect against rounding errors
sellQuantity = (quote.quoteQuantity * 1.0001).toFixed(market.quoteAsset.decimals);
buyQuantity = baseQuantity.toFixed(market.baseAsset.decimals);
} }
sellQuantity = syncProvider.tokenSet.parseToken( const sellQuantityParsed = syncProvider.tokenSet.parseToken(
tokenSell, tokenSell,
sellQuantity sellQuantity
); );
sellQuantity = zksync.utils.closestPackableTransactionAmount(sellQuantity); const sellQuantityPacked = zksync.utils.closestPackableTransactionAmount(sellQuantityParsed);
const tokenRatio = {}; const tokenRatio = {};
tokenRatio[baseCurrency] = baseQuantity.toFixed(market.baseAsset.decimals); tokenRatio[tokenBuy] = buyQuantity;
tokenRatio[quoteCurrency] = quoteQuantity.toFixed(market.quoteAsset.decimals); tokenRatio[tokenSell] = sellQuantity;
console.log(tokenRatio); console.log(tokenRatio);
console.log(sellQuantity.toString());
const one_min_expiry = (Date.now() / 1000 | 0) + 60; const one_min_expiry = (Date.now() / 1000 | 0) + 60;
const orderDetails = { const orderDetails = {
tokenSell, tokenSell,
tokenBuy, tokenBuy,
amount: sellQuantity, amount: sellQuantityPacked,
ratio: zksync.utils.tokenRatio(tokenRatio), ratio: zksync.utils.tokenRatio(tokenRatio),
validUntil: one_min_expiry validUntil: one_min_expiry
} }