ocean-subgraph/test/integration/Dispenser.test.ts
Maria Carmina e1df119197
Fix #628 & #629 & #621: Store event log index for all records (#630)
* Store eventIndex.

* Changed in veDelegation. Removed import of String.

* linter.

* Removed tx hash.

* Revert some tweaks.

* added logIndex.

* converted to big int.

* 0 -> BigInt.zero().

* Added eventIndex to template and OPC.

* updated tweak

* updated tweak2

* Added eventIndex in tests.

* revert.

* Added eventIndex for TokenCreated and NFTCreated events. Increase time sleep for graphql request.

* Changed position of eventIndex in entity.

* Added eventIndex for order events and for dt events. Added new test commands in package.json.

* Added eventIndex for NFT Update events.

* Added eventIndex for dispenser.

* Modified dispenser tests.

* Reverted sleep secs. Updated tests.

* Updated dispenser tests. Added eventIndex for FRE.

* Added eventIndex in df rewards.

* Updated Ve with eventIndex.

* Updating order id with event index.

* Updated @ocean/lib with multichain version.

* Updated to number type.

* Updated tests for order.

* some changes.

* Fix dt tests. Added logs for provider fee. Need fix for Simple publish and consume tests.

* Problem raised by retrieving order event index in provider fee event handler.

* Added function for searching the right order.

* Debug order with provider fee.

* Removed console logs.

* Added debug logs.

* Hardcoded eventIndex just for testing.

* Paste logs from graph node.

* added extra sleep in test.

* fixed command.

* Added comments. Modified util function for Order Reuse.

* Added more logs and other tweaks.

* fixed command for docker logs.

* Added more logs.

* Converted to lowercase.

* Removed condition just for test.

* Added more logs. Order is not null.

* Call getOrder.

* Added verification back.

* converted to hex and add toString.

* Pass toString as param.

* Added ethereumjs util.

* replaced with ==.

* Refactored logic.

* Print event index.

* added more logs of event index.

* Modified tweaks and asserts.

* Added log for reuse order.

* updates.

* Reverted changes.

* Added check for eventIndex == 0.

* Enhanced the code. Replaced while with for.

* Added more logs for reuse test.

* added another condition.

* Added logs in tests. Removed redundant condition.

* Added more logs to test.

* Fixed typo.

* still debugging

* Refactored code.

* Getting closer.

* Fix tests for orders part. Removed logs.

* Removed more logs.

* Fix DT tests related to order.

* Implemented Publishing Market Fee event handler. Added test.

* Added consume market fee handler. Test consume market fee handler.

* Fixed tests for fees. Added TODOs.

* Generated ID with eventIndex in ficed rate. Added assert errors messages.

* Added FRE tests to workflow.

* Generated dispenser transaction with event index.

* Fixed dispenser tests.

* Add event index for NftUpdate entity ID.

* Changed IDs for VeDelegation and VeAllocationUpdate.

* Added full test suite to workflow.

* Fixed nft transfer ID.

* print blocks.

* test just dt and ending test to see the last block.

* Added df test.

* Added dispenser test.

* Added FRE test.

* Added NFT test.

* Added simple publish consume test.

* Added simple subgraph test.

* Added users test.

* Added ve test.

* Increased sleep time.

* commented delegation test.

* respect lint

* Fixed ending tests. Removed commented code. Brought back test suite.

* Print values from failing tests. Updated mappings.

* Rollback changes in veDelegation and veUtils. Added more prints for debug in tests.

* Removed veDelegation creation record.

* Rollback to the approach for veDelegation like it is in main.

* Removed prints. Match changes with main.

* Removed -1 from last block.

* Added prints for eventIndex. Fixed some suggestions.

* Fixed veDelegation.

* Removed prints.
2023-05-13 15:00:52 +03:00

528 lines
18 KiB
TypeScript

