From 70257a0447c52ef0baaa0af39108c2f64bb08068 Mon Sep 17 00:00:00 2001 From: lacoop6tu Date: Fri, 22 Oct 2021 10:55:05 -0500 Subject: [PATCH] add Router Class and some unit test --- package.json | 2 +- src/factories/NFTFactory.ts | 2 +- src/pools/Router.ts | 378 +++++++++++++++++++++++++++++++++ test/TestContractHandler.ts | 68 +++--- test/unit/NFTFactory.test.ts | 8 +- test/unit/pools/Router.test.ts | 149 +++++++++++++ 6 files changed, 573 insertions(+), 34 deletions(-) create mode 100644 src/pools/Router.ts create mode 100644 test/unit/pools/Router.test.ts diff --git a/package.json b/package.json index 85854213..60966e93 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "release": "release-it --non-interactive", "changelog": "auto-changelog -p", "prepublishOnly": "npm run build", - "test:pool": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/NFTFactory.test.ts'", + "test:pool": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/pools/Router.test.ts'", "test:unit": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/**/*.test.ts'", "test:unit:cover": "nyc --report-dir coverage/unit npm run test:unit", "test:integration": "mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/**/*.test.ts'", diff --git a/src/factories/NFTFactory.ts b/src/factories/NFTFactory.ts index bdadb2fc..469fde0d 100644 --- a/src/factories/NFTFactory.ts +++ b/src/factories/NFTFactory.ts @@ -47,7 +47,7 @@ interface FixedData { uints: (string | number)[] } /** - * Provides an interface for NFT DataTokens + * Provides an interface for NFT Factory contract */ export class NFTFactory { public GASLIMIT_DEFAULT = 1000000 diff --git a/src/pools/Router.ts b/src/pools/Router.ts new file mode 100644 index 00000000..5aa2258e --- /dev/null +++ b/src/pools/Router.ts @@ -0,0 +1,378 @@ +import { Contract } from 'web3-eth-contract' +import Web3 from 'web3' +import { TransactionReceipt } from 'web3-core' +import { AbiItem } from 'web3-utils' +import defaultRouter from '@oceanprotocol/contracts/artifacts/contracts/pools/FactoryRouter.sol/FactoryRouter.json' +import { Logger, getFairGasPrice, generateDtName } from '../utils' + +interface Operations { + exchangeIds: string + source: string + operation: number + tokenIn: string + amountsIn: string | number + tokenOut: string + amountsOut: string | number + maxPrice: string | number +} + +/** + * Provides an interface for FactoryRouter contract + */ +export class Router { + public GASLIMIT_DEFAULT = 1000000 + public routerAddress: string + public RouterABI: AbiItem | AbiItem[] + public web3: Web3 + private logger: Logger + public startBlock: number + public router: Contract + + /** + * Instantiate Router. + * @param {String} routerAddress + * @param {AbiItem | AbiItem[]} Router + * @param {Web3} web3 + */ + constructor( + routerAddress: string, + web3: Web3, + logger: Logger, + RouterABI?: AbiItem | AbiItem[], + startBlock?: number + ) { + this.routerAddress = routerAddress + this.RouterABI = RouterABI || (defaultRouter.abi as AbiItem[]) + this.web3 = web3 + this.logger = logger + this.startBlock = startBlock || 0 + this.router = new this.web3.eth.Contract(this.RouterABI, this.routerAddress) + } + + /** + * BuyDTBatch + * @param {String} address + * @param {Operations} operations Operations objects array + * @return {Promise} Transaction receipt + */ + public async buyDTBatch( + address: string, + operations: Operations[] + ): Promise { + // Get estimated gas value + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .buyDTBatch(operations) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.buyDTBatch(operations).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** Check if a token is on ocean tokens list, if true opfFee is ZERO in pools with that token/DT + * @return {Promise} true if is on the list. + */ + public async isOceanTokens(address: string): Promise { + return await this.router.methods.oceanTokens(address).call() + } + + /** Check if an address is a side staking contract. + * @return {Promise} true if is a SS contract + */ + public async isSideStaking(address: string): Promise { + return await this.router.methods.ssContracts(address).call() + } + + /** Check if an address is a Fixed Rate contract. + * @return {Promise} true if is a Fixed Rate contract + */ + public async isFixedPrice(address: string): Promise { + return await this.router.methods.fixedPrice(address).call() + } + + /** Get Router Owner + * @return {Promise} Router Owner address + */ + public async getOwner(): Promise { + return await this.router.methods.routerOwner().call() + } + + /** Get NFT Factory address + * @return {Promise} NFT Factory address + */ + public async getNFTFactory(): Promise { + return await this.router.methods.factory().call() + } + + /** Check if an address is a pool template contract. + * @return {Promise} true if is a Template + */ + public async isPoolTemplate(address: string): Promise { + return await this.router.methods.isPoolTemplate(address).call() + } + + /** + * Add a new token to oceanTokens list, pools with basetoken in this list have NO opf Fee + * @param {String} address + * @param {String} tokenAddress template address to add + * @return {Promise} + */ + public async addOceanToken( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .addOceanToken(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.addOceanToken(tokenAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Remove a token from oceanTokens list, pools without basetoken in this list have a opf Fee + * @param {String} address + * @param {String} tokenAddress address to remove + * @return {Promise} + */ + public async removeOceanToken( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .removeOceanToken(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.removeOceanToken(tokenAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Add a new contract to ssContract list, after is added, can be used when deploying a new pool + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async addSSContract( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .addSSContract(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.addSSContract(tokenAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Add a new contract to fixedRate list, after is added, can be used when deploying a new pool + * @param {String} address + * @param {String} tokenAddress contract address to add + * @return {Promise} + */ + public async addFixedRateContract( + address: string, + tokenAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .addFixedRateContract(tokenAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.addFixedRateContract(tokenAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** Get OPF Fee per token + * @return {Promise} OPF fee for a specific baseToken + */ + public async getOPFFee(baseToken: string): Promise { + return await this.router.methods.getOPFFee(baseToken).call() + } + + /** Get Current OPF Fee + * @return {Promise} OPF fee + */ + public async getCurrentOPFFee(): Promise { + return await this.router.methods.swapOceanFee().call() + } + + /** + * Add a new contract to fixedRate list, after is added, can be used when deploying a new pool + * @param {String} address + * @param {String} newFee new OPF Fee + * @return {Promise} + */ + public async updateOPFFee( + address: string, + newFee: number + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .updateOPFFee(newFee) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.updateOPFFee(newFee).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Add a new template to poolTemplates mapping, after template is added,it can be used + * @param {String} address + * @param {String} templateAddress template address to add + * @return {Promise} + */ + public async addPoolTemplate( + address: string, + templateAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .addPoolTemplate(templateAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods.addPoolTemplate(templateAddress).send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } + + /** + * Remove template from poolTemplates mapping, after template is removed,it can be used anymore + * @param {String} address + * @param {String} templateAddress template address to remove + * @return {Promise} + */ + public async removePoolTemplate( + address: string, + templateAddress: string + ): Promise { + if ((await this.getOwner()) !== address) { + throw new Error(`Caller is not Router Owner`) + } + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await this.router.methods + .removePoolTemplate(templateAddress) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + // Invoke createToken function of the contract + const trxReceipt = await this.router.methods + .removePoolTemplate(templateAddress) + .send({ + from: address, + gas: estGas + 1, + gasPrice: await getFairGasPrice(this.web3) + }) + + return trxReceipt + } +} diff --git a/test/TestContractHandler.ts b/test/TestContractHandler.ts index 696cc9d6..61a5a084 100644 --- a/test/TestContractHandler.ts +++ b/test/TestContractHandler.ts @@ -163,10 +163,39 @@ export class TestContractHandler { return contract.options.address }) + // DEPLOY OCEAN MOCK + // get est gascost + estGas = await this.MockERC20.deploy({ + data: this.MockERC20Bytecode, + arguments: ['OCEAN', 'OCEAN', 18] + }).estimateGas(function (err, estGas) { + if (err) console.log('DeployContracts: ' + err) + return estGas + }) + // deploy the contract and get it's address + this.oceanAddress = await this.MockERC20.deploy({ + data: this.MockERC20Bytecode, + arguments: ['OCEAN', 'OCEAN', 18] + }) + .send({ + from: owner, + gas: estGas + 1, + gasPrice: '3000000000' + }) + .then(function (contract) { + return contract.options.address + }) + // DEPLOY ROUTER estGas = await this.Router.deploy({ data: this.RouterBytecode, - arguments: [owner, oceanAddress, this.poolTemplateAddress, communityCollector, []] + arguments: [ + owner, + this.oceanAddress, + this.poolTemplateAddress, + communityCollector, + [] + ] }).estimateGas(function (err, estGas) { if (err) console.log('DeployContracts: ' + err) return estGas @@ -174,7 +203,13 @@ export class TestContractHandler { // deploy the contract and get it's address this.routerAddress = await this.Router.deploy({ data: this.RouterBytecode, - arguments: [owner, oceanAddress, this.poolTemplateAddress, communityCollector, []] + arguments: [ + owner, + this.oceanAddress, + this.poolTemplateAddress, + communityCollector, + [] + ] }) .send({ from: owner, @@ -283,29 +318,6 @@ export class TestContractHandler { return contract.options.address }) - // DEPLOY OCEAN MOCK - // get est gascost - estGas = await this.MockERC20.deploy({ - data: this.MockERC20Bytecode, - arguments: ['OCEAN', 'OCEAN', 18] - }).estimateGas(function (err, estGas) { - if (err) console.log('DeployContracts: ' + err) - return estGas - }) - // deploy the contract and get it's address - this.oceanAddress = await this.MockERC20.deploy({ - data: this.MockERC20Bytecode, - arguments: ['OCEAN', 'OCEAN', 18] - }) - .send({ - from: owner, - gas: estGas + 1, - gasPrice: '3000000000' - }) - .then(function (contract) { - return contract.options.address - }) - // DEPLOY USDC MOCK // get est gascost estGas = await this.MockERC20.deploy({ @@ -366,8 +378,8 @@ export class TestContractHandler { .send({ from: owner }) // TODO: add OPF deployment and update argument // TODO: how are we going to call those functions with an OPF contract? it should be a multisig the owner - await RouterContract.methods - .changeRouterOwner(communityCollector) - .send({ from: owner }) + // await RouterContract.methods + // .changeRouterOwner(communityCollector) + // .send({ from: owner }) } } diff --git a/test/unit/NFTFactory.test.ts b/test/unit/NFTFactory.test.ts index 6acbf172..416e4fb1 100644 --- a/test/unit/NFTFactory.test.ts +++ b/test/unit/NFTFactory.test.ts @@ -114,7 +114,7 @@ describe('NFT Factory test', () => { it('#disableNFTTemplate - should disable NFT template if factory owner', async () => { let nftTemplate = await nftFactory.getNFTTemplate(2) assert(nftTemplate.isActive === true) - await nftFactory.disableNFTTemplate(contracts.accounts[0], 2) // owner disable template index = 2 + await nftFactory.disableNFTTemplate(contracts.accounts[0], 2) // owner disables template index = 2 nftTemplate = await nftFactory.getNFTTemplate(2) assert(nftTemplate.isActive === false) @@ -122,7 +122,7 @@ describe('NFT Factory test', () => { it('#reactivateNFTTemplate - should disable NFT template if factory owner', async () => { let nftTemplate = await nftFactory.getNFTTemplate(2) assert(nftTemplate.isActive === false) - await nftFactory.reactivateNFTTemplate(contracts.accounts[0], 2) // owner reactivate template index = 2 + await nftFactory.reactivateNFTTemplate(contracts.accounts[0], 2) // owner reactivates template index = 2 nftTemplate = await nftFactory.getNFTTemplate(2) assert(nftTemplate.isActive === true) @@ -139,7 +139,7 @@ describe('NFT Factory test', () => { it('#disableTokenTemplate - should disable Token template if factory owner', async () => { let tokenTemplate = await nftFactory.getTokenTemplate(2) assert(tokenTemplate.isActive === true) - await nftFactory.disableTokenTemplate(contracts.accounts[0], 2) // owner disable template index = 2 + await nftFactory.disableTokenTemplate(contracts.accounts[0], 2) // owner disables template index = 2 tokenTemplate = await nftFactory.getTokenTemplate(2) assert(tokenTemplate.isActive === false) @@ -147,7 +147,7 @@ describe('NFT Factory test', () => { it('#reactivateTokenTemplate - should disable Token template if factory owner', async () => { let tokenTemplate = await nftFactory.getTokenTemplate(2) assert(tokenTemplate.isActive === false) - await nftFactory.reactivateTokenTemplate(contracts.accounts[0], 2) // owner reactivate template index = 2 + await nftFactory.reactivateTokenTemplate(contracts.accounts[0], 2) // owner reactivates template index = 2 tokenTemplate = await nftFactory.getTokenTemplate(2) assert(tokenTemplate.isActive === true) diff --git a/test/unit/pools/Router.test.ts b/test/unit/pools/Router.test.ts new file mode 100644 index 00000000..dc927a8d --- /dev/null +++ b/test/unit/pools/Router.test.ts @@ -0,0 +1,149 @@ +import { assert, expect } from 'chai' +import { AbiItem } from 'web3-utils/types' +import { TestContractHandler } from '../../TestContractHandler' +import Web3 from 'web3' +import ERC721Factory from '@oceanprotocol/contracts/artifacts/contracts/ERC721Factory.sol/ERC721Factory.json' +import ERC721Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC721Template.sol/ERC721Template.json' +import SideStaking from '@oceanprotocol/contracts/artifacts/contracts/pools/ssContracts/SideStaking.sol/SideStaking.json' +import FactoryRouter from '@oceanprotocol/contracts/artifacts/contracts/pools/FactoryRouter.sol/FactoryRouter.json' +import ERC20Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json' +import Dispenser from '@oceanprotocol/contracts/artifacts/contracts/pools/dispenser/Dispenser.sol/Dispenser.json' +import FixedRate from '@oceanprotocol/contracts/artifacts/contracts/pools/fixedRate/FixedRateExchange.sol/FixedRateExchange.json' +import MockERC20 from '@oceanprotocol/contracts/artifacts/contracts/utils/mock/MockERC20Decimals.sol/MockERC20Decimals.json' +import PoolTemplate from '@oceanprotocol/contracts/artifacts/contracts/pools/balancer/BPool.sol/BPool.json' +import { LoggerInstance } from '../../../src/utils' +// import { NFTDataToken } from '../../../src/datatokens/NFTDatatoken' +import { Router } from '../../../src/pools/Router' + +const web3 = new Web3('http://127.0.0.1:8545') +const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75' + +describe('Router unit test', () => { + let factoryOwner: string + let nftOwner: string + let user1: string + let user2: string + let user3: string + let contracts: TestContractHandler + let router: Router + let dtAddress: string + let dtAddress2: string + let nftAddress: string + + it('should deploy contracts', async () => { + contracts = new TestContractHandler( + web3, + ERC721Template.abi as AbiItem[], + ERC20Template.abi as AbiItem[], + PoolTemplate.abi as AbiItem[], + ERC721Factory.abi as AbiItem[], + FactoryRouter.abi as AbiItem[], + SideStaking.abi as AbiItem[], + FixedRate.abi as AbiItem[], + Dispenser.abi as AbiItem[], + + ERC721Template.bytecode, + ERC20Template.bytecode, + PoolTemplate.bytecode, + ERC721Factory.bytecode, + FactoryRouter.bytecode, + SideStaking.bytecode, + FixedRate.bytecode, + Dispenser.bytecode + ) + await contracts.getAccounts() + factoryOwner = contracts.accounts[0] + nftOwner = contracts.accounts[1] + user1 = contracts.accounts[2] + user2 = contracts.accounts[3] + user3 = contracts.accounts[4] + + await contracts.deployContracts(factoryOwner, FactoryRouter.abi as AbiItem[]) + + const daiContract = new web3.eth.Contract( + contracts.MockERC20.options.jsonInterface, + contracts.daiAddress + ) + await daiContract.methods + .approve(contracts.factory721Address, web3.utils.toWei('10000')) + .send({ from: contracts.accounts[0] }) + }) + + it('should initiate Router instance', async () => { + router = new Router(contracts.routerAddress, web3, LoggerInstance) + }) + + it('#getOwner - should return actual owner', async () => { + const owner = await router.getOwner() + assert(owner === contracts.accounts[0]) + }) + + it('#getNFTFactory - should return NFT Factory address', async () => { + const factory = await router.getNFTFactory() + assert(factory === contracts.factory721Address) + }) + + it('#isOceanTokens - should return true if in oceanTokens list', async () => { + expect(await router.isOceanTokens(contracts.oceanAddress)).to.equal(true) + expect(await router.isOceanTokens(contracts.daiAddress)).to.equal(false) + }) + it('#isSideStaking - should return true if in ssContracts list', async () => { + expect(await router.isSideStaking(contracts.sideStakingAddress)).to.equal(true) + expect(await router.isSideStaking(contracts.fixedRateAddress)).to.equal(false) + }) + it('#isFixedPrice - should return true if in fixedPrice list', async () => { + expect(await router.isFixedPrice(contracts.fixedRateAddress)).to.equal(true) + expect(await router.isFixedPrice(contracts.daiAddress)).to.equal(false) + // Dispenser contract is also a fixed price contract + expect(await router.isFixedPrice(contracts.dispenserAddress)).to.equal(true) + }) + it('#isPoolTemplate - should return true if in poolTemplates list', async () => { + expect(await router.isPoolTemplate(contracts.poolTemplateAddress)).to.equal(true) + expect(await router.isPoolTemplate(contracts.fixedRateAddress)).to.equal(false) + }) + it('#addOceanToken - should add a new token into oceanTokens list(NO OPF FEE)', async () => { + await router.addOceanToken(contracts.accounts[0], contracts.daiAddress) + expect(await router.isOceanTokens(contracts.daiAddress)).to.equal(true) + }) + it('#removeOceanToken - should remove a token from oceanTokens list', async () => { + await router.removeOceanToken(contracts.accounts[0], contracts.daiAddress) + expect(await router.isOceanTokens(contracts.daiAddress)).to.equal(false) + }) + it('#addSSContract - should add a new token into SSContracts list', async () => { + await router.addSSContract(contracts.accounts[0], contracts.daiAddress) + expect(await router.isSideStaking(contracts.daiAddress)).to.equal(true) + }) + it('#addFixedRate - should add a new token into fixedPrice list', async () => { + await router.addFixedRateContract(contracts.accounts[0], contracts.daiAddress) + expect(await router.isFixedPrice(contracts.daiAddress)).to.equal(true) + }) + + it('#getOPFFee - should return actual OPF fee for a given baseToken', async () => { + const opfFee = 1e15 + expect(await router.getOPFFee(contracts.oceanAddress)).to.equal('0') + expect(await router.getOPFFee(contracts.daiAddress)).to.equal(opfFee.toString()) + }) + + it('#getCurrentOPFFee - should return actual OPF Fee', async () => { + const opfFee = 1e15 + expect(await router.getCurrentOPFFee()).to.equal(opfFee.toString()) + }) + + it('#updateOPFFee - should update opf fee if Router Owner', async () => { + const opfFee = 1e15 + expect(await router.getCurrentOPFFee()).to.equal(opfFee.toString()) + const newOPFFee = 1e14 + await router.updateOPFFee(contracts.accounts[0], 1e14) + expect(await router.getCurrentOPFFee()).to.equal(newOPFFee.toString()) + }) + + it('#addPoolTemplate - should add a new token into poolTemplates mapping if Router Owner', async () => { + await router.addPoolTemplate(contracts.accounts[0], contracts.daiAddress) + expect(await router.isPoolTemplate(contracts.daiAddress)).to.equal(true) + }) + + it('#removePoolTemplate - should add a new token into poolTemplates mapping if Router Owner', async () => { + await router.removePoolTemplate(contracts.accounts[0], contracts.daiAddress) + expect(await router.isPoolTemplate(contracts.daiAddress)).to.equal(false) + }) +})