nft transfer event (#573)

* Updating schema

* updating nft.owner with newOwner

* Updating nftOwner in Order

* Fixing tests with nft.owner and nft.creator

* Tracking nft transferHistory

* removing nftOwner from order

* Removing nftOwner test from order

* Updating schema for nftTransferHistory

* Updating tests for transferHistory

* Updating test

* Fixing test

* Fixing timestamp test

* Revert "removing nftOwner from order"

This reverts commit 6f9aae3c40.

* Reverting removal of nftOwner Test + resolving conflicts
This commit is contained in:
Jamie Hewitt 2022-11-24 16:40:31 +03:00 committed by GitHub
parent 6c4fc1c346
commit 20c27cd521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 91 additions and 30 deletions

View File

@ -26,7 +26,7 @@
"test": "npm run codegen && npm run lint && npm run type-check", "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-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-dispenser": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/Dispenser.test.ts'",
"test-simple": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/SimplePublishConsume.test.ts'", "test-simple": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/SimpleSubgraph.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'", "test-fixed": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/FixedRateExchange.test.ts'",
"test-users": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/users.test.ts'", "test-users": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/users.test.ts'",
"test-ve": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/VeOcean.test.ts'", "test-ve": "TS_NODE_PROJECT='test/integration/tsconfig.json' mocha --config=test/integration/.mocharc.json --node-env=test --exit 'test/integration/VeOcean.test.ts'",

View File

@ -76,9 +76,9 @@ type Nft @entity{
tokenUri: String tokenUri: String
"address of the owner of the nft" "address of the owner of the nft"
owner: String! owner: User!
"address of the creator of the nft" "address of the creator of the nft"
creator: String! creator: User!
"same as id, it's just for easy discoverability" "same as id, it's just for easy discoverability"
address: String! address: String!
@ -115,6 +115,7 @@ type Nft @entity{
hasMetadata: Boolean! hasMetadata: Boolean!
nftData: [NftData!] @derivedFrom(field: "nft") nftData: [NftData!] @derivedFrom(field: "nft")
transferHistory: [NftTransferHistory!] @derivedFrom(field: "nft")
} }
type NftData @entity{ type NftData @entity{
@ -148,6 +149,7 @@ type Order @entity {
payer: User! payer: User!
amount: BigDecimal! amount: BigDecimal!
serviceIndex: Int! serviceIndex: Int!
nftOwner: User!
# the fees will be updated from an event that will be created after (todo) # the fees will be updated from an event that will be created after (todo)
@ -572,3 +574,15 @@ type DFReward @entity {
availableClaims: [DFAvailableClaim!] @derivedFrom(field: "receiver") availableClaims: [DFAvailableClaim!] @derivedFrom(field: "receiver")
history: [DFHistory!] @derivedFrom(field: "receiver") history: [DFHistory!] @derivedFrom(field: "receiver")
} }
type NftTransferHistory @entity {
# ID = hash(nftAddress+txId+eventNumber)
id: ID!
nft: Nft!
oldOwner: User!
newOwner: User!
txId: String
timestamp: Int!
block: Int!
}

View File

@ -38,6 +38,12 @@ export function handleOrderStarted(event: OrderStarted): void {
const consumer = getUser(event.params.consumer.toHex()) const consumer = getUser(event.params.consumer.toHex())
order.consumer = consumer.id order.consumer = consumer.id
if (token.nft) {
const nft = Nft.load(token.nft as string) as Nft
const nftOwner = getUser(nft.owner)
order.nftOwner = nftOwner.id
}
const payer = getUser(event.params.payer.toHex()) const payer = getUser(event.params.payer.toHex())
payer.totalOrders = payer.totalOrders.plus(integer.ONE) payer.totalOrders = payer.totalOrders.plus(integer.ONE)
payer.save() payer.save()

View File

@ -1,4 +1,4 @@
import { Nft, NftUpdate, NftData } from '../@types/schema' import { Nft, NftUpdate, NftData, NftTransferHistory } from '../@types/schema'
import { import {
MetadataCreated, MetadataCreated,
MetadataState, MetadataState,
@ -256,9 +256,22 @@ export function handleCleanedPermissions(event: CleanedPermissions): void {
export function handleNftTransferred(event: Transfer): void { export function handleNftTransferred(event: Transfer): void {
const id = event.address.toHex() const id = event.address.toHex()
const nft = getNftTokenWithID(id) const nft = getNftTokenWithID(id)
const oldOwner = nft.owner
const newOwner = getUser(event.params.to.toHexString()) const newOwner = getUser(event.params.to.toHexString())
nft.owner = newOwner.id nft.owner = newOwner.id
nft.save() nft.save()
const transferId = `${nft.address}-${event.transaction.hash.toHex()}-${
event.logIndex
}`
const newTransfer = new NftTransferHistory(transferId)
newTransfer.oldOwner = oldOwner
newTransfer.nft = nft.id
newTransfer.newOwner = newOwner.id
newTransfer.txId = event.transaction.hash.toHex()
newTransfer.timestamp = event.block.timestamp.toI32()
newTransfer.block = event.block.number.toI32()
newTransfer.save()
} }
export function handleNftData(event: DataChanged): void { export function handleNftData(event: DataChanged): void {

View File

@ -358,7 +358,7 @@ describe('Datatoken tests', async () => {
assert(Number(user2balance) === 0, 'Invalid user2 balance') assert(Number(user2balance) === 0, 'Invalid user2 balance')
const query = { const query = {
query: `query {token(id: "${newDtAddress.toLowerCase()}"){id,orderCount,orders {id, lastPriceToken{id}}}}` query: `query {token(id: "${newDtAddress.toLowerCase()}"){id,orderCount,orders {id, nftOwner{id}, lastPriceToken{id}}}}`
} }
await sleep(2000) await sleep(2000)
@ -419,5 +419,6 @@ describe('Datatoken tests', async () => {
assert(token.orderCount === '1', 'Invalid orderCount after order') assert(token.orderCount === '1', 'Invalid orderCount after order')
assert(token.orders[0].id === orderId) assert(token.orders[0].id === orderId)
assert(token.orders[0].lastPriceToken.id === ZERO_ADDRESS) assert(token.orders[0].lastPriceToken.id === ZERO_ADDRESS)
assert(token.orders[0].nftOwner.id === publisher, 'invalid nftOwner')
}) })
}) })

View File

@ -125,8 +125,8 @@ describe('Dispenser tests', async () => {
symbol, symbol,
name, name,
tokenUri, tokenUri,
owner, owner{id},
creator, creator{id},
address, address,
providerUrl, providerUrl,
assetState, assetState,
@ -153,8 +153,8 @@ describe('Dispenser tests', async () => {
assert(nft.symbol === nftSymbol, 'incorrect value for: symbol') assert(nft.symbol === nftSymbol, 'incorrect value for: symbol')
assert(nft.name === nftName, 'incorrect value for: name') assert(nft.name === nftName, 'incorrect value for: name')
assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri') assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri')
assert(nft.owner === publisher, 'incorrect value for: owner') assert(nft.owner.id === publisher, 'incorrect value for: owner')
assert(nft.creator === publisher, 'incorrect value for: creator') assert(nft.creator.id === publisher, 'incorrect value for: creator')
assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole') assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole')
assert( assert(
nft.erc20DeployerRole[0] === factoryAddress, nft.erc20DeployerRole[0] === factoryAddress,

View File

@ -138,8 +138,8 @@ describe('Fixed Rate Exchange tests', async () => {
symbol, symbol,
name, name,
tokenUri, tokenUri,
owner, owner{id},
creator, creator{id},
address, address,
providerUrl, providerUrl,
assetState, assetState,
@ -166,8 +166,8 @@ describe('Fixed Rate Exchange tests', async () => {
assert(nft.symbol === nftSymbol, 'incorrect value for: symbol') assert(nft.symbol === nftSymbol, 'incorrect value for: symbol')
assert(nft.name === nftName, 'incorrect value for: name') assert(nft.name === nftName, 'incorrect value for: name')
assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri') assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri')
assert(nft.owner === publisher, 'incorrect value for: owner') assert(nft.owner.id === publisher, 'incorrect value for: owner')
assert(nft.creator === publisher, 'incorrect value for: creator') assert(nft.creator.id === publisher, 'incorrect value for: creator')
assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole') assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole')
assert( assert(
nft.erc20DeployerRole[0] === factoryAddress, nft.erc20DeployerRole[0] === factoryAddress,

View File

@ -130,8 +130,8 @@ describe('NFT tests', async () => {
symbol, symbol,
name, name,
tokenUri, tokenUri,
owner, owner{id},
creator, creator{id},
address, address,
providerUrl, providerUrl,
assetState, assetState,
@ -157,8 +157,8 @@ describe('NFT tests', async () => {
assert(nft.symbol === nftSymbol, 'incorrect value for: symbol') assert(nft.symbol === nftSymbol, 'incorrect value for: symbol')
assert(nft.name === nftName, 'incorrect value for: name') assert(nft.name === nftName, 'incorrect value for: name')
assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri') assert(nft.tokenUri === tokenURI, 'incorrect value for: tokenUri')
assert(nft.owner === publisher, 'incorrect value for: owner') assert(nft.owner.id === publisher, 'incorrect value for: owner')
assert(nft.creator === publisher, 'incorrect value for: creator') assert(nft.creator.id === publisher, 'incorrect value for: creator')
assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole') assert(nft.managerRole[0] === publisher, 'incorrect value for: managerRole')
assert( assert(
nft.erc20DeployerRole[0] === factoryAddress, nft.erc20DeployerRole[0] === factoryAddress,
@ -219,8 +219,8 @@ describe('NFT tests', async () => {
symbol, symbol,
name, name,
tokenUri, tokenUri,
owner, owner{id},
creator, creator{id},
address, address,
providerUrl, providerUrl,
assetState, assetState,
@ -247,8 +247,8 @@ describe('NFT tests', async () => {
assert(updatedNft.symbol === nftSymbol, 'incorrect value for: symbol') assert(updatedNft.symbol === nftSymbol, 'incorrect value for: symbol')
assert(updatedNft.name === nftName, 'incorrect value for: name') assert(updatedNft.name === nftName, 'incorrect value for: name')
assert(updatedNft.tokenUri === tokenURI, 'incorrect value for: tokenUri') assert(updatedNft.tokenUri === tokenURI, 'incorrect value for: tokenUri')
assert(updatedNft.owner === publisher, 'incorrect value for: owner') assert(updatedNft.owner.id === publisher, 'incorrect value for: owner')
assert(updatedNft.creator === publisher, 'incorrect value for: creator') assert(updatedNft.creator.id === publisher, 'incorrect value for: creator')
assert( assert(
updatedNft.managerRole[0] === publisher, updatedNft.managerRole[0] === publisher,
'incorrect value for: managerRole' 'incorrect value for: managerRole'

View File

@ -191,7 +191,7 @@ describe('Simple Publish & consume test', async () => {
const queryOriginalOwner = { const queryOriginalOwner = {
query: `query { query: `query {
nft(id:"${graphNftToken}"){symbol,id,owner}}` nft(id:"${graphNftToken}"){symbol,id,owner{id}}}`
} }
const initialResponse = await fetch(subgraphUrl, { const initialResponse = await fetch(subgraphUrl, {
method: 'POST', method: 'POST',
@ -200,7 +200,7 @@ describe('Simple Publish & consume test', async () => {
const initialResult = await initialResponse.json() const initialResult = await initialResponse.json()
// Checking original owner account has been set correctly // Checking original owner account has been set correctly
assert( assert(
initialResult.data.nft.owner.toLowerCase() === initialResult.data.nft.owner.id.toLowerCase() ===
publisherAccount.toLowerCase() publisherAccount.toLowerCase()
) )
@ -235,14 +235,14 @@ describe('Simple Publish & consume test', async () => {
await sleep(2000) await sleep(2000)
const query2 = { const query2 = {
query: `query { query: `query {
nft(id:"${graphNftToken}"){symbol,id,owner, transferable}}` nft(id:"${graphNftToken}"){symbol,id,owner{id}, transferable}}`
} }
const response = await fetch(subgraphUrl, { const response = await fetch(subgraphUrl, {
method: 'POST', method: 'POST',
body: JSON.stringify(query2) body: JSON.stringify(query2)
}) })
const queryResult = await response.json() const queryResult = await response.json()
assert(queryResult.data.nft.owner === newOwnerAccount) assert(queryResult.data.nft.owner.id === newOwnerAccount)
}) })
it('should save provider fees after startOrder is called', async () => { it('should save provider fees after startOrder is called', async () => {

View File

@ -31,6 +31,7 @@ describe('Tests coverage without provider/aquarius', async () => {
let accounts: string[] let accounts: string[]
let publisherAccount: string let publisherAccount: string
let newOwnerAccount: string let newOwnerAccount: string
let time: number
before(async () => { before(async () => {
nft = new Nft(web3) nft = new Nft(web3)
@ -38,6 +39,8 @@ describe('Tests coverage without provider/aquarius', async () => {
accounts = await web3.eth.getAccounts() accounts = await web3.eth.getAccounts()
publisherAccount = accounts[0] publisherAccount = accounts[0]
newOwnerAccount = accounts[1].toLowerCase() newOwnerAccount = accounts[1].toLowerCase()
const date = new Date()
time = Math.floor(date.getTime() / 1000)
}) })
it('should publish a dataset (create NFT + ERC20)', async () => { it('should publish a dataset (create NFT + ERC20)', async () => {
@ -105,20 +108,44 @@ describe('Tests coverage without provider/aquarius', async () => {
) )
await sleep(2000) await sleep(2000)
const erc721Address = result.events.NFTCreated.returnValues[0] const erc721Address = result.events.NFTCreated.returnValues[0]
const graphNftToken = erc721Address.toLowerCase() const nftAddress = erc721Address.toLowerCase()
// Transfer the NFT // Transfer the NFT
await nft.transferNft(graphNftToken, publisherAccount, newOwnerAccount) const tx = await nft.transferNft(
nftAddress,
publisherAccount,
newOwnerAccount
)
await sleep(2000) await sleep(2000)
const query2 = { const query2 = {
query: `query { query: `query {
nft(id:"${graphNftToken}"){symbol,id,owner, transferable}}` nft(id:"${nftAddress}"){
symbol,
id,
owner{id},
transferable,
transferHistory(orderBy: timestamp, orderDirection: desc){id,nft,oldOwner,newOwner,txId,timestamp,block}
}}`
} }
const response = await fetch(subgraphUrl, { const response = await fetch(subgraphUrl, {
method: 'POST', method: 'POST',
body: JSON.stringify(query2) body: JSON.stringify(query2)
}) })
const queryResult = await response.json() const queryResult = await response.json()
assert(queryResult.data.nft.owner === newOwnerAccount) const transferHistory = queryResult.data.nft.transferHistory[0]
assert(queryResult.data.nft.owner.id === newOwnerAccount)
assert(
transferHistory.id ===
`${nftAddress}-${tx.transactionHash}-${tx.events.Transfer.logIndex}`,
'Invalid transferHistory Id'
)
assert(transferHistory.txId === tx.transactionHash, 'invalid txId')
assert(transferHistory.timestamp)
assert(transferHistory.timestamp >= time - 500, 'incorrect value timestamp')
assert(transferHistory.timestamp < time + 500, 'incorrect value timestamp')
assert(transferHistory.block === tx.blockNumber, 'blockNumber')
}) })
}) })