import {
DatatokenCreateParams,
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(
addresses.Dispenser,
web3,
8996,
null,
DispenserTemplate.abi as AbiItem[]
)
assert(dispenser.getDefaultAbi() !== null)
datatoken = new Datatoken(web3, 8996, null, ERC20Template.abi as AbiItem[])
assert(datatoken.getDefaultAbi() !== 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: DatatokenCreateParams = {
templateIndex,
cap,
feeAmount,
paymentCollector: ZERO_ADDRESS,
feeToken: ZERO_ADDRESS,
minter: publisher,
mpFeeAddress: marketPlaceFeeAddress
}
const tx = await Factory.createNftWithDatatoken(
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{id},
creator{id},
address,
providerUrl,
assetState,
managerRole,
erc20DeployerRole,
storeUpdateRole,
metadataRole,
template,
transferable,
createdTimestamp,
tx,
eventIndex,
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.id === publisher, 'incorrect value for: owner')
assert(nft.creator.id === 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')
assert(
nft.eventIndex !== null && nft.eventIndex > 0,
'Invalid eventIndex for NFT creation'
)
})
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,
eventIndex,
block,
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.lastPriceValue === '0', 'incorrect value for: lastPriceValue')
assert(
dt.eventIndex !== null && dt.eventIndex > 0,
'incorrect value for: eventIndex'
)
})
it('Make user1 minter', async () => {
await datatoken.addMinter(dtAddress, publisher, user1)
assert((await datatoken.getPermissions(dtAddress, user1)).minter === true)
await sleep(sleepMs)
const minterQuery = {
query: `query {token(id: "${dtAddress}"){minter{id}, eventIndex}}`
}
const minterResponse = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(minterQuery)
})
const dt = (await minterResponse.json()).data.token
assert(dt.minter[1] === user1, 'incorrect value for: minter')
assert(dt.eventIndex !== null, 'incorrect value for: eventIndex')
})
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
eventIndex
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.eventIndex !== null && response.eventIndex > 0,
'incorrect value for: eventIndex'
)
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, eventIndex}}`
}
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
const tx = 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
assert(updatedActive.active === false, 'incorrect value for: updatedActive')
assert(updatedActive.eventIndex !== null, 'incorrect value for: eventIndex')
assert(
updatedActive.eventIndex === tx.events.DispenserDeactivated.logIndex,
'incorrect value for: eventIndex'
)
})
it('Activates dispenser', async () => {
const activeQuery = {
query: `query {dispenser(id: "${dispenserId}"){active, eventIndex}}`
}
const initialResponse = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(activeQuery)
})
const initialActive = (await initialResponse.json()).data.dispenser
assert(initialActive.active === false, 'incorrect value for: initialActive')
assert(initialActive.eventIndex !== null, 'incorrect value for: eventIndex')
// Activate dispenser
const tx = 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
assert(updatedActive.active === true, 'incorrect value for: updatedActive')
assert(updatedActive.eventIndex !== null, 'incorrect value for: eventIndex')
assert(
updatedActive.eventIndex === tx.events.DispenserActivated.logIndex,
'incorrect value for: eventIndex'
)
})
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
eventIndex
__typename
}}}`
}
// Check initial values before dispense
const response1 = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(dispenseQuery)
})
await sleep(sleepMs)
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}-${tx.events.TokensDispensed.logIndex.toFixed(1)}`,
'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.eventIndex !== null, 'incorrect value for: eventIndex')
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, eventIndex}}`
}
const response = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(balanceQuery)
})
const balance = (await response.json()).data.dispenser
assert(balance.balance === '0', 'incorrect value for: balance')
assert(balance.eventIndex !== null, 'incorrect value for: eventIndex')
})
it('Updates allowed swapper', async () => {
const swapperQuery = {
query: `query {dispenser(id: "${dispenserId}"){allowedSwapper, eventIndex}}`
}
// 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'
)
const tx = 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
assert(
allowedSwapper2.allowedSwapper === user1,
'incorrect value for: allowedSwapper 2'
)
assert(
allowedSwapper2.eventIndex !== null &&
allowedSwapper2.eventIndex ===
tx.events.DispenserAllowedSwapperChanged.logIndex,
'incorrect value for: eventIndex'
)
})
})