@melonproject/protocol
Version:
Technology Regulated and Operated Investment Funds
326 lines (325 loc) • 17.8 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 signOrder_1 = require("../../contracts/exchanges/third-party/0x/utils/signOrder");
const order_utils_1 = require("@0x/order-utils");
const getAssetProxy_1 = require("../../contracts/exchanges/third-party/0x/calls/getAssetProxy");
const token_math_1 = require("@melonproject/token-math");
const updateTestingPriceFeed_1 = require("../utils/updateTestingPriceFeed");
const getAllBalances_1 = require("../utils/getAllBalances");
const initTestEnvironment_1 = require("../utils/initTestEnvironment");
const deployAndGetSystem_1 = require("../utils/deployAndGetSystem");
const getToken_1 = require("../../contracts/dependencies/token/calls/getToken");
const beginSetup_1 = require("../../contracts/factory/transactions/beginSetup");
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 randomHexOfSize_1 = require("../../utils/helpers/randomHexOfSize");
const Contracts_1 = require("../../Contracts");
const withDifferentAccount_1 = require("../../utils/environment/withDifferentAccount");
const deployContract_1 = require("../../utils/solidity/deployContract");
const getContract_1 = require("../../utils/solidity/getContract");
const bignumber_js_1 = require("bignumber.js");
const orderSignatures_1 = require("../../utils/constants/orderSignatures");
const fillOrder_1 = require("../../contracts/exchanges/third-party/0x/transactions/fillOrder");
const createOrder_1 = require("../../contracts/exchanges/third-party/0x/utils/createOrder");
const evm_1 = require("../../utils/evm");
// mock data
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
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.gas = 8000000;
s.opts = { from: s.deployer, gas: s.gas };
s.erc20ProxyAddress = (yield getAssetProxy_1.getAssetProxy(s.environment, s.ethfinex.options.address)).toString();
s.mlnTokenInterface = yield getToken_1.getToken(s.environment, s.mln.options.address);
s.wethTokenInterface = yield getToken_1.getToken(s.environment, s.weth.options.address);
s.dgxTokenInterface = yield getToken_1.getToken(s.environment, s.dgx.options.address);
const exchangeConfigs = {
[Contracts_1.Exchanges.Ethfinex]: {
adapter: s.ethfinexAdapter.options.address,
exchange: s.ethfinex.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, s.mlnTokenInterface],
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 wrapperRegistryAddress = yield deployContract_1.deployContract(s.environment, Contracts_1.Contracts.WrapperRegistryEFX, []);
const wrapperRegistry = yield getContract_1.getContract(s.environment, Contracts_1.Contracts.WrapperRegistryEFX, wrapperRegistryAddress);
s.ethTokenWrapper = yield getToken_1.getToken(s.environment, yield deployContract_1.deployContract(s.environment, Contracts_1.Contracts.WrapperLockEth, [
'WETH',
'WETH Token',
18,
s.ethfinex.options.address,
s.erc20ProxyAddress,
]));
s.mlnTokenWrapper = yield getToken_1.getToken(s.environment, yield deployContract_1.deployContract(s.environment, Contracts_1.Contracts.WrapperLock, [
s.mln.options.address,
'MLN',
'Melon',
18,
false,
s.ethfinex.options.address,
s.erc20ProxyAddress,
]));
yield wrapperRegistry.methods
.addNewWrapperPair([s.weth.options.address, s.mln.options.address], [s.ethTokenWrapper.address, s.mlnTokenWrapper.address])
.send({ from: s.deployer, gas: s.gas });
yield s.registry.methods
.setEthfinexWrapperRegistry(wrapperRegistry.options.address)
.send({ from: s.deployer, gas: s.gas });
}));
const initialTokenAmount = new token_math_1.BigInteger(Math.pow(10, 19));
test('investor gets initial ethToken for testing)', () => __awaiter(this, void 0, void 0, function* () {
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
yield s.weth.methods
.transfer(s.investor, `${initialTokenAmount}`)
.send(s.opts);
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));
}));
// tslint:disable-next-line:max-line-length
test('fund receives ETH from investment, and gets ZRX from direct transfer', () => __awaiter(this, void 0, void 0, function* () {
const offeredValue = new token_math_1.BigInteger(Math.pow(10, 18));
const wantedShares = new token_math_1.BigInteger(Math.pow(10, 18));
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
yield s.weth.methods
.approve(s.fund.participation.options.address, `${offeredValue}`)
.send({ from: s.investor, gas: s.gas });
yield s.fund.participation.methods
.requestInvestment(`${offeredValue}`, `${wantedShares}`, s.weth.options.address)
.send({ from: s.investor, gas: s.gas, value: '10000000000000000' });
yield s.fund.participation.methods
.executeRequestFor(s.investor)
.send({ from: s.investor, gas: s.gas });
yield s.zrx.methods
.transfer(s.fund.vault.options.address, `${initialTokenAmount}`)
.send({ from: s.deployer, gas: s.gas });
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
expect(post.investor.weth).toEqual(token_math_1.subtract(pre.investor.weth, offeredValue));
expect(post.fund.weth).toEqual(token_math_1.add(pre.fund.weth, offeredValue));
}));
test('Make order through the fund', () => __awaiter(this, void 0, void 0, function* () {
yield s.mln.methods
.transfer(s.fund.vault.options.address, new bignumber_js_1.BigNumber(Math.pow(10, 18)).toFixed())
.send({ from: s.deployer, gas: s.gas });
const makerAddress = s.fund.trading.options.address.toLowerCase();
const makerQuantity = token_math_1.createQuantity(s.mlnTokenWrapper, 1);
const takerQuantity = token_math_1.createQuantity(s.wethTokenInterface, 0.1);
const order = yield createOrder_1.createOrder(s.environment, s.ethfinex.options.address, {
makerAddress,
makerQuantity,
takerQuantity,
});
const orderHashHex = order_utils_1.orderHashUtils.getOrderHashHex(order);
s.signedOrder = yield signOrder_1.signOrder(s.environment, order, s.manager);
const preCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
yield s.fund.trading.methods
.callOnExchange(0, orderSignatures_1.makeOrderSignature, [
makerAddress,
NULL_ADDRESS,
s.mln.options.address,
s.weth.options.address,
order.feeRecipientAddress,
NULL_ADDRESS,
], [
order.makerAssetAmount.toFixed(),
order.takerAssetAmount.toFixed(),
order.makerFee.toFixed(),
order.takerFee.toFixed(),
order.expirationTimeSeconds.toFixed(),
order.salt.toFixed(),
0,
0,
], randomHexOfSize_1.randomHexOfSize(20), order.makerAssetData, order.takerAssetData, s.signedOrder.signature)
.send({ from: s.manager, gas: s.gas });
const postCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
const isValidSignatureBeforeMake = yield s.ethfinex.methods
.isValidSignature(orderHashHex, s.fund.trading.options.address, s.signedOrder.signature)
.call();
expect(isValidSignatureBeforeMake).toBeTruthy();
expect(postCalculations.gav).toBe(preCalculations.gav);
expect(postCalculations.sharePrice).toBe(preCalculations.sharePrice);
}));
test('Third party takes the order made by the fund', () => __awaiter(this, void 0, void 0, function* () {
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const mlnWrapperContract = yield getContract_1.getContract(s.environment, Contracts_1.Contracts.WrapperLock, s.mlnTokenWrapper.address);
const preDeployerWrappedMLN = new token_math_1.BigInteger(yield mlnWrapperContract.methods.balanceOf(s.deployer).call());
const result = yield fillOrder_1.fillOrder(s.environment, s.ethfinex.options.address, {
signedOrder: s.signedOrder,
});
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const postDeployerWrappedMLN = new token_math_1.BigInteger(yield mlnWrapperContract.methods.balanceOf(s.deployer).call());
expect(result).toBeTruthy();
expect(post.fund.mln).toEqual(token_math_1.subtract(pre.fund.mln, token_math_1.toBI(s.signedOrder.makerAssetAmount)));
expect(post.fund.weth).toEqual(token_math_1.add(pre.fund.weth, token_math_1.toBI(s.signedOrder.takerAssetAmount)));
expect(postDeployerWrappedMLN).toEqual(token_math_1.add(preDeployerWrappedMLN, token_math_1.toBI(s.signedOrder.makerAssetAmount)));
expect(post.deployer.weth).toEqual(token_math_1.subtract(pre.deployer.weth, token_math_1.toBI(s.signedOrder.takerAssetAmount)));
}));
// tslint:disable-next-line:max-line-length
test('Make order with native asset', () => __awaiter(this, void 0, void 0, function* () {
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const preCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
const preIsDgxInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.dgx.options.address)
.call();
const makerAddress = s.fund.trading.options.address.toLowerCase();
const makerQuantity = token_math_1.createQuantity(s.ethTokenWrapper, 0.05);
const takerQuantity = token_math_1.createQuantity(s.dgxTokenInterface, 0.5);
s.unsignedOrder = yield createOrder_1.createOrder(s.environment, s.zeroExExchange.options.address, {
feeRecipientAddress: s.investor,
makerAddress,
makerQuantity,
takerQuantity,
});
s.signedOrder = yield signOrder_1.signOrder(s.environment, s.unsignedOrder, s.manager);
yield s.fund.trading.methods
.callOnExchange(0, orderSignatures_1.makeOrderSignature, [
makerAddress,
NULL_ADDRESS,
s.weth.options.address,
s.dgx.options.address,
s.signedOrder.feeRecipientAddress,
NULL_ADDRESS,
], [
s.signedOrder.makerAssetAmount.toFixed(),
s.signedOrder.takerAssetAmount.toFixed(),
s.signedOrder.makerFee.toFixed(),
s.signedOrder.takerFee.toFixed(),
s.signedOrder.expirationTimeSeconds.toFixed(),
s.signedOrder.salt.toFixed(),
0,
0,
], randomHexOfSize_1.randomHexOfSize(20), s.signedOrder.makerAssetData, s.signedOrder.takerAssetData, s.signedOrder.signature)
.send({ from: s.manager, gas: s.gas });
const post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const postCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
const postIsDgxInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.dgx.options.address)
.call();
const openOrdersAgainstDgx = yield s.fund.trading.methods
.openMakeOrdersAgainstAsset(s.dgx.options.address)
.call();
expect(postCalculations.gav).toBe(preCalculations.gav);
expect(postCalculations.sharePrice).toBe(preCalculations.sharePrice);
expect(post.fund.weth).toEqual(pre.fund.weth);
expect(postIsDgxInAssetList).toBeTruthy();
expect(preIsDgxInAssetList).toBeFalsy();
expect(Number(openOrdersAgainstDgx)).toEqual(1);
}));
test('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 isDgxInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.dgx.options.address)
.call();
expect(isDgxInAssetList).toBeTruthy();
}));
test('Cancel the order and withdraw tokens', () => __awaiter(this, void 0, void 0, function* () {
const orderHashHex = order_utils_1.orderHashUtils.getOrderHashHex(s.signedOrder);
const pre = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const preCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
yield s.fund.trading.methods
.callOnExchange(0, orderSignatures_1.cancelOrderSignature, [
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
], [0, 0, 0, 0, 0, 0, 0, 0], orderHashHex, '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas });
const isOrderCancelled = yield s.zeroExExchange.methods
.cancelled(orderHashHex)
.call();
expect(isOrderCancelled).toBeTruthy();
const preWithdraw = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const preWithdrawCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
// Withdraw WETH
yield evm_1.increaseTime(s.environment, 25 * 60 * 60);
yield s.fund.trading.methods
.callOnExchange(0, orderSignatures_1.withdrawTokensSignature, [
s.weth.options.address,
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
NULL_ADDRESS,
], [0, 0, 0, 0, 0, 0, 0, 0], '0x0', '0x0', '0x0', '0x0')
.send({ from: s.manager, gas: s.gas });
// To Clean up asset list
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 post = yield getAllBalances_1.getAllBalances(s, s.accounts, s.fund, s.environment);
const postCalculations = yield s.fund.accounting.methods
.performCalculations()
.call();
const isDgxInAssetList = yield s.fund.accounting.methods
.isInAssetList(s.dgx.options.address)
.call();
const openOrdersAgainstDgx = yield s.fund.trading.methods
.openMakeOrdersAgainstAsset(s.dgx.options.address)
.call();
expect(post.fund.weth).toEqual(preWithdraw.fund.weth);
expect(preWithdraw.fund.weth).toEqual(pre.fund.weth);
expect(postCalculations.gav).toEqual(preWithdrawCalculations.gav);
expect(preWithdrawCalculations.gav).toEqual(preCalculations.gav);
expect(postCalculations.sharePrice).toEqual(preWithdrawCalculations.sharePrice);
expect(preWithdrawCalculations.sharePrice).toEqual(preCalculations.sharePrice);
expect(isDgxInAssetList).toBeFalsy();
expect(Number(openOrdersAgainstDgx)).toEqual(0);
}));