From 02e980fce2970752e93fbd15b57f55a6f4913df6 Mon Sep 17 00:00:00 2001 From: Jamie Hewitt Date: Fri, 12 Aug 2022 10:32:48 +0300 Subject: [PATCH] Dispenser tests (#514) * Setting up initial dispenser tests * Testing making user1 minter * Creating dispenser & testing all fields * Creating deactivate dispenser test * Fixing handleDeactivate in dispenser * Adding test for updating allowed swapper * Writting test for owner withdrawing all datatokens from dispenser --- package.json | 1 + src/mappings/dispenser.ts | 2 +- test/integration/Dispenser.test.ts | 487 +++++++++++++++++++++++++++++ 3 files changed, 489 insertions(+), 1 deletion(-) create mode 100644 test/integration/Dispenser.test.ts diff --git a/package.json b/package.json index da8be1b..bc9333e 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "deploy:local-barge": "graph deploy oceanprotocol/ocean-subgraph subgraph.yaml -l $npm_package_version --debug --ipfs http://172.15.0.16:5001 --node http://172.15.0.15:8020", "test": "npm run codegen && npm run lint && npm run type-check", "test-integration": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/**/*.test.ts'", + "test-dispenser": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/Dispenser.test.ts'", "test-fixed": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/FixedRateExchange.test.ts'", "lint": "eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx .", "lint:fix": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx . --fix", diff --git a/src/mappings/dispenser.ts b/src/mappings/dispenser.ts index a2c7a6b..20a41b5 100644 --- a/src/mappings/dispenser.ts +++ b/src/mappings/dispenser.ts @@ -66,7 +66,7 @@ export function handleDeactivate(event: DispenserDeactivated): void { event.params.datatokenAddress ) const dispenser = getDispenser(dispenserID) - dispenser.active = true + dispenser.active = false dispenser.save() } diff --git a/test/integration/Dispenser.test.ts b/test/integration/Dispenser.test.ts new file mode 100644 index 0000000..a93decd --- /dev/null +++ b/test/integration/Dispenser.test.ts @@ -0,0 +1,487 @@ +import { + Erc20CreateParams, + NftFactory, + NftCreateData, + sleep, + ZERO_ADDRESS, + Dispenser, + Datatoken, + DispenserParams +} from '@oceanprotocol/lib' +import DispenserTemplate from '@oceanprotocol/contracts/artifacts/contracts/pools/dispenser/Dispenser.sol/Dispenser.json' +import ERC20Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json' +import { assert } from 'chai' +import Web3 from 'web3' +import { homedir } from 'os' +import fs from 'fs' +import { fetch } from 'cross-fetch' +import { TransactionReceipt } from 'web3-core' +import { AbiItem } from 'web3-utils/types' + +const sleepMs = 1800 + +const data = JSON.parse( + fs.readFileSync( + process.env.ADDRESS_FILE || + `${homedir}/.ocean/ocean-contracts/artifacts/address.json`, + 'utf8' + ) +) + +const addresses = data.development +const web3 = new Web3('http://127.0.0.1:8545') + +const subgraphUrl = + 'http://127.0.0.1:9000/subgraphs/name/oceanprotocol/ocean-subgraph' + +describe('Dispenser tests', async () => { + const nftName = 'test-Fixed-Price-NFT' + const nftSymbol = 'TST-FIXED' + const tokenURI = 'https://oceanprotocol.com/nft/fixed' + const cap = '10000' + const feeAmount = '0.2' + const templateIndex = 1 + const dispenserAddress = addresses.Dispenser.toLowerCase() + let dtAddress: string + let marketPlaceFeeAddress: string + let dt + let Factory: NftFactory + let factoryAddress: string + let accounts: string[] + let publisher: string + let nftAddress: string + let time: number + let blockNumber: number + let dispenser: Dispenser + let dispenserId: string + let datatoken: Datatoken + let user1: string + let user2: string + + before(async () => { + factoryAddress = addresses.ERC721Factory.toLowerCase() + Factory = new NftFactory(factoryAddress, web3) + accounts = await web3.eth.getAccounts() + publisher = accounts[0].toLowerCase() + marketPlaceFeeAddress = accounts[1].toLowerCase() + user1 = accounts[2].toLowerCase() + user2 = accounts[3].toLowerCase() + }) + + it('should initialize Dispenser and datatoken class', async () => { + dispenser = new Dispenser( + web3, + 8996, + addresses.Dispenser, + DispenserTemplate.abi as AbiItem[] + ) + assert(dispenser.dispenserAbi !== null) + + datatoken = new Datatoken(web3, 8996, ERC20Template.abi as AbiItem[]) + assert(datatoken.datatokensAbi !== null) + }) + + it('Deploying an NFT with ERC20', async () => { + const date = new Date() + time = Math.floor(date.getTime() / 1000) + blockNumber = await web3.eth.getBlockNumber() + + const nftParams: NftCreateData = { + name: nftName, + symbol: nftSymbol, + templateIndex: 1, + tokenURI, + transferable: true, + owner: publisher + } + const erc20Params: Erc20CreateParams = { + templateIndex, + cap, + feeAmount, + paymentCollector: ZERO_ADDRESS, + feeToken: ZERO_ADDRESS, + minter: publisher, + mpFeeAddress: marketPlaceFeeAddress + } + + const tx = await Factory.createNftWithErc20( + publisher, + nftParams, + erc20Params + ) + assert(tx.events.NFTCreated.event === 'NFTCreated') + assert(tx.events.TokenCreated.event === 'TokenCreated') + nftAddress = tx.events.NFTCreated.returnValues.newTokenAddress.toLowerCase() + dtAddress = + tx.events.TokenCreated.returnValues.newTokenAddress.toLowerCase() + + // Check NFT values + await sleep(sleepMs) + const nftQuery = { + query: `query { + nft(id:"${nftAddress}"){ + id, + symbol, + name, + tokenUri, + owner, + creator, + address, + providerUrl, + assetState, + managerRole, + erc20DeployerRole, + storeUpdateRole, + metadataRole, + template, + transferable, + createdTimestamp, + tx, + block, + orderCount}}` + } + const initialResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(nftQuery) + }) + const nft = (await initialResponse.json()).data.nft + const nftTx: TransactionReceipt = await web3.eth.getTransactionReceipt( + nft.tx + ) + assert(nft.id === nftAddress, 'incorrect value for: id') + assert(nft.symbol === nftSymbol, 'incorrect value for: symbol') + assert(nft.name === nftName, 'incorrect value for: name') + assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri') + assert(nft.owner === publisher, 'incorrect value for: owner') + assert(nft.creator === publisher, 'incorrect value for: creator') + assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole') + assert( + nft.erc20DeployerRole[0] === factoryAddress, + 'incorrect value for: erc20DeployerRole' + ) + assert(nft.storeUpdateRole === null, 'incorrect value for: storeUpdateRole') + assert(nft.metadataRole === null, 'incorrect value for: metadataRole') + assert(nft.template === '', 'incorrect value for: template') + assert(nft.transferable === true, 'incorrect value for: transferable') + assert(nft.createdTimestamp >= time, 'incorrect value: createdTimestamp') + assert(nft.createdTimestamp < time + 5, 'incorrect value: createdTimestamp') + assert(nftTx.from === publisher, 'incorrect value for: tx') + assert(nftTx.to === factoryAddress, 'incorrect value for: tx') + assert(nftTx.blockNumber >= blockNumber, 'incorrect value for: tx') + assert(nft.block >= blockNumber, 'incorrect value for: block') + assert(nft.block < blockNumber + 50, 'incorrect value for: block') + assert(nft.orderCount === '0', 'incorrect value for: orderCount') + }) + + it('Test all DT Fields after deploying', async () => { + // Check Datatoken Values + const dtQuery = { + query: `query { + token(id: "${dtAddress}"){ + id, + symbol, + name, + decimals, + address, + cap, + supply, + isDatatoken, + nft {id}, + minter, + paymentManager, + paymentCollector, + publishMarketFeeAddress, + publishMarketFeeAmount, + templateId, + holderCount, + orderCount, + orders {id}, + fixedRateExchanges {id}, + dispensers {id}, + createdTimestamp, + tx, + block, + lastPriceToken, + lastPriceValue + }}` + } + const dtResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(dtQuery) + }) + dt = (await dtResponse.json()).data.token + + const dtTx: TransactionReceipt = await web3.eth.getTransactionReceipt(dt.tx) + + assert(dt.id === dtAddress, 'incorrect value for: id') + assert(dt.symbol, 'incorrect value for: symbol') + assert(dt.name, 'incorrect value for: name') + assert(dt.decimals === 18, 'incorrect value for: decimals') + assert(dt.address === dtAddress, 'incorrect value for: address') + assert(dt.cap === cap, 'incorrect value for: cap') + assert(dt.supply === '0', 'incorrect value for: supply') + assert(dt.isDatatoken === true, 'incorrect value for: isDatatoken') + assert(dt.nft.id === nftAddress, 'incorrect value for: nft.id') + assert(dt.minter[0] === publisher, 'incorrect value for: minter') + assert(dt.paymentManager === null, 'incorrect value for: paymentManager') + assert( + dt.paymentCollector === null, + 'incorrect value for: paymentCollector' + ) + assert( + dt.publishMarketFeeAddress === marketPlaceFeeAddress, + 'incorrect value for: publishMarketFeeAddress' + ) + assert( + dt.publishMarketFeeAmount === feeAmount, + 'incorrect value for: publishMarketFeeAmount' + ) + + assert(dt.templateId === templateIndex, 'incorrect value for: templateId') + assert(dt.holderCount === '0', 'incorrect value for: holderCount') + assert(dt.orderCount === '0', 'incorrect value for: orderCount') + assert(dt.orders, 'incorrect value for: orders') + assert(dt.fixedRateExchanges, 'incorrect value for: fixedRateExchanges') + assert(dt.dispensers, 'incorrect value for: dispensers') + assert(dt.createdTimestamp >= time, 'incorrect value for: createdTimestamp') + assert( + dt.createdTimestamp < time + 5, + 'incorrect value for: createdTimestamp' + ) + assert(dtTx.from === publisher, 'incorrect value for: tx') + assert(dtTx.to === factoryAddress, 'incorrect value for: tx') + assert(dtTx.blockNumber >= blockNumber, 'incorrect value for: tx') + assert(dt.block >= blockNumber, 'incorrect value for: block') + assert(dt.block < blockNumber + 50, 'incorrect value for: block') + assert( + dt.lastPriceToken === '0x0000000000000000000000000000000000000000', + 'incorrect value for: lastPriceToken' + ) + assert(dt.lastPriceValue === '0', 'incorrect value for: lastPriceValue') + }) + + it('Make user1 minter', async () => { + await datatoken.addMinter(dtAddress, publisher, user1) + + assert((await datatoken.getDTPermissions(dtAddress, user1)).minter === true) + await sleep(sleepMs) + const minterQuery = { + query: `query {token(id: "${dtAddress}"){minter{id}}}` + } + + const minterResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(minterQuery) + }) + const minter = (await minterResponse.json()).data.token.minter + assert(minter[1] === user1, 'incorrect value for: minter') + }) + + it('Create dispenser', async () => { + const maxTokens = '921' + const maxBalance = '9032' + const dispenserParams: DispenserParams = { + maxTokens, + maxBalance, + withMint: true + } + const tx = ( + await datatoken.createDispenser( + dtAddress, + publisher, + dispenserAddress, + dispenserParams + ) + ).events.NewDispenser + await sleep(sleepMs) + assert(tx, 'Cannot create dispenser') + dispenserId = `${dispenserAddress}-${dtAddress}` + + const dispenserQuery = { + query: `query {dispenser(id: "${dispenserId}"){ + id + contract + active + owner + token { + id + } + allowedSwapper + isMinter + maxTokens + maxBalance + balance + block + createdTimestamp + tx + dispenses { + id + } + __typename + }}` + } + const graphResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(dispenserQuery) + }) + const response = (await graphResponse.json()).data.dispenser + + assert(response.id === dispenserId, 'incorrect value for: id') + assert(response.contract === dispenserAddress, 'incorrect value: contract') + assert(response.active === true, 'incorrect value for: active') + assert(response.owner === publisher, 'incorrect value for: owner') + assert(response.token.id === dtAddress, 'incorrect value for: token.id') + assert(response.allowedSwapper === ZERO_ADDRESS, 'incorrect allowedSwapper') + assert(response.isMinter === true, 'incorrect value for: isMinter') + assert(response.maxTokens === web3.utils.fromWei(maxTokens), 'maxTokens') + assert(response.maxBalance === web3.utils.fromWei(maxBalance), 'maxBalance') + assert(response.balance === '0', 'maxBalance') + assert(response.block === tx.blockNumber, 'wrong block') + assert(response.createdTimestamp >= time, 'incorrect: createdTimestamp') + assert(response.createdTimestamp < time + 15, 'incorrect: createdTimestamp') + assert(response.tx === tx.transactionHash, 'incorrect value for: tx') + assert(response.dispenses.length === 0, 'incorrect value for: dispenses') + assert(response.__typename === 'Dispenser', 'incorrect value: __typename') + }) + + it('Deactivates dispenser', async () => { + const deactiveQuery = { + query: `query {dispenser(id: "${dispenserId}"){active}}` + } + + const initialResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(deactiveQuery) + }) + const initialActive = (await initialResponse.json()).data.dispenser.active + assert(initialActive === true, 'incorrect value for: initialActive') + + // Deactivate exchange + await dispenser.deactivate(dtAddress, publisher) + const status = await dispenser.status(dtAddress) + assert(status.active === false, 'Dispenser is still active') + await sleep(sleepMs) + // Check the updated value for active + const updatedResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(deactiveQuery) + }) + const updatedActive = (await updatedResponse.json()).data.dispenser.active + assert(updatedActive === false, 'incorrect value for: updatedActive') + }) + + it('Activates exchange', async () => { + const activeQuery = { + query: `query {dispenser(id: "${dispenserId}"){active}}` + } + const initialResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(activeQuery) + }) + const initialActive = (await initialResponse.json()).data.dispenser.active + assert(initialActive === false, 'incorrect value for: initialActive') + + // Activate exchange + await dispenser.activate(dtAddress, '100', '100', publisher) + await sleep(sleepMs) + + // Check the updated value for active + const updatedResponse = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(activeQuery) + }) + const updatedActive = (await updatedResponse.json()).data.dispenser.active + assert(updatedActive === true, 'incorrect value for: updatedActive') + }) + + it('User2 gets datatokens from the dispenser', async () => { + const amount = '3' + const dispenseQuery = { + query: `query {dispenser(id: "${dispenserId}"){ + dispenses{ + id + dispenser{id} + user {id} + amount + block + createdTimestamp + tx + __typename + }}}` + } + // Check initial values before dispense + const response1 = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(dispenseQuery) + }) + const before = (await response1.json()).data.dispenser.dispenses + assert(before.length === 0, 'incorrect value for: dispenses') + + const tx = await dispenser.dispense(dtAddress, user2, amount, user2) + await sleep(sleepMs) + + // Check values after dispense + const response2 = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(dispenseQuery) + }) + const dispense = (await response2.json()).data.dispenser.dispenses[0] + + assert(dispense.id === `${tx.transactionHash}-${dispenserId}`, 'wrong id') + assert(dispense.dispenser.id === dispenserId, 'incorrect value for: user') + assert(dispense.user.id === user2, 'incorrect value for: user') + assert(dispense.amount === amount, 'incorrect value for: user') + assert(dispense.block === tx.blockNumber, 'incorrect value for: block') + assert(dispense.createdTimestamp >= time, 'incorrect: createdTimestamp') + assert(dispense.createdTimestamp < time + 15, 'incorrect: createdTimestamp') + assert(dispense.tx === tx.transactionHash, 'incorrect value for: tx') + assert(dispense.__typename === 'DispenserTransaction', 'wrong __typename') + }) + + it('Owner withdraws all of the datatokens', async () => { + await dispenser.ownerWithdraw(dtAddress, publisher) + await sleep(sleepMs) + + // Check balance after owner withdraw + const balanceQuery = { + query: `query {dispenser(id: "${dispenserId}"){balance}}` + } + + const response = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(balanceQuery) + }) + const balance = (await response.json()).data.dispenser.balance + + assert(balance === '0', 'incorrect value for: balance') + }) + + it('Updates allowed swapper', async () => { + const swapperQuery = { + query: `query {dispenser(id: "${dispenserId}"){allowedSwapper}}` + } + // Check initial allowedSwapper + const swapperResponse1 = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(swapperQuery) + }) + const allowedSwapper1 = (await swapperResponse1.json()).data.dispenser + .allowedSwapper + assert( + allowedSwapper1 === ZERO_ADDRESS, + 'incorrect value for: allowedSwapper' + ) + + await dispenser.setAllowedSwapper(dtAddress, publisher, user1) + await sleep(sleepMs) + + const swapperResponse2 = await fetch(subgraphUrl, { + method: 'POST', + body: JSON.stringify(swapperQuery) + }) + const allowedSwapper2 = (await swapperResponse2.json()).data.dispenser + .allowedSwapper + + assert(allowedSwapper2 === user1, 'incorrect value for: allowedSwapper 2') + }) +})