@gnosis.pm/dex-contracts
Version:
Contracts for dFusion multi-token batch auction exchange
94 lines (93 loc) • 5.73 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bn_js_1 = __importDefault(require("bn.js"));
const fee_token_liquidity_1 = require("../src/fee_token_liquidity");
const onchain_reading_1 = require("../src/onchain_reading");
const logging_1 = require("../src/logging");
const log = logging_1.factory.getLogger("scripts.owl_liquidity");
const BatchExchange = artifacts.require("BatchExchange");
const MAXU32 = new bn_js_1.default(2).pow(new bn_js_1.default(32)).sub(new bn_js_1.default(1));
const MIN_OWL_LIQUIDITY = new bn_js_1.default(10).pow(new bn_js_1.default(17));
const SELL_AMOUNT_OWL = new bn_js_1.default(10).pow(new bn_js_1.default(18)).mul(new bn_js_1.default(5));
// All orders provided by this liquidity script will sell OWL for a very high price:
// At 1000 [token]/[OWL]. In most of the cases this will ensure that 1 [OWL] is valued
// higher than 1 dollar. For tokens valued below 1/10000 USD, OWL can be extracted profitably
// from these orders. However, since we only sell 5 OWL and 10 OWL have to be spent to add one token,
// stealing OWL by adding new tokens is not profitable.
const PRICE_FOR_PROVISION = new bn_js_1.default(10000);
const containsSellOrderProvidingLiquidity = function (orders) {
return orders.some((order) => order.sellTokenBalance.gt(MIN_OWL_LIQUIDITY) &&
order.remainingAmount.gt(MIN_OWL_LIQUIDITY));
};
// This function checks whether it is likely that Gnosis has already provided liquidity for this token
// with a liquidity-order. The check depends on the match of two order criteria: SellAmount and validUntil.
// Despite being just an heuristic check, it should be sufficient for now.
const hasOWLLiquidityOrderAlreadyBeenPlaced = function (orders) {
return orders.some((order) => order.priceDenominator.eq(SELL_AMOUNT_OWL) &&
new bn_js_1.default(order.validUntil).eq(MAXU32));
};
module.exports = (callback) => __awaiter(void 0, void 0, void 0, function* () {
try {
const exchange = yield BatchExchange.deployed();
const owlTokenAddress = yield exchange.tokenIdToAddressMap(0);
const [liquidityEnsurer] = yield web3.eth.getAccounts();
log.info(`Using account ${liquidityEnsurer}`);
// check that liquidityEnsurer has sufficient OWL in the exchange:
const owlBalance = yield exchange.getBalance(liquidityEnsurer, owlTokenAddress);
if (new bn_js_1.default(10).pow(new bn_js_1.default(18)).gt(owlBalance)) {
callback("Error: OWL balance is below the 10 OWL threshold, please stock it up again");
}
// Get the order data
const numTokens = (yield exchange.numTokens()).toNumber();
const batchId = (yield exchange.getCurrentBatchId()).toNumber();
log.info("Retrieving orders from exchange. This may take a while...");
let orders = yield onchain_reading_1.getOrdersPaginated(exchange.contract, 100);
orders = orders.filter((order) => order.validUntil >= batchId && order.validFrom <= batchId);
// Ensure OWL-liquidity is given
const tokensRequiringLiquidity = [];
for (let tokenId = 1; tokenId < numTokens; tokenId++) {
const tokenAddress = yield exchange.tokenIdToAddressMap(tokenId);
log.info(`Checking liquidity for token ${tokenId} - ${tokenAddress}`);
const ordersForTokenId = orders.filter((order) => order.buyToken == tokenId && order.sellToken == 0);
if (!containsSellOrderProvidingLiquidity(ordersForTokenId) &&
!hasOWLLiquidityOrderAlreadyBeenPlaced(ordersForTokenId)) {
tokensRequiringLiquidity.push(tokenId);
}
else {
log.info(` Liquidity for ${tokenAddress} is given or has been provided in the past`);
}
}
if (tokensRequiringLiquidity) {
log.info(`Attempting to place orders for tokens ${tokensRequiringLiquidity}`);
const successTokens = yield fee_token_liquidity_1.placeFeeTokenLiquidityOrders(exchange, tokensRequiringLiquidity, PRICE_FOR_PROVISION, SELL_AMOUNT_OWL, artifacts);
if (successTokens && successTokens.length) {
log.info(`Successfully placed fee token liquidity orders for tokens: ${successTokens}`);
}
// This scenario is actually quite common. In fact, always
// happens once a non-ERC20 token has been registered on exchange.
const failedTokens = tokensRequiringLiquidity.filter((x) => !successTokens.includes(x));
if (failedTokens && failedTokens.length) {
log.warn(`No orders placed for ${failedTokens} (Likely not ERC20s on this network).`);
}
}
else {
log.info("Did not detect any tokens requiring liquidity");
}
callback();
}
catch (error) {
callback(error);
}
});