@melonproject/protocol
Version:
Technology Regulated and Operated Investment Funds
326 lines (325 loc) • 20.7 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const initTestEnvironment_1 = require("../utils/initTestEnvironment");
const deployAndGetSystem_1 = require("../utils/deployAndGetSystem");
const randomHexOfSize_1 = require("../../utils/helpers/randomHexOfSize");
const orderSignatures_1 = require("../../utils/constants/orderSignatures");
const token_math_1 = require("@melonproject/token-math");
const updateTestingPriceFeed_1 = require("../utils/updateTestingPriceFeed");
const getAllBalances_1 = require("../utils/getAllBalances");
const beginSetup_1 = require("../../contracts/factory/transactions/beginSetup");
const getToken_1 = require("../../contracts/dependencies/token/calls/getToken");
const Contracts_1 = require("../../Contracts");
const completeSetup_1 = require("../../contracts/factory/transactions/completeSetup");
const createAccounting_1 = require("../../contracts/factory/transactions/createAccounting");
const createFeeManager_1 = require("../../contracts/factory/transactions/createFeeManager");
const createParticipation_1 = require("../../contracts/factory/transactions/createParticipation");
const createPolicyManager_1 = require("../../contracts/factory/transactions/createPolicyManager");
const createShares_1 = require("../../contracts/factory/transactions/createShares");
const createTrading_1 = require("../../contracts/factory/transactions/createTrading");
const createVault_1 = require("../../contracts/factory/transactions/createVault");
const getFundComponents_1 = require("../../utils/getFundComponents");
const withDifferentAccount_1 = require("../../utils/environment/withDifferentAccount");
const increaseTime_1 = require("../../utils/evm/increaseTime");
const precisionUnits = token_math_1.power(new token_math_1.BigInteger(10), new token_math_1.BigInteger(18));
let s = {};
beforeAll(() => __awaiter(this, void 0, void 0, function* () {
s.environment = yield initTestEnvironment_1.initTestEnvironment();
s.accounts = yield s.environment.eth.getAccounts();
const { addresses, contracts } = yield deployAndGetSystem_1.deployAndGetSystem(s.environment);
s.addresses = addresses;
s = Object.assign(s, contracts);
[s.deployer, s.manager, s.investor] = s.accounts;
s.exchanges = [s.matchingMarket];
s.gas = 8000000;
s.numberofExchanges = 1;
s.exchanges = [s.matchingMarket];
s.mlnTokenInterface = yield getToken_1.getToken(s.environment, s.mln.options.address);
s.wethTokenInterface = yield getToken_1.getToken(s.environment, s.weth.options.address);
const exchangeConfigs = {
[Contracts_1.Exchanges.MatchingMarket]: {
adapter: s.matchingMarketAdapter.options.address,
exchange: s.matchingMarket.options.address,
takesCustody: true,
},
};
const envManager = withDifferentAccount_1.withDifferentAccount(s.environment, s.manager);
yield beginSetup_1.beginSetup(envManager, s.version.options.address, {
defaultTokens: [s.wethTokenInterface],
exchangeConfigs,
fees: [],
fundName: 'Test fund',
quoteToken: s.wethTokenInterface,
});
yield createAccounting_1.createAccounting(envManager, s.version.options.address);
yield createFeeManager_1.createFeeManager(envManager, s.version.options.address);
yield createParticipation_1.createParticipation(envManager, s.version.options.address);
yield createPolicyManager_1.createPolicyManager(envManager, s.version.options.address);
yield createShares_1.createShares(envManager, s.version.options.address);
yield createTrading_1.createTrading(envManager, s.version.options.address);
yield createVault_1.createVault(envManager, s.version.options.address);
const hubAddress = yield completeSetup_1.completeSetup(envManager, s.version.options.address);
s.fund = yield getFundComponents_1.getFundComponents(envManager, hubAddress);
yield updateTestingPriceFeed_1.updateTestingPriceFeed(s, s.environment);
const [referencePrice] = Object.values(yield s.priceSource.methods
.getReferencePriceInfo(s.weth.options.address, s.mln.options.address)
.call()).map(e => new token_math_1.BigInteger(e));
const sellQuantity1 = token_math_1.power(new token_math_1.BigInteger(10), new token_math_1.BigInteger(20));
s.trade1 = {
buyQuantity: token_math_1.divide(token_math_1.multiply(referencePrice, sellQuantity1), precisionUnits),
sellQuantity: sellQuantity1,
};
const sellQuantity2 = new token_math_1.BigInteger(5 * Math.pow(10, 16));
s.trade2 = {
buyQuantity: token_math_1.divide(token_math_1.multiply(referencePrice, sellQuantity2), precisionUnits),
sellQuantity: sellQuantity2,
};
// Register price tolerance policy
const priceTolerance = s.priceTolerance;
yield expect(s.fund.policyManager.methods
.register(orderSignatures_1.makeOrderSignatureBytes, priceTolerance.options.address)
.send({ from: s.manager })).resolves.not.toThrow();
yield expect(s.fund.policyManager.methods
.register(orderSignatures_1.takeOrderSignatureBytes, priceTolerance.options.address)
.send({ from: s.manager })).resolves.not.toThrow();
}));
test('Transfer ethToken to the investor', () => __awaiter(this, void 0, void 0, function* () {
const initialTokenAmount = token_math_1.power(new token_math_1.BigInteger(10), new token_math_1.BigInteger(21));
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
yield s.weth.methods
.transfer(s.investor, `${initialTokenAmount}`)
.send({ from: s.deployer });
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
expect(post.investor.weth).toEqual(token_math_1.add(pre.investor.weth, initialTokenAmount));
}));
Array.from(Array(s.numberofExchanges).keys()).forEach(i => {
test(`fund gets ETH Token from investment [round ${i + 1}]`, () => __awaiter(this, void 0, void 0, function* () {
const wantedShares = token_math_1.power(new token_math_1.BigInteger(10), new token_math_1.BigInteger(20));
// const pre = await getAllBalances(s, s.accounts, s.fund, s.environment);
const preTotalSupply = yield s.fund.shares.methods.totalSupply().call();
yield s.weth.methods
.approve(s.fund.participation.options.address, wantedShares)
.send({ from: s.investor, gas: s.gas });
yield s.fund.participation.methods
.requestInvestment(`${wantedShares}`, `${wantedShares}`, s.weth.options.address)
.send({ from: s.investor, gas: s.gas, value: '10000000000000000' });
yield updateTestingPriceFeed_1.updateTestingPriceFeed(s, s.environment);
yield updateTestingPriceFeed_1.updateTestingPriceFeed(s, s.environment);
yield s.fund.participation.methods
.executeRequestFor(s.investor)
.send({ from: s.investor, gas: s.gas });
// const post = await getAllBalances(s, s.accounts, s.fund, s.environment);
const postTotalSupply = yield s.fund.shares.methods.totalSupply().call();
expect(postTotalSupply).toEqual(token_math_1.add(token_math_1.toBI(preTotalSupply), wantedShares));
}));
test(`Exchange ${i +
1}: manager makes order, sellToken sent to exchange`, () => __awaiter(this, void 0, void 0, function* () {
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePreMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePreEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
const preIsMlnInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.mln.options.address)
.call();
yield s.fund.trading.methods
.callOnExchange(i, orderSignatures_1.makeOrderSignature, [
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
s.weth.options.address,
s.mln.options.address,
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
], [
`${s.trade1.sellQuantity}`,
`${s.trade1.buyQuantity}`,
0,
0,
0,
0,
0,
0,
], randomHexOfSize_1.randomHexOfSize(20), '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas });
const exchangePostMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePostEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const postIsMlnInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.mln.options.address)
.call();
const openOrdersAgainstMln = yield s.fund.trading.methods
.openMakeOrdersAgainstAsset(s.mln.options.address)
.call();
expect(exchangePostMln).toEqual(exchangePreMln);
expect(exchangePostEthToken).toEqual(token_math_1.add(exchangePreEthToken, token_math_1.toBI(s.trade1.sellQuantity)));
expect(post.fund.weth).toEqual(pre.fund.weth);
expect(post.deployer.mln).toEqual(pre.deployer.mln);
expect(postIsMlnInAssetList).toBeTruthy();
expect(preIsMlnInAssetList).toBeFalsy();
expect(Number(openOrdersAgainstMln)).toEqual(1);
}));
test(`Exchange ${i +
1}: anticipated taker asset is not removed from owned assets`, () => __awaiter(this, void 0, void 0, function* () {
yield s.fund.accounting.methods
.performCalculations()
.send({ from: s.manager, gas: s.gas });
yield s.fund.accounting.methods
.updateOwnedAssets()
.send({ from: s.manager, gas: s.gas });
const isMlnInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.mln.options.address)
.call();
expect(isMlnInAssetList).toBeTruthy();
}));
test(`Exchange ${i +
1}: third party takes entire order, allowing fund to receive mlnToken`, () => __awaiter(this, void 0, void 0, function* () {
const orderId = yield s.exchanges[i].methods.last_offer_id().call();
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePreMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePreEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
yield s.mln.methods
.approve(s.exchanges[i].options.address, `${s.trade1.buyQuantity}`)
.send({ from: s.deployer, gasPrice: 8000000 });
yield s.exchanges[i].methods
.buy(orderId, `${s.trade1.sellQuantity}`)
.send({ from: s.deployer, gas: s.gas });
yield s.fund.trading.methods
.returnBatchToVault([s.mln.options.address, s.weth.options.address])
.send({ from: s.manager, gas: s.gas });
const exchangePostMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePostEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
expect(exchangePostMln).toEqual(exchangePreMln);
expect(exchangePostEthToken).toEqual(token_math_1.subtract(exchangePreEthToken, token_math_1.toBI(s.trade1.sellQuantity)));
expect(post.fund.weth).toEqual(token_math_1.subtract(pre.fund.weth, token_math_1.toBI(s.trade1.sellQuantity)));
expect(post.fund.mln).toEqual(token_math_1.add(pre.fund.mln, token_math_1.toBI(s.trade1.buyQuantity)));
expect(post.deployer.weth).toEqual(token_math_1.add(pre.deployer.weth, token_math_1.toBI(s.trade1.sellQuantity)));
expect(post.deployer.mln).toEqual(token_math_1.subtract(pre.deployer.mln, token_math_1.toBI(s.trade1.buyQuantity)));
}));
test(`Exchange ${i +
// tslint:disable-next-line:max-line-length
1}: third party makes order (sell ETH-T for MLN-T),and ETH-T is transferred to exchange`, () => __awaiter(this, void 0, void 0, function* () {
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePreMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePreEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
yield s.weth.methods
.approve(s.exchanges[i].options.address, `${s.trade2.sellQuantity}`)
.send({ from: s.deployer, gas: s.gas });
yield s.exchanges[i].methods
.offer(`${s.trade2.sellQuantity}`, s.weth.options.address, `${s.trade2.buyQuantity}`, s.mln.options.address)
.send({ from: s.deployer, gas: s.gas });
const exchangePostMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePostEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
expect(exchangePostMln).toEqual(exchangePreMln);
expect(exchangePostEthToken).toEqual(token_math_1.add(exchangePreEthToken, token_math_1.toBI(s.trade2.sellQuantity)));
expect(post.deployer.weth).toEqual(token_math_1.subtract(pre.deployer.weth, token_math_1.toBI(s.trade2.sellQuantity)));
expect(post.deployer.mln).toEqual(pre.deployer.mln);
}));
test(`Exchange ${i +
1}: manager takes order (buys ETH-T for MLN-T)`, () => __awaiter(this, void 0, void 0, function* () {
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePreMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePreEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
const orderId = yield s.exchanges[i].methods.last_offer_id().call();
yield s.fund.trading.methods
.callOnExchange(i, orderSignatures_1.takeOrderSignature, [
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
s.weth.options.address,
s.mln.options.address,
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
], [0, 0, 0, 0, 0, 0, `${s.trade2.buyQuantity}`, 0], `0x${Number(orderId)
.toString(16)
.padStart(64, '0')}`, '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas });
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePostMln = new token_math_1.BigInteger(yield s.mln.methods.balanceOf(s.exchanges[i].options.address).call());
const exchangePostEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
expect(exchangePostMln).toEqual(exchangePreMln);
expect(exchangePostEthToken).toEqual(token_math_1.subtract(exchangePreEthToken, token_math_1.toBI(s.trade2.sellQuantity)));
expect(post.deployer.mln).toEqual(token_math_1.add(pre.deployer.mln, token_math_1.toBI(s.trade2.buyQuantity)));
expect(post.fund.mln).toEqual(token_math_1.subtract(pre.fund.mln, token_math_1.toBI(s.trade2.buyQuantity)));
expect(post.fund.weth).toEqual(token_math_1.add(pre.fund.weth, token_math_1.toBI(s.trade2.sellQuantity)));
expect(post.fund.ether).toEqual(pre.fund.ether);
}));
test(`Exchange ${i + 1}: manager makes an order and cancels it`, () => __awaiter(this, void 0, void 0, function* () {
yield increaseTime_1.increaseTime(s.environment, 60 * 30);
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePreEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
yield s.fund.trading.methods
.returnBatchToVault([s.mln.options.address, s.weth.options.address])
.send({ from: s.manager, gas: s.gas });
yield s.fund.accounting.methods
.updateOwnedAssets()
.send({ from: s.manager, gas: s.gas });
yield s.fund.trading.methods
.callOnExchange(i, orderSignatures_1.makeOrderSignature, [
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
s.weth.options.address,
s.mln.options.address,
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
], [
`${s.trade2.sellQuantity}`,
`${s.trade2.buyQuantity}`,
0,
0,
0,
0,
0,
0,
], randomHexOfSize_1.randomHexOfSize(20), '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas });
const orderId = yield s.exchanges[i].methods.last_offer_id().call();
yield s.fund.trading.methods
.callOnExchange(i, orderSignatures_1.cancelOrderSignature, [
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
s.weth.options.address,
s.mln.options.address,
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
], [0, 0, 0, 0, 0, 0, 0, 0], `0x${Number(orderId)
.toString(16)
.padStart(64, '0')}`, '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas });
const orderOpen = yield s.exchanges[i].methods.isActive(orderId).call();
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const exchangePostEthToken = new token_math_1.BigInteger(yield s.weth.methods.balanceOf(s.exchanges[i].options.address).call());
expect(orderOpen).toBeFalsy();
expect(exchangePostEthToken).toEqual(exchangePreEthToken);
expect(post.fund.mln).toEqual(pre.fund.mln);
expect(post.fund.weth).toEqual(pre.fund.weth);
}));
test(`Exchange ${i +
1}: Risk management prevents from taking an ill-priced order`, () => __awaiter(this, void 0, void 0, function* () {
yield s.weth.methods
.approve(s.exchanges[i].options.address, `${s.trade2.sellQuantity}`)
.send({ from: s.deployer, gas: s.gas });
yield s.exchanges[i].methods
.offer(`${token_math_1.divide(s.trade2.sellQuantity, 2)}`, s.weth.options.address, `${s.trade2.buyQuantity}`, s.mln.options.address)
.send({ from: s.deployer, gas: s.gas });
const orderId = yield s.exchanges[i].methods.last_offer_id().call();
yield expect(s.fund.trading.methods
.callOnExchange(i, orderSignatures_1.takeOrderSignature, [
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
s.weth.options.address,
s.mln.options.address,
randomHexOfSize_1.randomHexOfSize(20),
randomHexOfSize_1.randomHexOfSize(20),
], [0, 0, 0, 0, 0, 0, `${s.trade2.buyQuantity}`, 0], `0x${Number(orderId)
.toString(16)
.padStart(64, '0')}`, '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas })).rejects.toThrow();
}));
});