mirror of
https://github.com/ZigZagExchange/zksync-lite-market-maker.git
synced 2025-12-17 07:04:23 +01:00
fully functioning general pair marketmaker
This commit is contained in:
14
.env.EXAMPLE
14
.env.EXAMPLE
@@ -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
|
||||
@@ -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'
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,16 +1,107 @@
|
||||
{
|
||||
"eth_privkey": "aaaaaaaaaa.......",
|
||||
"zigzag_chain_id": 1000,
|
||||
"zigzag_ws_url": "wss://zigzag-exchange.herokuapp.com",
|
||||
"ethPrivKey": "aaaa....",
|
||||
"zigzagChainId": 1000,
|
||||
"zigzagWsUrl": "wss://zigzag-exchange.herokuapp.com",
|
||||
"pairs": {
|
||||
"ETH-USDC": {
|
||||
"priceFeedPrimary": "cryptowatch:6631",
|
||||
"priceFeedSecondary": null,
|
||||
"slippageRate": 1e-9,
|
||||
"slippageRate": 1e-5,
|
||||
"active": true,
|
||||
"maxSize": 100,
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,14 @@ else {
|
||||
const mmConfigFile = fs.readFileSync("config.json", "utf8");
|
||||
MM_CONFIG = JSON.parse(mmConfigFile);
|
||||
}
|
||||
console.log(MM_CONFIG);
|
||||
const activePairs = Object.keys(MM_CONFIG.pairs).join(',');
|
||||
let activePairs = [];
|
||||
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
|
||||
let ORDER_BROADCASTING = false;
|
||||
@@ -32,7 +38,7 @@ let syncWallet, ethersProvider, syncProvider, ethWallet,
|
||||
ethersProvider = ethers.getDefaultProvider(ETH_NETWORK);
|
||||
try {
|
||||
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);
|
||||
if (!(await syncWallet.isSigningKeySet())) {
|
||||
console.log("setting sign key");
|
||||
@@ -52,9 +58,13 @@ const SPOT_PRICES = {};
|
||||
const OPEN_ORDERS = {};
|
||||
|
||||
// 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());
|
||||
console.log(markets);
|
||||
if (markets.error) {
|
||||
console.error(markets);
|
||||
throw new Error(markets.error);
|
||||
}
|
||||
const MARKETS = {};
|
||||
for (let i in markets) {
|
||||
const market = markets[i];
|
||||
@@ -72,8 +82,10 @@ function onWsOpen() {
|
||||
zigzagws.on('close', onWsClose);
|
||||
fillOrdersInterval = setInterval(fillOpenOrders, 5000);
|
||||
for (let market in MM_CONFIG.pairs) {
|
||||
const msg = {op:"subscribemarket", args:[CHAIN_ID, market]};
|
||||
zigzagws.send(JSON.stringify(msg));
|
||||
if (MM_CONFIG.pairs[market].active) {
|
||||
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];
|
||||
if (chainid != CHAIN_ID) return { fillable: false, reason: "badchain" }
|
||||
if (!market) return { fillable: false, reason: "badmarket" }
|
||||
if (!mmConfig.active) return { fillable: false, reason: "inactivemarket" }
|
||||
|
||||
const baseQuantity = order[5];
|
||||
const quoteQuantity = order[6];
|
||||
@@ -164,10 +177,10 @@ function isOrderFillable(order) {
|
||||
return { fillable: false, reason: e.message }
|
||||
}
|
||||
|
||||
if (side == 's' && price > quote.hardPrice) {
|
||||
if (side == 's' && price > quote.quotePrice) {
|
||||
return { fillable: false, reason: "badprice" };
|
||||
}
|
||||
else if (side == 'b' && price < quote.hardPrice) {
|
||||
else if (side == 'b' && price < quote.quotePrice) {
|
||||
return { fillable: false, reason: "badprice" };
|
||||
}
|
||||
|
||||
@@ -205,34 +218,37 @@ async function sendfillrequest(orderreceipt) {
|
||||
const baseCurrency = market.baseAssetId;
|
||||
const quoteCurrency = market.quoteAssetId;
|
||||
const side = orderreceipt[3];
|
||||
let price = orderreceipt[4];
|
||||
const baseQuantity = orderreceipt[5];
|
||||
const quoteQuantity = orderreceipt[6];
|
||||
let tokenSell, tokenBuy, sellQuantity;
|
||||
const quote = genquote(chainId, market_id, side, baseQuantity);
|
||||
let tokenSell, tokenBuy, sellQuantity, buyQuantity;
|
||||
if (side === "b") {
|
||||
tokenSell = market.baseAssetId;
|
||||
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") {
|
||||
tokenSell = market.quoteAssetId;
|
||||
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,
|
||||
sellQuantity
|
||||
);
|
||||
sellQuantity = zksync.utils.closestPackableTransactionAmount(sellQuantity);
|
||||
const sellQuantityPacked = zksync.utils.closestPackableTransactionAmount(sellQuantityParsed);
|
||||
const tokenRatio = {};
|
||||
tokenRatio[baseCurrency] = baseQuantity.toFixed(market.baseAsset.decimals);
|
||||
tokenRatio[quoteCurrency] = quoteQuantity.toFixed(market.quoteAsset.decimals);
|
||||
tokenRatio[tokenBuy] = buyQuantity;
|
||||
tokenRatio[tokenSell] = sellQuantity;
|
||||
console.log(tokenRatio);
|
||||
console.log(sellQuantity.toString());
|
||||
const one_min_expiry = (Date.now() / 1000 | 0) + 60;
|
||||
const orderDetails = {
|
||||
tokenSell,
|
||||
tokenBuy,
|
||||
amount: sellQuantity,
|
||||
amount: sellQuantityPacked,
|
||||
ratio: zksync.utils.tokenRatio(tokenRatio),
|
||||
validUntil: one_min_expiry
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user