From 3789a53e34c9bde12c836ec27d57badeeaed48ab Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Fri, 20 Oct 2023 15:59:05 -0300 Subject: [PATCH 1/9] Role assingment impl --- abis/ERC7432.json | 4 +- schema.graphql | 17 ++-- src/erc7432/role/grant-handler.ts | 6 +- src/erc7432/role/revoke-handler.ts | 22 +++--- src/erc7432/role/role-approval-handler.ts | 4 +- src/utils/helper.ts | 52 ++++++++---- subgraph-goerli.yaml | 2 +- subgraph-mumbai.yaml | 2 +- subgraph-polygon.yaml | 2 +- tests/erc7432/grant-handler.test.ts | 58 +++++++------- tests/erc7432/revoke-handler.test.ts | 96 +++++++++++------------ tests/helpers/entities.ts | 45 +++++------ tests/helpers/events.ts | 8 +- 13 files changed, 173 insertions(+), 145 deletions(-) diff --git a/abis/ERC7432.json b/abis/ERC7432.json index 47f3b19..ebb3940 100644 --- a/abis/ERC7432.json +++ b/abis/ERC7432.json @@ -122,7 +122,7 @@ "components": [ { "internalType": "bytes32", - "name": "role", + "name": "roleassignment", "type": "bytes32" }, { @@ -172,7 +172,7 @@ "components": [ { "internalType": "bytes32", - "name": "role", + "name": "roleassignment", "type": "bytes32" }, { diff --git a/schema.graphql b/schema.graphql index 6c471f8..3c63820 100644 --- a/schema.graphql +++ b/schema.graphql @@ -3,26 +3,33 @@ type Nft @entity { address: String! tokenId: BigInt! owner: Account! - rolesHistory: [Role!] @derivedFrom(field: "nft") + rolesHistory: [RoleAssignment!] @derivedFrom(field: "nft") } type Account @entity { id: ID! # address nfts: [Nft!] @derivedFrom(field: "owner") - rolesGranted: [Role!] @derivedFrom(field: "grantor") - rolesReceived: [Role!] @derivedFrom(field: "grantee") + rolesGranted: [RoleAssignment!] @derivedFrom(field: "grantor") + rolesReceived: [RoleAssignment!] @derivedFrom(field: "grantee") roleApprovals: [RoleApproval!] @derivedFrom(field: "grantor") } -type Role @entity { +type RoleAssignment @entity { id: ID! # grantorAddress + tokenId + tokenAddress + granteeAddress + roleHash - roleId: Bytes! + role: Role! nft: Nft! grantor: Account! grantee: Account! expirationDate: BigInt! revocable: Boolean! data: Bytes! + timestamp: BigInt! +} + +type Role @entity { + id: ID! # tokenId + tokenAddress + roleHash + roleHash: Bytes! + roleAssignments: [RoleAssignment!] @derivedFrom(field: "role") } type RoleApproval @entity { diff --git a/src/erc7432/role/grant-handler.ts b/src/erc7432/role/grant-handler.ts index bb9f498..f9c3e07 100644 --- a/src/erc7432/role/grant-handler.ts +++ b/src/erc7432/role/grant-handler.ts @@ -1,7 +1,7 @@ import { log } from '@graphprotocol/graph-ts' import { RoleGranted } from '../../../generated/ERC7432-Immutable-Roles/ERC7432' import { Account, Nft } from '../../../generated/schema' -import { generateNftId, findOrCreateAccount, findOrCreateRole } from '../../utils/helper' +import { generateNftId, findOrCreateAccount, findOrCreateRoleAssignment } from '../../utils/helper' export function handleRoleGranted(event: RoleGranted): void { const tokenId = event.params._tokenId.toString() @@ -26,6 +26,6 @@ export function handleRoleGranted(event: RoleGranted): void { } const granteeAccount = findOrCreateAccount(event.params._grantee.toHex()) - const role = findOrCreateRole(event, grantorAccount, granteeAccount, nft) - log.warning('[handleRoleGranted] Role: {} NFT: {} Tx: {}', [role.id, nftId, event.transaction.hash.toHex()]) + const roleAssignment = findOrCreateRoleAssignment(event, grantorAccount, granteeAccount, nft) + log.warning('[handleRoleGranted] roleAssignment: {} NFT: {} Tx: {}', [roleAssignment.id, nftId, event.transaction.hash.toHex()]) } diff --git a/src/erc7432/role/revoke-handler.ts b/src/erc7432/role/revoke-handler.ts index 71da0fe..3c6f252 100644 --- a/src/erc7432/role/revoke-handler.ts +++ b/src/erc7432/role/revoke-handler.ts @@ -1,7 +1,7 @@ import { log } from '@graphprotocol/graph-ts' import { RoleRevoked } from '../../../generated/ERC7432-Immutable-Roles/ERC7432' -import { Account, Nft, Role } from '../../../generated/schema' -import { generateNftId, generateRoleId } from '../../utils/helper' +import { Account, Nft, RoleAssignment } from '../../../generated/schema' +import { generateNftId, generateRoleAssignmentId } from '../../utils/helper' export function handleRoleRevoked(event: RoleRevoked): void { const tokenId = event.params._tokenId.toString() @@ -28,18 +28,18 @@ export function handleRoleRevoked(event: RoleRevoked): void { return } - const roleId = generateRoleId(revoker, grantee, nft, event.params._role) - const role = Role.load(roleId) - if (!role) { - log.warning('[handleRoleRevoked] Role {} does not exist, skipping...', [roleId]) + const roleAssignmentId = generateRoleAssignmentId(revoker, grantee, nft, event.params._role) + const roleassignment = RoleAssignment.load(roleAssignmentId) + if (!roleassignment) { + log.warning('[handleRoleRevoked] RoleAssignment {} does not exist, skipping...', [roleAssignmentId]) return } - if (event.block.timestamp > role.expirationDate) { - log.warning('[handleRoleRevoked] Role {} already expired, skipping...', [roleId]) + if (event.block.timestamp > roleassignment.expirationDate) { + log.warning('[handleRoleRevoked] RoleAssignment {} already expired, skipping...', [roleAssignmentId]) return } - role.expirationDate = event.block.timestamp - role.save() - log.warning('[handleRoleRevoked] Revoked Role: {} NFT: {} Tx: {}', [roleId, nftId, event.transaction.hash.toHex()]) + roleassignment.expirationDate = event.block.timestamp + roleassignment.save() + log.warning('[handleRoleRevoked] Revoked RoleAssignment: {} NFT: {} Tx: {}', [roleAssignmentId, nftId, event.transaction.hash.toHex()]) } diff --git a/src/erc7432/role/role-approval-handler.ts b/src/erc7432/role/role-approval-handler.ts index 54490a5..7729ed3 100644 --- a/src/erc7432/role/role-approval-handler.ts +++ b/src/erc7432/role/role-approval-handler.ts @@ -18,14 +18,14 @@ export function handleRoleApprovalForAll(event: RoleApprovalForAll): void { if (isApproved) { const roleApproval = insertRoleApprovalIfNotExist(grantorAccount, operatorAccount, tokenAddress) - log.warning('[handleRoleApprovalForAll] Updated Role Approval: {} Tx: {}', [ + log.warning('[handleRoleApprovalForAll] Updated RoleAssignment Approval: {} Tx: {}', [ roleApproval.id, event.transaction.hash.toHex(), ]) } else { const roleApprovalId = generateRoleApprovalId(grantorAccount, operatorAccount, tokenAddress) deleteRoleApprovalIfExist(roleApprovalId) - log.warning('[handleRoleApprovalForAll] Removed Role Approval: {} Tx: {}', [ + log.warning('[handleRoleApprovalForAll] Removed RoleAssignment Approval: {} Tx: {}', [ roleApprovalId, event.transaction.hash.toHex(), ]) diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 2950412..64421db 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,5 +1,5 @@ import { BigInt, Bytes, store } from '@graphprotocol/graph-ts' -import { Account, Nft, Role, RoleApproval } from '../../generated/schema' +import { Account, Nft, Role, RoleApproval, RoleAssignment } from '../../generated/schema' import { RoleGranted } from '../../generated/ERC7432-Immutable-Roles/ERC7432' export function findOrCreateAccount(id: string): Account { @@ -25,27 +25,47 @@ export function generateNftId(tokenAddress: string, tokenId: string): string { return tokenAddress + '-' + tokenId } -export function generateRoleId(grantor: Account, grantee: Account, nft: Nft, role: Bytes): string { - return grantor.id + '-' + grantee.id + '-' + nft.id + '-' + role.toHex() +export function generateRoleAssignmentId(grantor: Account, grantee: Account, nft: Nft, roleAssignment: Bytes): string { + return grantor.id + '-' + grantee.id + '-' + nft.id + '-' + roleAssignment.toHex() } -export function findOrCreateRole(event: RoleGranted, grantor: Account, grantee: Account, nft: Nft): Role { - const roleId = generateRoleId(grantor, grantee, nft, event.params._role) - let role = Role.load(roleId) - if (!role) { - role = new Role(roleId) - role.roleId = event.params._role - role.nft = nft.id - role.grantor = grantor.id - role.grantee = grantee.id +export function findOrCreateRoleAssignment(event: RoleGranted, grantor: Account, grantee: Account, nft: Nft): RoleAssignment { + const roleAssignmentId = generateRoleAssignmentId(grantor, grantee, nft, event.params._role) + let roleAssignment = RoleAssignment.load(roleAssignmentId) + + if (!roleAssignment) { + roleAssignment = new RoleAssignment(roleAssignmentId) + roleAssignment.role = findOrCreateRole(nft, event.params._role).id + roleAssignment.nft = nft.id + roleAssignment.grantor = grantor.id + roleAssignment.grantee = grantee.id + } + + roleAssignment.expirationDate = event.params._expirationDate + roleAssignment.revocable = event.params._revocable + roleAssignment.data = event.params._data + roleAssignment.timestamp = event.block.timestamp + roleAssignment.save() + return roleAssignment +} + +export function findOrCreateRole(nft: Nft, roleHash: Bytes): Role { + + let role = Role.load(generateRoleId(nft, roleHash)) + + if(!role) { + role = new Role(generateRoleId(nft, roleHash)) + role.roleHash = roleHash + role.save() } - role.expirationDate = event.params._expirationDate - role.revocable = event.params._revocable - role.data = event.params._data - role.save() + return role } +export function generateRoleId(nft: Nft, roleHash: Bytes): string { + return nft.id + '-' + roleHash.toHex() +} + export function generateRoleApprovalId(grantor: Account, operator: Account, tokenAddress: string): string { return grantor.id + '-' + operator.id + '-' + tokenAddress.toLowerCase() } diff --git a/subgraph-goerli.yaml b/subgraph-goerli.yaml index 93e7eed..f5bd44b 100644 --- a/subgraph-goerli.yaml +++ b/subgraph-goerli.yaml @@ -38,7 +38,7 @@ dataSources: entities: - Nft - Account - - Role + - RoleAssignment - RoleApproval abis: - name: ERC7432 diff --git a/subgraph-mumbai.yaml b/subgraph-mumbai.yaml index 9dbb61a..6f506ea 100644 --- a/subgraph-mumbai.yaml +++ b/subgraph-mumbai.yaml @@ -18,7 +18,7 @@ dataSources: entities: - Nft - Account - - Role + - RoleAssignment - RoleApproval abis: - name: ERC7432 diff --git a/subgraph-polygon.yaml b/subgraph-polygon.yaml index 5661f9c..423c619 100644 --- a/subgraph-polygon.yaml +++ b/subgraph-polygon.yaml @@ -38,7 +38,7 @@ dataSources: entities: - Nft - Account - - Role + - RoleAssignment - RoleApproval abis: - name: ERC7432 diff --git a/tests/erc7432/grant-handler.test.ts b/tests/erc7432/grant-handler.test.ts index 7775630..45658c7 100644 --- a/tests/erc7432/grant-handler.test.ts +++ b/tests/erc7432/grant-handler.test.ts @@ -6,7 +6,7 @@ import { BigInt, Bytes } from '@graphprotocol/graph-ts' import { createMockAccount, createMockNft, validateRole } from '../helpers/entities' import { Account } from '../../generated/schema' -const RoleId = Bytes.fromUTF8('0xGrantRole') +const RoleAssignmentId = Bytes.fromUTF8('0xGrantRole') const tokenAddress = Addresses[0] const tokenId = '123' const grantee = Addresses[1] @@ -20,12 +20,12 @@ describe('ERC-7432 RoleGranted Handler', () => { clearStore() }) - test('should not grant role when NFT does not exist', () => { - assert.entityCount('Role', 0) + test('should not grant roleassignment when NFT does not exist', () => { + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 0) const event = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId, tokenAddress, grantee, @@ -36,17 +36,17 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 0) }) - test('should not grant role when grantor does not exist', () => { + test('should not grant roleassignment when grantor does not exist', () => { createMockNft(tokenAddress, tokenId, Addresses[0]) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 1) const event = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId, tokenAddress, grantee, @@ -57,18 +57,18 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 1) }) - test('should not grant role if grantor is not NFT owner', () => { + test('should not grant roleassignment if grantor is not NFT owner', () => { createMockNft(tokenAddress, tokenId, Addresses[0]) createMockAccount(grantor) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 2) const event = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId, tokenAddress, grantee, @@ -79,17 +79,17 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 2) }) test('should grant multiple roles for the same NFT', () => { const nft = createMockNft(tokenAddress, tokenId, grantor) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 1) const event1 = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId, tokenAddress, Addresses[0], @@ -100,7 +100,7 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event1) const event2 = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId, tokenAddress, Addresses[1], @@ -111,7 +111,7 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event2) const event3 = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId, tokenAddress, Addresses[2], @@ -122,13 +122,13 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event3) - assert.entityCount('Role', 3) + assert.entityCount('RoleAssignment', 3) assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) - validateRole(grantorAccount, new Account(Addresses[0]), nft, RoleId, expirationDate, data) - validateRole(grantorAccount, new Account(Addresses[1]), nft, RoleId, expirationDate, data) - validateRole(grantorAccount, new Account(Addresses[2]), nft, RoleId, expirationDate, data) + validateRole(grantorAccount, new Account(Addresses[0]), nft, RoleAssignmentId, expirationDate, data) + validateRole(grantorAccount, new Account(Addresses[1]), nft, RoleAssignmentId, expirationDate, data) + validateRole(grantorAccount, new Account(Addresses[2]), nft, RoleAssignmentId, expirationDate, data) }) test('should grant multiple roles for different NFTs', () => { @@ -139,11 +139,11 @@ describe('ERC-7432 RoleGranted Handler', () => { const nft1 = createMockNft(tokenAddress, tokenId1, grantor) const nft2 = createMockNft(tokenAddress, tokenId2, grantor) const nft3 = createMockNft(tokenAddress, tokenId3, grantor) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 1) const event1 = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId1, tokenAddress, Addresses[0], @@ -154,7 +154,7 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event1) const event2 = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId2, tokenAddress, Addresses[1], @@ -165,7 +165,7 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event2) const event3 = createNewRoleGrantedEvent( - RoleId, + RoleAssignmentId, tokenId3, tokenAddress, Addresses[2], @@ -176,12 +176,12 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event3) - assert.entityCount('Role', 3) + assert.entityCount('RoleAssignment', 3) assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) - validateRole(grantorAccount, new Account(Addresses[0]), nft1, RoleId, expirationDate, data) - validateRole(grantorAccount, new Account(Addresses[1]), nft2, RoleId, expirationDate, data) - validateRole(grantorAccount, new Account(Addresses[2]), nft3, RoleId, expirationDate, data) + validateRole(grantorAccount, new Account(Addresses[0]), nft1, RoleAssignmentId, expirationDate, data) + validateRole(grantorAccount, new Account(Addresses[1]), nft2, RoleAssignmentId, expirationDate, data) + validateRole(grantorAccount, new Account(Addresses[2]), nft3, RoleAssignmentId, expirationDate, data) }) }) diff --git a/tests/erc7432/revoke-handler.test.ts b/tests/erc7432/revoke-handler.test.ts index 2e9d364..e56aea0 100644 --- a/tests/erc7432/revoke-handler.test.ts +++ b/tests/erc7432/revoke-handler.test.ts @@ -2,13 +2,13 @@ import { assert, describe, test, clearStore, afterEach } from 'matchstick-as' import { createNewRoleRevokedEvent } from '../helpers/events' import { handleRoleRevoked } from '../../src/erc7432' import { Bytes, BigInt } from '@graphprotocol/graph-ts' -import { createMockAccount, createMockNft, createMockRole, validateRole } from '../helpers/entities' +import { createMockAccount, createMockNft, createMockRoleAssignment, validateRole } from '../helpers/entities' import { Addresses, ONE, TWO } from '../helpers/contants' -import { generateNftId, generateRoleId } from '../../src/utils/helper' +import { generateNftId, generateRoleAssignmentId } from '../../src/utils/helper' import { Account, Nft } from '../../generated/schema' const tokenId = '123' -const RoleId = Bytes.fromUTF8('0xGrantRole') +const RoleAssignmentId = Bytes.fromUTF8('0xGrantRole') const tokenAddress = Addresses[0] const grantee = Addresses[1] const revoker = Addresses[2] @@ -20,8 +20,8 @@ describe('ERC-7432 RoleRevoked Handler', () => { clearStore() }) - test('should not revoke role when NFT does not exist', () => { - assert.entityCount('Role', 0) + test('should not revoke roleassignment when NFT does not exist', () => { + assert.entityCount('RoleAssignment', 0) const nftId = generateNftId(tokenAddress, tokenId) const nft = new Nft(nftId) @@ -29,55 +29,55 @@ describe('ERC-7432 RoleRevoked Handler', () => { nft.tokenId = BigInt.fromString(tokenId) nft.owner = revoker - const event = createNewRoleRevokedEvent(RoleId, nft, revoker, grantee) + const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) }) - test('should not revoke role when revoker does not exist', () => { + test('should not revoke roleassignment when revoker does not exist', () => { const nft = createMockNft(tokenAddress, tokenId, Addresses[0]) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) - const event = createNewRoleRevokedEvent(RoleId, nft, revoker, grantee) + const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) }) - test('should not revoke role when grantee does not exist', () => { + test('should not revoke roleassignment when grantee does not exist', () => { const nft = createMockNft(tokenAddress, tokenId, revoker) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) - const event = createNewRoleRevokedEvent(RoleId, nft, revoker, grantee) + const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) }) - test('should not revoke role when role does not exist', () => { + test('should not revoke roleassignment when roleassignment does not exist', () => { const nft = createMockNft(tokenAddress, tokenId, revoker) createMockAccount(grantee) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) - const event = createNewRoleRevokedEvent(RoleId, nft, revoker, grantee) + const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) - assert.entityCount('Role', 0) + assert.entityCount('RoleAssignment', 0) }) - test('should not revoke role when role already expired', () => { + test('should not revoke roleassignment when roleassignment already expired', () => { const nft = createMockNft(tokenAddress, tokenId, revoker) const granteeAccount = createMockAccount(grantee) - createMockRole(RoleId, revoker, grantee, nft, BigInt.fromI32(0)) - assert.entityCount('Role', 1) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft, BigInt.fromI32(0)) + assert.entityCount('RoleAssignment', 1) - const event = createNewRoleRevokedEvent(RoleId, nft, revoker, grantee) + const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) - assert.entityCount('Role', 1) - const _id = generateRoleId(new Account(revoker), granteeAccount, nft, RoleId) - assert.fieldEquals('Role', _id, 'expirationDate', '0') + assert.entityCount('RoleAssignment', 1) + const _id = generateRoleAssignmentId(new Account(revoker), granteeAccount, nft, RoleAssignmentId) + assert.fieldEquals('RoleAssignment', _id, 'expirationDate', '0') }) test('should revoke multiple roles for the same NFT', () => { @@ -85,25 +85,25 @@ describe('ERC-7432 RoleRevoked Handler', () => { const account1 = createMockAccount(Addresses[0]) const account2 = createMockAccount(Addresses[1]) const account3 = createMockAccount(Addresses[2]) - createMockRole(RoleId, revoker, Addresses[0], nft, expirationDate) - createMockRole(RoleId, revoker, Addresses[1], nft, expirationDate.plus(ONE)) - createMockRole(RoleId, revoker, Addresses[2], nft, expirationDate.plus(TWO)) - assert.entityCount('Role', 3) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[0], nft, expirationDate) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[1], nft, expirationDate.plus(ONE)) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[2], nft, expirationDate.plus(TWO)) + assert.entityCount('RoleAssignment', 3) - const event1 = createNewRoleRevokedEvent(RoleId, nft, revoker, Addresses[0]) + const event1 = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, Addresses[0]) handleRoleRevoked(event1) - const event2 = createNewRoleRevokedEvent(RoleId, nft, revoker, Addresses[1]) + const event2 = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, Addresses[1]) handleRoleRevoked(event2) - const event3 = createNewRoleRevokedEvent(RoleId, nft, revoker, Addresses[2]) + const event3 = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, Addresses[2]) handleRoleRevoked(event3) - assert.entityCount('Role', 3) + assert.entityCount('RoleAssignment', 3) const revokerAccount = new Account(revoker) - validateRole(revokerAccount, account1, nft, RoleId, ONE, data) - validateRole(revokerAccount, account2, nft, RoleId, ONE, data) - validateRole(revokerAccount, account3, nft, RoleId, ONE, data) + validateRole(revokerAccount, account1, nft, RoleAssignmentId, ONE, data) + validateRole(revokerAccount, account2, nft, RoleAssignmentId, ONE, data) + validateRole(revokerAccount, account3, nft, RoleAssignmentId, ONE, data) }) test('should revoke multiple roles for different NFTs', () => { @@ -111,24 +111,24 @@ describe('ERC-7432 RoleRevoked Handler', () => { const nft1 = createMockNft(tokenAddress, '123', revoker) const nft2 = createMockNft(tokenAddress, '456', revoker) const nft3 = createMockNft(tokenAddress, '789', revoker) - createMockRole(RoleId, revoker, grantee, nft1, expirationDate) - createMockRole(RoleId, revoker, grantee, nft2, expirationDate.plus(ONE)) - createMockRole(RoleId, revoker, grantee, nft3, expirationDate.plus(TWO)) - assert.entityCount('Role', 3) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft1, expirationDate) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft2, expirationDate.plus(ONE)) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft3, expirationDate.plus(TWO)) + assert.entityCount('RoleAssignment', 3) - const event1 = createNewRoleRevokedEvent(RoleId, nft1, revoker, grantee) + const event1 = createNewRoleRevokedEvent(RoleAssignmentId, nft1, revoker, grantee) handleRoleRevoked(event1) - const event2 = createNewRoleRevokedEvent(RoleId, nft2, revoker, grantee) + const event2 = createNewRoleRevokedEvent(RoleAssignmentId, nft2, revoker, grantee) handleRoleRevoked(event2) - const event3 = createNewRoleRevokedEvent(RoleId, nft3, revoker, grantee) + const event3 = createNewRoleRevokedEvent(RoleAssignmentId, nft3, revoker, grantee) handleRoleRevoked(event3) - assert.entityCount('Role', 3) + assert.entityCount('RoleAssignment', 3) const revokerAccount = new Account(revoker) - validateRole(revokerAccount, granteeAccount, nft1, RoleId, ONE, data) - validateRole(revokerAccount, granteeAccount, nft2, RoleId, ONE, data) - validateRole(revokerAccount, granteeAccount, nft3, RoleId, ONE, data) + validateRole(revokerAccount, granteeAccount, nft1, RoleAssignmentId, ONE, data) + validateRole(revokerAccount, granteeAccount, nft2, RoleAssignmentId, ONE, data) + validateRole(revokerAccount, granteeAccount, nft3, RoleAssignmentId, ONE, data) }) }) diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index 5df1ca4..553bb61 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -1,6 +1,6 @@ import { BigInt, Bytes } from '@graphprotocol/graph-ts' -import { Account, Nft, Role, RoleApproval } from '../../generated/schema' -import { generateNftId, generateRoleId, generateRoleApprovalId } from '../../src/utils/helper' +import { Account, Nft, RoleAssignment, RoleApproval } from '../../generated/schema' +import { generateNftId, generateRoleAssignmentId, generateRoleApprovalId } from '../../src/utils/helper' import { assert } from 'matchstick-as' export function createMockNft(tokenAddress: string, tokenId: string, ownerAddress: string): Nft { @@ -21,18 +21,19 @@ export function createMockAccount(ethAddress: string): Account { return account } -export function createMockRole(role: Bytes, grantor: string, grantee: string, nft: Nft, expirationDate: BigInt): Role { - const roleId = generateRoleId(new Account(grantor), new Account(grantee), nft, role) - const newRole = new Role(roleId) - newRole.roleId = role - newRole.nft = nft.id - newRole.grantor = grantor - newRole.grantee = grantee - newRole.expirationDate = expirationDate - newRole.revocable = true - newRole.data = Bytes.fromUTF8('data') - newRole.save() - return newRole +export function createMockRoleAssignment(roleHash: Bytes, grantor: string, grantee: string, nft: Nft, expirationDate: BigInt): RoleAssignment { + const roleAssignmentId = generateRoleAssignmentId(new Account(grantor), new Account(grantee), nft, roleHash) + const newRoleAssignment = new RoleAssignment(roleAssignmentId) + newRoleAssignment.role = `${nft.id}-${roleHash.toHex()}` + newRoleAssignment.nft = nft.id + newRoleAssignment.grantor = grantor + newRoleAssignment.grantee = grantee + newRoleAssignment.expirationDate = expirationDate + newRoleAssignment.revocable = true + newRoleAssignment.data = Bytes.fromUTF8('data') + newRoleAssignment.timestamp = BigInt.fromI32(123) + newRoleAssignment.save() + return newRoleAssignment } export function createMockRoleApproval(grantor: string, operator: string, tokenAddress: string): RoleApproval { @@ -49,17 +50,17 @@ export function validateRole( grantor: Account, grantee: Account, nft: Nft, - role: Bytes, + roleAssignment: Bytes, expirationDate: BigInt, data: Bytes, ): void { - const _id = generateRoleId(grantor, grantee, nft, role) - assert.fieldEquals('Role', _id, 'roleId', role.toHex()) - assert.fieldEquals('Role', _id, 'nft', nft.id) - assert.fieldEquals('Role', _id, 'grantor', grantor.id) - assert.fieldEquals('Role', _id, 'grantee', grantee.id) - assert.fieldEquals('Role', _id, 'expirationDate', expirationDate.toString()) - assert.fieldEquals('Role', _id, 'data', data.toHex()) + const _id = generateRoleAssignmentId(grantor, grantee, nft, roleAssignment) + assert.fieldEquals('RoleAssignment', _id, 'role', `${nft.id}-${roleAssignment.toHex()}`) + assert.fieldEquals('RoleAssignment', _id, 'nft', nft.id) + assert.fieldEquals('RoleAssignment', _id, 'grantor', grantor.id) + assert.fieldEquals('RoleAssignment', _id, 'grantee', grantee.id) + assert.fieldEquals('RoleAssignment', _id, 'expirationDate', expirationDate.toString()) + assert.fieldEquals('RoleAssignment', _id, 'data', data.toHex()) } export function validateRoleApproval(grantor: string, operator: string, tokenAddress: string): void { diff --git a/tests/helpers/events.ts b/tests/helpers/events.ts index b12cdf1..7780ad1 100644 --- a/tests/helpers/events.ts +++ b/tests/helpers/events.ts @@ -14,10 +14,10 @@ export function createTransferEvent(from: string, to: string, tokenId: string, a return event } -export function createNewRoleRevokedEvent(role: Bytes, nft: Nft, revoker: string, grantee: string): RoleRevoked { +export function createNewRoleRevokedEvent(roleassignment: Bytes, nft: Nft, revoker: string, grantee: string): RoleRevoked { const event = changetype(newMockEvent()) event.parameters = new Array() - event.parameters.push(buildEventParamBytes('_role', role)) + event.parameters.push(buildEventParamBytes('_role', roleassignment)) event.parameters.push(buildEventParamAddress('_tokenAddress', nft.address)) event.parameters.push(buildEventParamUint('_tokenId', nft.tokenId)) event.parameters.push(buildEventParamAddress('_revoker', revoker)) @@ -26,7 +26,7 @@ export function createNewRoleRevokedEvent(role: Bytes, nft: Nft, revoker: string } export function createNewRoleGrantedEvent( - role: Bytes, + roleassignment: Bytes, tokenId: string, tokenAddress: string, grantee: string, @@ -37,7 +37,7 @@ export function createNewRoleGrantedEvent( ): RoleGranted { const event = changetype(newMockEvent()) event.parameters = new Array() - event.parameters.push(buildEventParamBytes('_role', role)) + event.parameters.push(buildEventParamBytes('_role', roleassignment)) event.parameters.push(buildEventParamAddress('_tokenAddress', tokenAddress)) event.parameters.push(buildEventParamUint('_tokenId', BigInt.fromString(tokenId))) event.parameters.push(buildEventParamAddress('_grantor', grantor)) From c10fb9374de4ae04ece28d88cca7b810469fe2a3 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Fri, 20 Oct 2023 16:02:13 -0300 Subject: [PATCH 2/9] lint --- package-lock.json | 2 +- src/erc7432/role/grant-handler.ts | 6 +++++- src/erc7432/role/revoke-handler.ts | 6 +++++- src/utils/helper.ts | 10 +++++++--- tests/helpers/entities.ts | 8 +++++++- tests/helpers/events.ts | 7 ++++++- 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 15988b4..e4b76f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "": { "name": "roles-subgraph", "version": "1.0.0", - "license": "MIT", + "license": "CC0-1.0", "dependencies": { "@graphprotocol/graph-cli": "^0.55.0" }, diff --git a/src/erc7432/role/grant-handler.ts b/src/erc7432/role/grant-handler.ts index f9c3e07..f71db3d 100644 --- a/src/erc7432/role/grant-handler.ts +++ b/src/erc7432/role/grant-handler.ts @@ -27,5 +27,9 @@ export function handleRoleGranted(event: RoleGranted): void { const granteeAccount = findOrCreateAccount(event.params._grantee.toHex()) const roleAssignment = findOrCreateRoleAssignment(event, grantorAccount, granteeAccount, nft) - log.warning('[handleRoleGranted] roleAssignment: {} NFT: {} Tx: {}', [roleAssignment.id, nftId, event.transaction.hash.toHex()]) + log.warning('[handleRoleGranted] roleAssignment: {} NFT: {} Tx: {}', [ + roleAssignment.id, + nftId, + event.transaction.hash.toHex(), + ]) } diff --git a/src/erc7432/role/revoke-handler.ts b/src/erc7432/role/revoke-handler.ts index 3c6f252..bf368a1 100644 --- a/src/erc7432/role/revoke-handler.ts +++ b/src/erc7432/role/revoke-handler.ts @@ -41,5 +41,9 @@ export function handleRoleRevoked(event: RoleRevoked): void { roleassignment.expirationDate = event.block.timestamp roleassignment.save() - log.warning('[handleRoleRevoked] Revoked RoleAssignment: {} NFT: {} Tx: {}', [roleAssignmentId, nftId, event.transaction.hash.toHex()]) + log.warning('[handleRoleRevoked] Revoked RoleAssignment: {} NFT: {} Tx: {}', [ + roleAssignmentId, + nftId, + event.transaction.hash.toHex(), + ]) } diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 64421db..5f283b8 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -29,7 +29,12 @@ export function generateRoleAssignmentId(grantor: Account, grantee: Account, nft return grantor.id + '-' + grantee.id + '-' + nft.id + '-' + roleAssignment.toHex() } -export function findOrCreateRoleAssignment(event: RoleGranted, grantor: Account, grantee: Account, nft: Nft): RoleAssignment { +export function findOrCreateRoleAssignment( + event: RoleGranted, + grantor: Account, + grantee: Account, + nft: Nft, +): RoleAssignment { const roleAssignmentId = generateRoleAssignmentId(grantor, grantee, nft, event.params._role) let roleAssignment = RoleAssignment.load(roleAssignmentId) @@ -50,10 +55,9 @@ export function findOrCreateRoleAssignment(event: RoleGranted, grantor: Account, } export function findOrCreateRole(nft: Nft, roleHash: Bytes): Role { - let role = Role.load(generateRoleId(nft, roleHash)) - if(!role) { + if (!role) { role = new Role(generateRoleId(nft, roleHash)) role.roleHash = roleHash role.save() diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index 553bb61..3101373 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -21,7 +21,13 @@ export function createMockAccount(ethAddress: string): Account { return account } -export function createMockRoleAssignment(roleHash: Bytes, grantor: string, grantee: string, nft: Nft, expirationDate: BigInt): RoleAssignment { +export function createMockRoleAssignment( + roleHash: Bytes, + grantor: string, + grantee: string, + nft: Nft, + expirationDate: BigInt, +): RoleAssignment { const roleAssignmentId = generateRoleAssignmentId(new Account(grantor), new Account(grantee), nft, roleHash) const newRoleAssignment = new RoleAssignment(roleAssignmentId) newRoleAssignment.role = `${nft.id}-${roleHash.toHex()}` diff --git a/tests/helpers/events.ts b/tests/helpers/events.ts index 7780ad1..954b5f9 100644 --- a/tests/helpers/events.ts +++ b/tests/helpers/events.ts @@ -14,7 +14,12 @@ export function createTransferEvent(from: string, to: string, tokenId: string, a return event } -export function createNewRoleRevokedEvent(roleassignment: Bytes, nft: Nft, revoker: string, grantee: string): RoleRevoked { +export function createNewRoleRevokedEvent( + roleassignment: Bytes, + nft: Nft, + revoker: string, + grantee: string, +): RoleRevoked { const event = changetype(newMockEvent()) event.parameters = new Array() event.parameters.push(buildEventParamBytes('_role', roleassignment)) From ac8f1674c229783745eaf6382cde394085d736e2 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Fri, 20 Oct 2023 16:08:47 -0300 Subject: [PATCH 3/9] update role history --- schema.graphql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/schema.graphql b/schema.graphql index 3c63820..a6e46fe 100644 --- a/schema.graphql +++ b/schema.graphql @@ -3,7 +3,7 @@ type Nft @entity { address: String! tokenId: BigInt! owner: Account! - rolesHistory: [RoleAssignment!] @derivedFrom(field: "nft") + rolesHistory: [Role!] @derivedFrom(field: "nft") } type Account @entity { @@ -29,6 +29,7 @@ type RoleAssignment @entity { type Role @entity { id: ID! # tokenId + tokenAddress + roleHash roleHash: Bytes! + nft: Nft! roleAssignments: [RoleAssignment!] @derivedFrom(field: "role") } From 6501d197b2ec97201f5ab3f1bff92781f5b45fac Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Fri, 20 Oct 2023 16:12:06 -0300 Subject: [PATCH 4/9] fix role creation --- src/utils/helper.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 5f283b8..1b2507e 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -60,6 +60,7 @@ export function findOrCreateRole(nft: Nft, roleHash: Bytes): Role { if (!role) { role = new Role(generateRoleId(nft, roleHash)) role.roleHash = roleHash + role.nft = nft.id role.save() } From a4f0d30744881fedd0cf83eb6c66f3661aa504fe Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Fri, 20 Oct 2023 18:00:17 -0300 Subject: [PATCH 5/9] PR fixes --- abis/ERC7432.json | 4 ++-- schema.graphql | 4 ++-- src/utils/helper.ts | 2 +- tests/erc721/transfer-handler.test.ts | 6 +++--- tests/erc7432/revoke-handler.test.ts | 2 +- tests/helpers/entities.ts | 2 +- tests/helpers/events.ts | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/abis/ERC7432.json b/abis/ERC7432.json index ebb3940..47f3b19 100644 --- a/abis/ERC7432.json +++ b/abis/ERC7432.json @@ -122,7 +122,7 @@ "components": [ { "internalType": "bytes32", - "name": "roleassignment", + "name": "role", "type": "bytes32" }, { @@ -172,7 +172,7 @@ "components": [ { "internalType": "bytes32", - "name": "roleassignment", + "name": "role", "type": "bytes32" }, { diff --git a/schema.graphql b/schema.graphql index a6e46fe..fed3ff6 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1,9 +1,9 @@ type Nft @entity { id: ID! # tokenId + tokenAddress - address: String! + tokenAddress: String! tokenId: BigInt! owner: Account! - rolesHistory: [Role!] @derivedFrom(field: "nft") + roles: [Role!] @derivedFrom(field: "nft") } type Account @entity { diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 1b2507e..c253312 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -15,7 +15,7 @@ export function findOrCreateAccount(id: string): Account { export function createNft(id: string, contractAddress: string, tokenId: BigInt, owner: string): Nft { const nft = new Nft(id) nft.tokenId = tokenId - nft.address = contractAddress.toLowerCase() + nft.tokenAddress = contractAddress.toLowerCase() nft.owner = owner.toLowerCase() nft.save() return nft diff --git a/tests/erc721/transfer-handler.test.ts b/tests/erc721/transfer-handler.test.ts index dcc3f24..c12a5ae 100644 --- a/tests/erc721/transfer-handler.test.ts +++ b/tests/erc721/transfer-handler.test.ts @@ -22,7 +22,7 @@ describe('ERC-721 Transfer Handler', () => { assert.entityCount('Account', 1) const _id = generateNftId(event.address.toHexString(), event.params.tokenId.toString()) - assert.fieldEquals('Nft', _id, 'address', ZERO_ADDRESS) + assert.fieldEquals('Nft', _id, 'tokenAddress', ZERO_ADDRESS) assert.fieldEquals('Nft', _id, 'tokenId', tokenId) assert.fieldEquals('Nft', _id, 'owner', Addresses[1]) }) @@ -38,7 +38,7 @@ describe('ERC-721 Transfer Handler', () => { assert.entityCount('Account', 2) const _id = generateNftId(event.address.toHexString(), event.params.tokenId.toString()) - assert.fieldEquals('Nft', _id, 'address', ZERO_ADDRESS) + assert.fieldEquals('Nft', _id, 'tokenAddress', ZERO_ADDRESS) assert.fieldEquals('Nft', _id, 'tokenId', tokenId) assert.fieldEquals('Nft', _id, 'owner', Addresses[2]) }) @@ -54,7 +54,7 @@ describe('ERC-721 Transfer Handler', () => { assert.entityCount('Account', 2) const _id = generateNftId(event.address.toHexString(), event.params.tokenId.toString()) - assert.fieldEquals('Nft', _id, 'address', ZERO_ADDRESS) + assert.fieldEquals('Nft', _id, 'tokenAddress', ZERO_ADDRESS) assert.fieldEquals('Nft', _id, 'tokenId', tokenId) assert.fieldEquals('Nft', _id, 'owner', Addresses[2]) }) diff --git a/tests/erc7432/revoke-handler.test.ts b/tests/erc7432/revoke-handler.test.ts index e56aea0..601a3ac 100644 --- a/tests/erc7432/revoke-handler.test.ts +++ b/tests/erc7432/revoke-handler.test.ts @@ -25,7 +25,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { const nftId = generateNftId(tokenAddress, tokenId) const nft = new Nft(nftId) - nft.address = tokenAddress + nft.tokenAddress = tokenAddress nft.tokenId = BigInt.fromString(tokenId) nft.owner = revoker diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index 3101373..bf2503a 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -5,7 +5,7 @@ import { assert } from 'matchstick-as' export function createMockNft(tokenAddress: string, tokenId: string, ownerAddress: string): Nft { const nft = new Nft(generateNftId(tokenAddress, tokenId)) - nft.address = tokenAddress + nft.tokenAddress = tokenAddress nft.tokenId = BigInt.fromString(tokenId) const nftOwner = createMockAccount(ownerAddress) diff --git a/tests/helpers/events.ts b/tests/helpers/events.ts index 954b5f9..f4437b0 100644 --- a/tests/helpers/events.ts +++ b/tests/helpers/events.ts @@ -23,7 +23,7 @@ export function createNewRoleRevokedEvent( const event = changetype(newMockEvent()) event.parameters = new Array() event.parameters.push(buildEventParamBytes('_role', roleassignment)) - event.parameters.push(buildEventParamAddress('_tokenAddress', nft.address)) + event.parameters.push(buildEventParamAddress('_tokenAddress', nft.tokenAddress)) event.parameters.push(buildEventParamUint('_tokenId', nft.tokenId)) event.parameters.push(buildEventParamAddress('_revoker', revoker)) event.parameters.push(buildEventParamAddress('_grantee', grantee)) From f248e89df7a12bc922f3bd6e598b02dfa2eb73a1 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 23 Oct 2023 09:43:18 -0300 Subject: [PATCH 6/9] pr fixes --- schema.graphql | 2 +- src/erc7432/role/revoke-handler.ts | 10 +++++----- src/utils/helper.ts | 2 +- tests/erc7432/grant-handler.test.ts | 6 +++--- tests/erc7432/revoke-handler.test.ts | 10 +++++----- tests/helpers/entities.ts | 2 +- tests/helpers/events.ts | 8 ++++---- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/schema.graphql b/schema.graphql index fed3ff6..e2fb13a 100644 --- a/schema.graphql +++ b/schema.graphql @@ -23,7 +23,7 @@ type RoleAssignment @entity { expirationDate: BigInt! revocable: Boolean! data: Bytes! - timestamp: BigInt! + createdAt: BigInt! } type Role @entity { diff --git a/src/erc7432/role/revoke-handler.ts b/src/erc7432/role/revoke-handler.ts index bf368a1..ab6fe02 100644 --- a/src/erc7432/role/revoke-handler.ts +++ b/src/erc7432/role/revoke-handler.ts @@ -29,18 +29,18 @@ export function handleRoleRevoked(event: RoleRevoked): void { } const roleAssignmentId = generateRoleAssignmentId(revoker, grantee, nft, event.params._role) - const roleassignment = RoleAssignment.load(roleAssignmentId) - if (!roleassignment) { + const roleAssignment = RoleAssignment.load(roleAssignmentId) + if (!roleAssignment) { log.warning('[handleRoleRevoked] RoleAssignment {} does not exist, skipping...', [roleAssignmentId]) return } - if (event.block.timestamp > roleassignment.expirationDate) { + if (event.block.timestamp > roleAssignment.expirationDate) { log.warning('[handleRoleRevoked] RoleAssignment {} already expired, skipping...', [roleAssignmentId]) return } - roleassignment.expirationDate = event.block.timestamp - roleassignment.save() + roleAssignment.expirationDate = event.block.timestamp + roleAssignment.save() log.warning('[handleRoleRevoked] Revoked RoleAssignment: {} NFT: {} Tx: {}', [ roleAssignmentId, nftId, diff --git a/src/utils/helper.ts b/src/utils/helper.ts index c253312..c295744 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -49,7 +49,7 @@ export function findOrCreateRoleAssignment( roleAssignment.expirationDate = event.params._expirationDate roleAssignment.revocable = event.params._revocable roleAssignment.data = event.params._data - roleAssignment.timestamp = event.block.timestamp + roleAssignment.createdAt = event.block.timestamp roleAssignment.save() return roleAssignment } diff --git a/tests/erc7432/grant-handler.test.ts b/tests/erc7432/grant-handler.test.ts index 45658c7..f858670 100644 --- a/tests/erc7432/grant-handler.test.ts +++ b/tests/erc7432/grant-handler.test.ts @@ -20,7 +20,7 @@ describe('ERC-7432 RoleGranted Handler', () => { clearStore() }) - test('should not grant roleassignment when NFT does not exist', () => { + test('should not grant roleAssignment when NFT does not exist', () => { assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 0) @@ -40,7 +40,7 @@ describe('ERC-7432 RoleGranted Handler', () => { assert.entityCount('Account', 0) }) - test('should not grant roleassignment when grantor does not exist', () => { + test('should not grant roleAssignment when grantor does not exist', () => { createMockNft(tokenAddress, tokenId, Addresses[0]) assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 1) @@ -61,7 +61,7 @@ describe('ERC-7432 RoleGranted Handler', () => { assert.entityCount('Account', 1) }) - test('should not grant roleassignment if grantor is not NFT owner', () => { + test('should not grant roleAssignment if grantor is not NFT owner', () => { createMockNft(tokenAddress, tokenId, Addresses[0]) createMockAccount(grantor) assert.entityCount('RoleAssignment', 0) diff --git a/tests/erc7432/revoke-handler.test.ts b/tests/erc7432/revoke-handler.test.ts index 601a3ac..7d1e6c3 100644 --- a/tests/erc7432/revoke-handler.test.ts +++ b/tests/erc7432/revoke-handler.test.ts @@ -20,7 +20,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { clearStore() }) - test('should not revoke roleassignment when NFT does not exist', () => { + test('should not revoke roleAssignment when NFT does not exist', () => { assert.entityCount('RoleAssignment', 0) const nftId = generateNftId(tokenAddress, tokenId) @@ -35,7 +35,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { assert.entityCount('RoleAssignment', 0) }) - test('should not revoke roleassignment when revoker does not exist', () => { + test('should not revoke roleAssignment when revoker does not exist', () => { const nft = createMockNft(tokenAddress, tokenId, Addresses[0]) assert.entityCount('RoleAssignment', 0) @@ -45,7 +45,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { assert.entityCount('RoleAssignment', 0) }) - test('should not revoke roleassignment when grantee does not exist', () => { + test('should not revoke roleAssignment when grantee does not exist', () => { const nft = createMockNft(tokenAddress, tokenId, revoker) assert.entityCount('RoleAssignment', 0) @@ -55,7 +55,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { assert.entityCount('RoleAssignment', 0) }) - test('should not revoke roleassignment when roleassignment does not exist', () => { + test('should not revoke roleAssignment when roleAssignment does not exist', () => { const nft = createMockNft(tokenAddress, tokenId, revoker) createMockAccount(grantee) assert.entityCount('RoleAssignment', 0) @@ -66,7 +66,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { assert.entityCount('RoleAssignment', 0) }) - test('should not revoke roleassignment when roleassignment already expired', () => { + test('should not revoke roleAssignment when roleAssignment already expired', () => { const nft = createMockNft(tokenAddress, tokenId, revoker) const granteeAccount = createMockAccount(grantee) createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft, BigInt.fromI32(0)) diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index bf2503a..ca4c168 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -37,7 +37,7 @@ export function createMockRoleAssignment( newRoleAssignment.expirationDate = expirationDate newRoleAssignment.revocable = true newRoleAssignment.data = Bytes.fromUTF8('data') - newRoleAssignment.timestamp = BigInt.fromI32(123) + newRoleAssignment.createdAt = BigInt.fromI32(123) newRoleAssignment.save() return newRoleAssignment } diff --git a/tests/helpers/events.ts b/tests/helpers/events.ts index f4437b0..b51372d 100644 --- a/tests/helpers/events.ts +++ b/tests/helpers/events.ts @@ -15,14 +15,14 @@ export function createTransferEvent(from: string, to: string, tokenId: string, a } export function createNewRoleRevokedEvent( - roleassignment: Bytes, + roleAssignment: Bytes, nft: Nft, revoker: string, grantee: string, ): RoleRevoked { const event = changetype(newMockEvent()) event.parameters = new Array() - event.parameters.push(buildEventParamBytes('_role', roleassignment)) + event.parameters.push(buildEventParamBytes('_role', roleAssignment)) event.parameters.push(buildEventParamAddress('_tokenAddress', nft.tokenAddress)) event.parameters.push(buildEventParamUint('_tokenId', nft.tokenId)) event.parameters.push(buildEventParamAddress('_revoker', revoker)) @@ -31,7 +31,7 @@ export function createNewRoleRevokedEvent( } export function createNewRoleGrantedEvent( - roleassignment: Bytes, + roleAssignment: Bytes, tokenId: string, tokenAddress: string, grantee: string, @@ -42,7 +42,7 @@ export function createNewRoleGrantedEvent( ): RoleGranted { const event = changetype(newMockEvent()) event.parameters = new Array() - event.parameters.push(buildEventParamBytes('_role', roleassignment)) + event.parameters.push(buildEventParamBytes('_role', roleAssignment)) event.parameters.push(buildEventParamAddress('_tokenAddress', tokenAddress)) event.parameters.push(buildEventParamUint('_tokenId', BigInt.fromString(tokenId))) event.parameters.push(buildEventParamAddress('_grantor', grantor)) From f8139d7df907f974dcf3d7625c0703feb0d6adfd Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 23 Oct 2023 10:43:39 -0300 Subject: [PATCH 7/9] Update tests with Role entity assert --- tests/erc7432/grant-handler.test.ts | 9 +++++++++ tests/erc7432/revoke-handler.test.ts | 4 ++++ tests/helpers/entities.ts | 28 +++++++++++++++++++--------- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tests/erc7432/grant-handler.test.ts b/tests/erc7432/grant-handler.test.ts index f858670..f91fc82 100644 --- a/tests/erc7432/grant-handler.test.ts +++ b/tests/erc7432/grant-handler.test.ts @@ -36,6 +36,7 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event) + assert.entityCount('Role', 0) assert.entityCount('RoleAssignment', 0) assert.entityCount('Account', 0) }) @@ -43,6 +44,7 @@ describe('ERC-7432 RoleGranted Handler', () => { test('should not grant roleAssignment when grantor does not exist', () => { createMockNft(tokenAddress, tokenId, Addresses[0]) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) assert.entityCount('Account', 1) const event = createNewRoleGrantedEvent( @@ -58,6 +60,7 @@ describe('ERC-7432 RoleGranted Handler', () => { handleRoleGranted(event) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) assert.entityCount('Account', 1) }) @@ -65,6 +68,7 @@ describe('ERC-7432 RoleGranted Handler', () => { createMockNft(tokenAddress, tokenId, Addresses[0]) createMockAccount(grantor) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) assert.entityCount('Account', 2) const event = createNewRoleGrantedEvent( @@ -80,12 +84,14 @@ describe('ERC-7432 RoleGranted Handler', () => { handleRoleGranted(event) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) assert.entityCount('Account', 2) }) test('should grant multiple roles for the same NFT', () => { const nft = createMockNft(tokenAddress, tokenId, grantor) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) assert.entityCount('Account', 1) const event1 = createNewRoleGrantedEvent( @@ -123,6 +129,7 @@ describe('ERC-7432 RoleGranted Handler', () => { handleRoleGranted(event3) assert.entityCount('RoleAssignment', 3) + assert.entityCount('Role', 1) assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) @@ -140,6 +147,7 @@ describe('ERC-7432 RoleGranted Handler', () => { const nft2 = createMockNft(tokenAddress, tokenId2, grantor) const nft3 = createMockNft(tokenAddress, tokenId3, grantor) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) assert.entityCount('Account', 1) const event1 = createNewRoleGrantedEvent( @@ -177,6 +185,7 @@ describe('ERC-7432 RoleGranted Handler', () => { handleRoleGranted(event3) assert.entityCount('RoleAssignment', 3) + assert.entityCount('Role', 3) assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) diff --git a/tests/erc7432/revoke-handler.test.ts b/tests/erc7432/revoke-handler.test.ts index 7d1e6c3..ba8d5a6 100644 --- a/tests/erc7432/revoke-handler.test.ts +++ b/tests/erc7432/revoke-handler.test.ts @@ -89,6 +89,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[1], nft, expirationDate.plus(ONE)) createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[2], nft, expirationDate.plus(TWO)) assert.entityCount('RoleAssignment', 3) + assert.entityCount('Role', 1) const event1 = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, Addresses[0]) handleRoleRevoked(event1) @@ -100,6 +101,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { handleRoleRevoked(event3) assert.entityCount('RoleAssignment', 3) + assert.entityCount('Role', 1) const revokerAccount = new Account(revoker) validateRole(revokerAccount, account1, nft, RoleAssignmentId, ONE, data) validateRole(revokerAccount, account2, nft, RoleAssignmentId, ONE, data) @@ -115,6 +117,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft2, expirationDate.plus(ONE)) createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft3, expirationDate.plus(TWO)) assert.entityCount('RoleAssignment', 3) + assert.entityCount('Role', 3) const event1 = createNewRoleRevokedEvent(RoleAssignmentId, nft1, revoker, grantee) handleRoleRevoked(event1) @@ -126,6 +129,7 @@ describe('ERC-7432 RoleRevoked Handler', () => { handleRoleRevoked(event3) assert.entityCount('RoleAssignment', 3) + assert.entityCount('Role', 3) const revokerAccount = new Account(revoker) validateRole(revokerAccount, granteeAccount, nft1, RoleAssignmentId, ONE, data) validateRole(revokerAccount, granteeAccount, nft2, RoleAssignmentId, ONE, data) diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index ca4c168..3b25d62 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -1,6 +1,6 @@ import { BigInt, Bytes } from '@graphprotocol/graph-ts' -import { Account, Nft, RoleAssignment, RoleApproval } from '../../generated/schema' -import { generateNftId, generateRoleAssignmentId, generateRoleApprovalId } from '../../src/utils/helper' +import { Account, Nft, RoleAssignment, RoleApproval, Role } from '../../generated/schema' +import { generateNftId, generateRoleAssignmentId, generateRoleApprovalId, generateRoleId } from '../../src/utils/helper' import { assert } from 'matchstick-as' export function createMockNft(tokenAddress: string, tokenId: string, ownerAddress: string): Nft { @@ -28,6 +28,12 @@ export function createMockRoleAssignment( nft: Nft, expirationDate: BigInt, ): RoleAssignment { + const roleId = generateRoleId(nft, roleHash) + const role = new Role(roleId) + role.roleHash = roleHash + role.nft = nft.id + role.save() + const roleAssignmentId = generateRoleAssignmentId(new Account(grantor), new Account(grantee), nft, roleHash) const newRoleAssignment = new RoleAssignment(roleAssignmentId) newRoleAssignment.role = `${nft.id}-${roleHash.toHex()}` @@ -60,13 +66,17 @@ export function validateRole( expirationDate: BigInt, data: Bytes, ): void { - const _id = generateRoleAssignmentId(grantor, grantee, nft, roleAssignment) - assert.fieldEquals('RoleAssignment', _id, 'role', `${nft.id}-${roleAssignment.toHex()}`) - assert.fieldEquals('RoleAssignment', _id, 'nft', nft.id) - assert.fieldEquals('RoleAssignment', _id, 'grantor', grantor.id) - assert.fieldEquals('RoleAssignment', _id, 'grantee', grantee.id) - assert.fieldEquals('RoleAssignment', _id, 'expirationDate', expirationDate.toString()) - assert.fieldEquals('RoleAssignment', _id, 'data', data.toHex()) + const roleId = generateRoleId(nft, roleAssignment) + assert.fieldEquals('Role', roleId, 'roleHash', roleAssignment.toHex()) + assert.fieldEquals('Role', roleId, 'nft', nft.id) + + const roleAssignemntId = generateRoleAssignmentId(grantor, grantee, nft, roleAssignment) + assert.fieldEquals('RoleAssignment', roleAssignemntId, 'role', `${nft.id}-${roleAssignment.toHex()}`) + assert.fieldEquals('RoleAssignment', roleAssignemntId, 'nft', nft.id) + assert.fieldEquals('RoleAssignment', roleAssignemntId, 'grantor', grantor.id) + assert.fieldEquals('RoleAssignment', roleAssignemntId, 'grantee', grantee.id) + assert.fieldEquals('RoleAssignment', roleAssignemntId, 'expirationDate', expirationDate.toString()) + assert.fieldEquals('RoleAssignment', roleAssignemntId, 'data', data.toHex()) } export function validateRoleApproval(grantor: string, operator: string, tokenAddress: string): void { From 285bd65b9b4d5884a8c79f86a4ee1d2701aae928 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 23 Oct 2023 11:45:40 -0300 Subject: [PATCH 8/9] add updatedAt field in role assingment entity --- schema.graphql | 1 + src/utils/helper.ts | 3 ++- tests/helpers/entities.ts | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/schema.graphql b/schema.graphql index e2fb13a..636fd88 100644 --- a/schema.graphql +++ b/schema.graphql @@ -24,6 +24,7 @@ type RoleAssignment @entity { revocable: Boolean! data: Bytes! createdAt: BigInt! + updatedAt: BigInt! } type Role @entity { diff --git a/src/utils/helper.ts b/src/utils/helper.ts index c295744..6a34b86 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -44,12 +44,13 @@ export function findOrCreateRoleAssignment( roleAssignment.nft = nft.id roleAssignment.grantor = grantor.id roleAssignment.grantee = grantee.id + roleAssignment.createdAt = event.block.timestamp } roleAssignment.expirationDate = event.params._expirationDate roleAssignment.revocable = event.params._revocable roleAssignment.data = event.params._data - roleAssignment.createdAt = event.block.timestamp + roleAssignment.updatedAt = event.block.timestamp roleAssignment.save() return roleAssignment } diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index 3b25d62..a3214f9 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -44,6 +44,7 @@ export function createMockRoleAssignment( newRoleAssignment.revocable = true newRoleAssignment.data = Bytes.fromUTF8('data') newRoleAssignment.createdAt = BigInt.fromI32(123) + newRoleAssignment.updatedAt = BigInt.fromI32(123) newRoleAssignment.save() return newRoleAssignment } From e87422cdb4d6d20d0605922e5ec9f6a3029175b8 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 23 Oct 2023 12:13:40 -0300 Subject: [PATCH 9/9] update utils --- src/utils/helper.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 6a34b86..2c65c04 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -56,10 +56,11 @@ export function findOrCreateRoleAssignment( } export function findOrCreateRole(nft: Nft, roleHash: Bytes): Role { - let role = Role.load(generateRoleId(nft, roleHash)) + const roleId = generateRoleId(nft, roleHash) + let role = Role.load(roleId) if (!role) { - role = new Role(generateRoleId(nft, roleHash)) + role = new Role(roleId) role.roleHash = roleHash role.nft = nft.id role.save()