From 00b9c74207e3295443bd9d8e9735e4b082c17033 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 24 Oct 2023 15:39:55 -0300 Subject: [PATCH 1/6] anonymous events --- subgraph-goerli.yaml | 1 - subgraph-mumbai.yaml | 2 -- subgraph-polygon.yaml | 1 - 3 files changed, 4 deletions(-) diff --git a/subgraph-goerli.yaml b/subgraph-goerli.yaml index f5bd44b..582f976 100644 --- a/subgraph-goerli.yaml +++ b/subgraph-goerli.yaml @@ -28,7 +28,6 @@ dataSources: kind: ethereum network: goerli source: - address: '0xb2ad616e84e1ef7a9ed0fa3169aaf31ee51ea824' abi: ERC7432 startBlock: 9815688 mapping: diff --git a/subgraph-mumbai.yaml b/subgraph-mumbai.yaml index 6f506ea..a36016b 100644 --- a/subgraph-mumbai.yaml +++ b/subgraph-mumbai.yaml @@ -2,13 +2,11 @@ specVersion: 0.0.4 schema: file: ./schema.graphql dataSources: - # There is no "(Chronos) Traveler" on Mumbai - name: ERC7432-Immutable-Roles kind: ethereum network: mumbai source: - address: '0xb2ad616e84e1ef7a9ed0fa3169aaf31ee51ea824' abi: ERC7432 startBlock: 40877849 mapping: diff --git a/subgraph-polygon.yaml b/subgraph-polygon.yaml index 423c619..d547ca5 100644 --- a/subgraph-polygon.yaml +++ b/subgraph-polygon.yaml @@ -28,7 +28,6 @@ dataSources: kind: ethereum network: matic source: - address: '0xb2ad616e84e1ef7a9ed0fa3169aaf31ee51ea824' abi: ERC7432 startBlock: 48672001 mapping: From 1efa572bf3edb0dd2d4aa65c4598a304999e47bc Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 24 Oct 2023 16:42:56 -0300 Subject: [PATCH 2/6] Add roles registry entity and update tests --- schema.graphql | 16 ++++-- src/erc7432/role/revoke-handler.ts | 2 +- src/erc7432/role/role-approval-handler.ts | 10 +++- src/utils/helper.ts | 56 +++++++++++++++----- tests/erc7432/approval-handler.test.ts | 11 ++-- tests/erc7432/grant-handler.test.ts | 63 ++++++++++++++++++++--- tests/erc7432/revoke-handler.test.ts | 51 ++++++++++++------ tests/helpers/entities.ts | 60 ++++++++++++++++----- tests/helpers/events.ts | 4 ++ 9 files changed, 213 insertions(+), 60 deletions(-) diff --git a/schema.graphql b/schema.graphql index 636fd88..188ac40 100644 --- a/schema.graphql +++ b/schema.graphql @@ -15,8 +15,9 @@ type Account @entity { } type RoleAssignment @entity { - id: ID! # grantorAddress + tokenId + tokenAddress + granteeAddress + roleHash + id: ID! # rolesRegistryAddress + grantorAddress + tokenId + tokenAddress + granteeAddress + roleHash role: Role! + rolesRegistry: RolesRegistry! nft: Nft! grantor: Account! grantee: Account! @@ -28,15 +29,24 @@ type RoleAssignment @entity { } type Role @entity { - id: ID! # tokenId + tokenAddress + roleHash + id: ID! # rolesRegistryAddress + tokenId + tokenAddress + roleHash + rolesRegistry: RolesRegistry! roleHash: Bytes! nft: Nft! roleAssignments: [RoleAssignment!] @derivedFrom(field: "role") } type RoleApproval @entity { - id: ID! # grantorAddress + operatorAddress + tokenAddress + id: ID! # rolesRegistryAddress + grantorAddress + operatorAddress + tokenAddress + rolesRegistry: RolesRegistry! grantor: Account! operator: Account! tokenAddress: String! } + +type RolesRegistry @entity { + id: ID! # contractAddress + roles: [Role!] @derivedFrom(field: "rolesRegistry") + roleAssignments: [RoleAssignment!] @derivedFrom(field: "rolesRegistry") + roleApprovals: [RoleApproval!] @derivedFrom(field: "rolesRegistry") +} diff --git a/src/erc7432/role/revoke-handler.ts b/src/erc7432/role/revoke-handler.ts index ab6fe02..37b5d3d 100644 --- a/src/erc7432/role/revoke-handler.ts +++ b/src/erc7432/role/revoke-handler.ts @@ -28,7 +28,7 @@ export function handleRoleRevoked(event: RoleRevoked): void { return } - const roleAssignmentId = generateRoleAssignmentId(revoker, grantee, nft, event.params._role) + const roleAssignmentId = generateRoleAssignmentId(event.address.toHex(), revoker, grantee, nft, event.params._role) const roleAssignment = RoleAssignment.load(roleAssignmentId) if (!roleAssignment) { log.warning('[handleRoleRevoked] RoleAssignment {} does not exist, skipping...', [roleAssignmentId]) diff --git a/src/erc7432/role/role-approval-handler.ts b/src/erc7432/role/role-approval-handler.ts index 7729ed3..e0c44bf 100644 --- a/src/erc7432/role/role-approval-handler.ts +++ b/src/erc7432/role/role-approval-handler.ts @@ -8,6 +8,7 @@ import { import { log } from '@graphprotocol/graph-ts' export function handleRoleApprovalForAll(event: RoleApprovalForAll): void { + const rolesRegistryAddress = event.address.toHex() const grantorAddress = event.transaction.from.toHex() const operatorAddress = event.params._operator.toHex() const tokenAddress = event.params._tokenAddress.toHex() @@ -17,13 +18,18 @@ export function handleRoleApprovalForAll(event: RoleApprovalForAll): void { const operatorAccount = findOrCreateAccount(operatorAddress) if (isApproved) { - const roleApproval = insertRoleApprovalIfNotExist(grantorAccount, operatorAccount, tokenAddress) + const roleApproval = insertRoleApprovalIfNotExist( + rolesRegistryAddress, + grantorAccount, + operatorAccount, + tokenAddress, + ) log.warning('[handleRoleApprovalForAll] Updated RoleAssignment Approval: {} Tx: {}', [ roleApproval.id, event.transaction.hash.toHex(), ]) } else { - const roleApprovalId = generateRoleApprovalId(grantorAccount, operatorAccount, tokenAddress) + const roleApprovalId = generateRoleApprovalId(rolesRegistryAddress, grantorAccount, operatorAccount, tokenAddress) deleteRoleApprovalIfExist(roleApprovalId) log.warning('[handleRoleApprovalForAll] Removed RoleAssignment Approval: {} Tx: {}', [ roleApprovalId, diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 2c65c04..f1d8554 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, RoleAssignment } from '../../generated/schema' +import { Account, Nft, Role, RoleApproval, RoleAssignment, RolesRegistry } from '../../generated/schema' import { RoleGranted } from '../../generated/ERC7432-Immutable-Roles/ERC7432' export function findOrCreateAccount(id: string): Account { @@ -25,8 +25,14 @@ export function generateNftId(tokenAddress: string, tokenId: string): string { return tokenAddress + '-' + tokenId } -export function generateRoleAssignmentId(grantor: Account, grantee: Account, nft: Nft, roleAssignment: Bytes): string { - return grantor.id + '-' + grantee.id + '-' + nft.id + '-' + roleAssignment.toHex() +export function generateRoleAssignmentId( + roleRegistryAddress: string, + grantor: Account, + grantee: Account, + nft: Nft, + roleAssignment: Bytes, +): string { + return roleRegistryAddress + '-' + grantor.id + '-' + grantee.id + '-' + nft.id + '-' + roleAssignment.toHex() } export function findOrCreateRoleAssignment( @@ -35,12 +41,13 @@ export function findOrCreateRoleAssignment( grantee: Account, nft: Nft, ): RoleAssignment { - const roleAssignmentId = generateRoleAssignmentId(grantor, grantee, nft, event.params._role) + const roleAssignmentId = generateRoleAssignmentId(event.address.toHex(), 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.role = findOrCreateRole(event.address.toHex(), nft, event.params._role).id + roleAssignment.rolesRegistry = findOrCreateRolesRegistry(event.address.toHex()).id roleAssignment.nft = nft.id roleAssignment.grantor = grantor.id roleAssignment.grantee = grantee.id @@ -55,36 +62,48 @@ export function findOrCreateRoleAssignment( return roleAssignment } -export function findOrCreateRole(nft: Nft, roleHash: Bytes): Role { - const roleId = generateRoleId(nft, roleHash) +export function findOrCreateRole(roleRegistryAddress: string, nft: Nft, roleHash: Bytes): Role { + const roleId = generateRoleId(roleRegistryAddress, nft, roleHash) let role = Role.load(roleId) if (!role) { role = new Role(roleId) role.roleHash = roleHash role.nft = nft.id + role.rolesRegistry = findOrCreateRolesRegistry(roleRegistryAddress).id role.save() } return role } -export function generateRoleId(nft: Nft, roleHash: Bytes): string { - return nft.id + '-' + roleHash.toHex() +export function generateRoleId(roleRegistryAddress: string, nft: Nft, roleHash: Bytes): string { + return roleRegistryAddress + '-' + nft.id + '-' + roleHash.toHex() } -export function generateRoleApprovalId(grantor: Account, operator: Account, tokenAddress: string): string { - return grantor.id + '-' + operator.id + '-' + tokenAddress.toLowerCase() +export function generateRoleApprovalId( + rolesRegistryAddress: string, + grantor: Account, + operator: Account, + tokenAddress: string, +): string { + return rolesRegistryAddress + '-' + grantor.id + '-' + operator.id + '-' + tokenAddress.toLowerCase() } -export function insertRoleApprovalIfNotExist(grantor: Account, operator: Account, tokenAddress: string): RoleApproval { - const roleApprovalId = generateRoleApprovalId(grantor, operator, tokenAddress) +export function insertRoleApprovalIfNotExist( + rolesRegistryAddress: string, + grantor: Account, + operator: Account, + tokenAddress: string, +): RoleApproval { + const roleApprovalId = generateRoleApprovalId(rolesRegistryAddress, grantor, operator, tokenAddress) let roleApproval = RoleApproval.load(roleApprovalId) if (!roleApproval) { roleApproval = new RoleApproval(roleApprovalId) roleApproval.grantor = grantor.id roleApproval.operator = operator.id roleApproval.tokenAddress = tokenAddress.toLowerCase() + roleApproval.rolesRegistry = findOrCreateRolesRegistry(rolesRegistryAddress).id roleApproval.save() } return roleApproval @@ -96,3 +115,14 @@ export function deleteRoleApprovalIfExist(roleApprovalId: string): void { store.remove('RoleApproval', roleApprovalId) } } + +export function findOrCreateRolesRegistry(rolesRegistryAddress: string): RolesRegistry { + let rolesRegistry = RolesRegistry.load(rolesRegistryAddress) + + if (!rolesRegistry) { + rolesRegistry = new RolesRegistry(rolesRegistryAddress) + rolesRegistry.save() + } + + return rolesRegistry +} diff --git a/tests/erc7432/approval-handler.test.ts b/tests/erc7432/approval-handler.test.ts index f9c4973..62c388d 100644 --- a/tests/erc7432/approval-handler.test.ts +++ b/tests/erc7432/approval-handler.test.ts @@ -1,12 +1,13 @@ import { assert, describe, test, clearStore, afterEach } from 'matchstick-as' import { createNewRoleApprovalForAllEvent } from '../helpers/events' import { validateRoleApproval, createMockRoleApproval } from '../helpers/entities' -import { Addresses } from '../helpers/contants' +import { Addresses, ZERO_ADDRESS } from '../helpers/contants' import { handleRoleApprovalForAll } from '../../src/erc7432' const grantor = Addresses[0] const operator = Addresses[1] const tokenAddress = Addresses[2] +const rolesRegistryAddress = ZERO_ADDRESS describe('ERC-7432 RoleApprovalForAll Handler', () => { afterEach(() => { @@ -15,7 +16,7 @@ describe('ERC-7432 RoleApprovalForAll Handler', () => { describe('When RoleApproval exists', () => { test('should remove approval when is set to false', () => { - createMockRoleApproval(grantor, operator, tokenAddress) + createMockRoleApproval(grantor, operator, tokenAddress, rolesRegistryAddress) assert.entityCount('RoleApproval', 1) const event = createNewRoleApprovalForAllEvent(grantor, operator, tokenAddress, false) @@ -25,14 +26,14 @@ describe('ERC-7432 RoleApprovalForAll Handler', () => { }) test('should not do anything when is set to true', () => { - createMockRoleApproval(grantor, operator, tokenAddress) + createMockRoleApproval(grantor, operator, tokenAddress, rolesRegistryAddress) assert.entityCount('RoleApproval', 1) const event = createNewRoleApprovalForAllEvent(grantor, operator, tokenAddress, true) handleRoleApprovalForAll(event) assert.entityCount('RoleApproval', 1) - validateRoleApproval(grantor, operator, tokenAddress) + validateRoleApproval(rolesRegistryAddress, grantor, operator, tokenAddress) }) }) @@ -53,7 +54,7 @@ describe('ERC-7432 RoleApprovalForAll Handler', () => { handleRoleApprovalForAll(event) assert.entityCount('RoleApproval', 1) - validateRoleApproval(grantor, operator, tokenAddress) + validateRoleApproval(rolesRegistryAddress, grantor, operator, tokenAddress) }) }) }) diff --git a/tests/erc7432/grant-handler.test.ts b/tests/erc7432/grant-handler.test.ts index f91fc82..eac1aec 100644 --- a/tests/erc7432/grant-handler.test.ts +++ b/tests/erc7432/grant-handler.test.ts @@ -1,7 +1,7 @@ import { assert, describe, test, clearStore, afterEach } from 'matchstick-as' import { createNewRoleGrantedEvent } from '../helpers/events' import { handleRoleGranted } from '../../src/erc7432' -import { Addresses } from '../helpers/contants' +import { Addresses, ZERO_ADDRESS } from '../helpers/contants' import { BigInt, Bytes } from '@graphprotocol/graph-ts' import { createMockAccount, createMockNft, validateRole } from '../helpers/entities' import { Account } from '../../generated/schema' @@ -14,6 +14,7 @@ const grantor = Addresses[2] const revocable = true const data = Bytes.fromUTF8('0x1234567890') const expirationDate = BigInt.fromI32(99999) +const rolesRegistryAddress = ZERO_ADDRESS describe('ERC-7432 RoleGranted Handler', () => { afterEach(() => { @@ -133,9 +134,33 @@ describe('ERC-7432 RoleGranted Handler', () => { assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) - 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) + validateRole( + grantorAccount, + new Account(Addresses[0]), + nft, + RoleAssignmentId, + expirationDate, + data, + event1.address.toHex(), + ) + validateRole( + grantorAccount, + new Account(Addresses[1]), + nft, + RoleAssignmentId, + expirationDate, + data, + event2.address.toHex(), + ) + validateRole( + grantorAccount, + new Account(Addresses[2]), + nft, + RoleAssignmentId, + expirationDate, + data, + event3.address.toHex(), + ) }) test('should grant multiple roles for different NFTs', () => { @@ -189,8 +214,32 @@ describe('ERC-7432 RoleGranted Handler', () => { assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) - 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) + validateRole( + grantorAccount, + new Account(Addresses[0]), + nft1, + RoleAssignmentId, + expirationDate, + data, + rolesRegistryAddress, + ) + validateRole( + grantorAccount, + new Account(Addresses[1]), + nft2, + RoleAssignmentId, + expirationDate, + data, + rolesRegistryAddress, + ) + validateRole( + grantorAccount, + new Account(Addresses[2]), + nft3, + RoleAssignmentId, + expirationDate, + data, + rolesRegistryAddress, + ) }) }) diff --git a/tests/erc7432/revoke-handler.test.ts b/tests/erc7432/revoke-handler.test.ts index ba8d5a6..fa9190c 100644 --- a/tests/erc7432/revoke-handler.test.ts +++ b/tests/erc7432/revoke-handler.test.ts @@ -3,7 +3,7 @@ import { createNewRoleRevokedEvent } from '../helpers/events' import { handleRoleRevoked } from '../../src/erc7432' import { Bytes, BigInt } from '@graphprotocol/graph-ts' import { createMockAccount, createMockNft, createMockRoleAssignment, validateRole } from '../helpers/entities' -import { Addresses, ONE, TWO } from '../helpers/contants' +import { Addresses, ONE, TWO, ZERO_ADDRESS } from '../helpers/contants' import { generateNftId, generateRoleAssignmentId } from '../../src/utils/helper' import { Account, Nft } from '../../generated/schema' @@ -14,6 +14,7 @@ const grantee = Addresses[1] const revoker = Addresses[2] const expirationDate = BigInt.fromI32(99999) const data = Bytes.fromUTF8('data') +const rolesRegistryAddress = ZERO_ADDRESS describe('ERC-7432 RoleRevoked Handler', () => { afterEach(() => { @@ -69,14 +70,20 @@ describe('ERC-7432 RoleRevoked Handler', () => { 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)) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft, BigInt.fromI32(0), rolesRegistryAddress) assert.entityCount('RoleAssignment', 1) const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) assert.entityCount('RoleAssignment', 1) - const _id = generateRoleAssignmentId(new Account(revoker), granteeAccount, nft, RoleAssignmentId) + const _id = generateRoleAssignmentId( + rolesRegistryAddress, + new Account(revoker), + granteeAccount, + nft, + RoleAssignmentId, + ) assert.fieldEquals('RoleAssignment', _id, 'expirationDate', '0') }) @@ -85,9 +92,23 @@ describe('ERC-7432 RoleRevoked Handler', () => { const account1 = createMockAccount(Addresses[0]) const account2 = createMockAccount(Addresses[1]) const account3 = createMockAccount(Addresses[2]) - 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)) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[0], nft, expirationDate, rolesRegistryAddress) + createMockRoleAssignment( + RoleAssignmentId, + revoker, + Addresses[1], + nft, + expirationDate.plus(ONE), + rolesRegistryAddress, + ) + createMockRoleAssignment( + RoleAssignmentId, + revoker, + Addresses[2], + nft, + expirationDate.plus(TWO), + rolesRegistryAddress, + ) assert.entityCount('RoleAssignment', 3) assert.entityCount('Role', 1) @@ -103,9 +124,9 @@ describe('ERC-7432 RoleRevoked Handler', () => { 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) - validateRole(revokerAccount, account3, nft, RoleAssignmentId, ONE, data) + validateRole(revokerAccount, account1, nft, RoleAssignmentId, ONE, data, rolesRegistryAddress) + validateRole(revokerAccount, account2, nft, RoleAssignmentId, ONE, data, rolesRegistryAddress) + validateRole(revokerAccount, account3, nft, RoleAssignmentId, ONE, data, rolesRegistryAddress) }) test('should revoke multiple roles for different NFTs', () => { @@ -113,9 +134,9 @@ describe('ERC-7432 RoleRevoked Handler', () => { const nft1 = createMockNft(tokenAddress, '123', revoker) const nft2 = createMockNft(tokenAddress, '456', revoker) const nft3 = createMockNft(tokenAddress, '789', revoker) - createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft1, expirationDate) - createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft2, expirationDate.plus(ONE)) - createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft3, expirationDate.plus(TWO)) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft1, expirationDate, rolesRegistryAddress) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft2, expirationDate.plus(ONE), rolesRegistryAddress) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft3, expirationDate.plus(TWO), rolesRegistryAddress) assert.entityCount('RoleAssignment', 3) assert.entityCount('Role', 3) @@ -131,8 +152,8 @@ describe('ERC-7432 RoleRevoked Handler', () => { 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) - validateRole(revokerAccount, granteeAccount, nft3, RoleAssignmentId, ONE, data) + validateRole(revokerAccount, granteeAccount, nft1, RoleAssignmentId, ONE, data, rolesRegistryAddress) + validateRole(revokerAccount, granteeAccount, nft2, RoleAssignmentId, ONE, data, rolesRegistryAddress) + validateRole(revokerAccount, granteeAccount, nft3, RoleAssignmentId, ONE, data, rolesRegistryAddress) }) }) diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index a3214f9..954c7c0 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -27,16 +27,24 @@ export function createMockRoleAssignment( grantee: string, nft: Nft, expirationDate: BigInt, + rolesRegistryAddress: string, ): RoleAssignment { - const roleId = generateRoleId(nft, roleHash) + const roleId = generateRoleId(rolesRegistryAddress, nft, roleHash) const role = new Role(roleId) role.roleHash = roleHash role.nft = nft.id + role.rolesRegistry = rolesRegistryAddress role.save() - const roleAssignmentId = generateRoleAssignmentId(new Account(grantor), new Account(grantee), nft, roleHash) + const roleAssignmentId = generateRoleAssignmentId( + rolesRegistryAddress, + new Account(grantor), + new Account(grantee), + nft, + roleHash, + ) const newRoleAssignment = new RoleAssignment(roleAssignmentId) - newRoleAssignment.role = `${nft.id}-${roleHash.toHex()}` + newRoleAssignment.role = role.id newRoleAssignment.nft = nft.id newRoleAssignment.grantor = grantor newRoleAssignment.grantee = grantee @@ -45,16 +53,28 @@ export function createMockRoleAssignment( newRoleAssignment.data = Bytes.fromUTF8('data') newRoleAssignment.createdAt = BigInt.fromI32(123) newRoleAssignment.updatedAt = BigInt.fromI32(123) + newRoleAssignment.rolesRegistry = rolesRegistryAddress newRoleAssignment.save() return newRoleAssignment } -export function createMockRoleApproval(grantor: string, operator: string, tokenAddress: string): RoleApproval { - const roleApprovalId = generateRoleApprovalId(new Account(grantor), new Account(operator), tokenAddress) +export function createMockRoleApproval( + grantor: string, + operator: string, + tokenAddress: string, + rolesRegistryAddress: string, +): RoleApproval { + const roleApprovalId = generateRoleApprovalId( + rolesRegistryAddress, + new Account(grantor), + new Account(operator), + tokenAddress, + ) const roleApproval = new RoleApproval(roleApprovalId) roleApproval.grantor = grantor roleApproval.operator = operator roleApproval.tokenAddress = tokenAddress + roleApproval.rolesRegistry = rolesRegistryAddress roleApproval.save() return roleApproval } @@ -66,22 +86,34 @@ export function validateRole( roleAssignment: Bytes, expirationDate: BigInt, data: Bytes, + rolesRegistryAddress: string, ): void { - const roleId = generateRoleId(nft, roleAssignment) + const roleId = generateRoleId(rolesRegistryAddress, 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()) + const roleAssignmentId = generateRoleAssignmentId(rolesRegistryAddress, grantor, grantee, nft, roleAssignment) + assert.fieldEquals( + 'RoleAssignment', + roleAssignmentId, + 'role', + `${rolesRegistryAddress}-${nft.id}-${roleAssignment.toHex()}`, + ) + assert.fieldEquals('RoleAssignment', roleAssignmentId, 'nft', nft.id) + assert.fieldEquals('RoleAssignment', roleAssignmentId, 'grantor', grantor.id) + assert.fieldEquals('RoleAssignment', roleAssignmentId, 'grantee', grantee.id) + assert.fieldEquals('RoleAssignment', roleAssignmentId, 'expirationDate', expirationDate.toString()) + assert.fieldEquals('RoleAssignment', roleAssignmentId, 'data', data.toHex()) } -export function validateRoleApproval(grantor: string, operator: string, tokenAddress: string): void { +export function validateRoleApproval( + rolesRegistryAddress: string, + grantor: string, + operator: string, + tokenAddress: string, +): void { const roleApprovalId = generateRoleApprovalId( + rolesRegistryAddress, new Account(grantor.toLowerCase()), new Account(operator.toLowerCase()), tokenAddress, diff --git a/tests/helpers/events.ts b/tests/helpers/events.ts index b51372d..c1f1940 100644 --- a/tests/helpers/events.ts +++ b/tests/helpers/events.ts @@ -3,6 +3,7 @@ import { Transfer } from '../../generated/ERC721-Chronos-Traveler/ERC721' import { Address, BigInt, Bytes, ethereum } from '@graphprotocol/graph-ts' import { RoleGranted, RoleRevoked, RoleApprovalForAll } from '../../generated/ERC7432-Immutable-Roles/ERC7432' import { Nft } from '../../generated/schema' +import { ZERO_ADDRESS } from './contants' export function createTransferEvent(from: string, to: string, tokenId: string, address: string): Transfer { const event = changetype(newMockEvent()) @@ -21,6 +22,7 @@ export function createNewRoleRevokedEvent( grantee: string, ): RoleRevoked { const event = changetype(newMockEvent()) + event.address = Address.fromString(ZERO_ADDRESS) event.parameters = new Array() event.parameters.push(buildEventParamBytes('_role', roleAssignment)) event.parameters.push(buildEventParamAddress('_tokenAddress', nft.tokenAddress)) @@ -41,6 +43,7 @@ export function createNewRoleGrantedEvent( data: Bytes, ): RoleGranted { const event = changetype(newMockEvent()) + event.address = Address.fromString(ZERO_ADDRESS) event.parameters = new Array() event.parameters.push(buildEventParamBytes('_role', roleAssignment)) event.parameters.push(buildEventParamAddress('_tokenAddress', tokenAddress)) @@ -60,6 +63,7 @@ export function createNewRoleApprovalForAllEvent( isApproved: boolean, ): RoleApprovalForAll { const event = changetype(newMockEvent()) + event.address = Address.fromString(ZERO_ADDRESS) event.parameters = new Array() event.transaction.from = Address.fromString(grantor) event.parameters.push(buildEventParamAddress('_tokenAddress', tokenAddress)) From ca9f36c4bddff564bd565d66f40219ae3a7ccba8 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Wed, 25 Oct 2023 10:26:56 -0300 Subject: [PATCH 3/6] pr fixes --- subgraph-mumbai.yaml | 1 + tests/erc7432/grant-handler.test.ts | 32 +++--------------- tests/erc7432/revoke-handler.test.ts | 50 +++++++++------------------- 3 files changed, 20 insertions(+), 63 deletions(-) diff --git a/subgraph-mumbai.yaml b/subgraph-mumbai.yaml index a36016b..289c369 100644 --- a/subgraph-mumbai.yaml +++ b/subgraph-mumbai.yaml @@ -2,6 +2,7 @@ specVersion: 0.0.4 schema: file: ./schema.graphql dataSources: + # There is no "(Chronos) Traveler" on Mumbai - name: ERC7432-Immutable-Roles kind: ethereum diff --git a/tests/erc7432/grant-handler.test.ts b/tests/erc7432/grant-handler.test.ts index eac1aec..616c0a2 100644 --- a/tests/erc7432/grant-handler.test.ts +++ b/tests/erc7432/grant-handler.test.ts @@ -14,7 +14,7 @@ const grantor = Addresses[2] const revocable = true const data = Bytes.fromUTF8('0x1234567890') const expirationDate = BigInt.fromI32(99999) -const rolesRegistryAddress = ZERO_ADDRESS +const rolesRegistry = ZERO_ADDRESS describe('ERC-7432 RoleGranted Handler', () => { afterEach(() => { @@ -214,32 +214,8 @@ describe('ERC-7432 RoleGranted Handler', () => { assert.entityCount('Account', 3) const grantorAccount = new Account(grantor) - validateRole( - grantorAccount, - new Account(Addresses[0]), - nft1, - RoleAssignmentId, - expirationDate, - data, - rolesRegistryAddress, - ) - validateRole( - grantorAccount, - new Account(Addresses[1]), - nft2, - RoleAssignmentId, - expirationDate, - data, - rolesRegistryAddress, - ) - validateRole( - grantorAccount, - new Account(Addresses[2]), - nft3, - RoleAssignmentId, - expirationDate, - data, - rolesRegistryAddress, - ) + validateRole(grantorAccount, new Account(Addresses[0]), nft1, RoleAssignmentId, expirationDate, data, rolesRegistry) + validateRole(grantorAccount, new Account(Addresses[1]), nft2, RoleAssignmentId, expirationDate, data, rolesRegistry) + validateRole(grantorAccount, new Account(Addresses[2]), nft3, RoleAssignmentId, expirationDate, data, rolesRegistry) }) }) diff --git a/tests/erc7432/revoke-handler.test.ts b/tests/erc7432/revoke-handler.test.ts index fa9190c..254c47a 100644 --- a/tests/erc7432/revoke-handler.test.ts +++ b/tests/erc7432/revoke-handler.test.ts @@ -14,7 +14,7 @@ const grantee = Addresses[1] const revoker = Addresses[2] const expirationDate = BigInt.fromI32(99999) const data = Bytes.fromUTF8('data') -const rolesRegistryAddress = ZERO_ADDRESS +const rolesRegistry = ZERO_ADDRESS describe('ERC-7432 RoleRevoked Handler', () => { afterEach(() => { @@ -70,20 +70,14 @@ describe('ERC-7432 RoleRevoked Handler', () => { 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), rolesRegistryAddress) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft, BigInt.fromI32(0), rolesRegistry) assert.entityCount('RoleAssignment', 1) const event = createNewRoleRevokedEvent(RoleAssignmentId, nft, revoker, grantee) handleRoleRevoked(event) assert.entityCount('RoleAssignment', 1) - const _id = generateRoleAssignmentId( - rolesRegistryAddress, - new Account(revoker), - granteeAccount, - nft, - RoleAssignmentId, - ) + const _id = generateRoleAssignmentId(rolesRegistry, new Account(revoker), granteeAccount, nft, RoleAssignmentId) assert.fieldEquals('RoleAssignment', _id, 'expirationDate', '0') }) @@ -92,23 +86,9 @@ describe('ERC-7432 RoleRevoked Handler', () => { const account1 = createMockAccount(Addresses[0]) const account2 = createMockAccount(Addresses[1]) const account3 = createMockAccount(Addresses[2]) - createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[0], nft, expirationDate, rolesRegistryAddress) - createMockRoleAssignment( - RoleAssignmentId, - revoker, - Addresses[1], - nft, - expirationDate.plus(ONE), - rolesRegistryAddress, - ) - createMockRoleAssignment( - RoleAssignmentId, - revoker, - Addresses[2], - nft, - expirationDate.plus(TWO), - rolesRegistryAddress, - ) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[0], nft, expirationDate, rolesRegistry) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[1], nft, expirationDate.plus(ONE), rolesRegistry) + createMockRoleAssignment(RoleAssignmentId, revoker, Addresses[2], nft, expirationDate.plus(TWO), rolesRegistry) assert.entityCount('RoleAssignment', 3) assert.entityCount('Role', 1) @@ -124,9 +104,9 @@ describe('ERC-7432 RoleRevoked Handler', () => { assert.entityCount('RoleAssignment', 3) assert.entityCount('Role', 1) const revokerAccount = new Account(revoker) - validateRole(revokerAccount, account1, nft, RoleAssignmentId, ONE, data, rolesRegistryAddress) - validateRole(revokerAccount, account2, nft, RoleAssignmentId, ONE, data, rolesRegistryAddress) - validateRole(revokerAccount, account3, nft, RoleAssignmentId, ONE, data, rolesRegistryAddress) + validateRole(revokerAccount, account1, nft, RoleAssignmentId, ONE, data, rolesRegistry) + validateRole(revokerAccount, account2, nft, RoleAssignmentId, ONE, data, rolesRegistry) + validateRole(revokerAccount, account3, nft, RoleAssignmentId, ONE, data, rolesRegistry) }) test('should revoke multiple roles for different NFTs', () => { @@ -134,9 +114,9 @@ describe('ERC-7432 RoleRevoked Handler', () => { const nft1 = createMockNft(tokenAddress, '123', revoker) const nft2 = createMockNft(tokenAddress, '456', revoker) const nft3 = createMockNft(tokenAddress, '789', revoker) - createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft1, expirationDate, rolesRegistryAddress) - createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft2, expirationDate.plus(ONE), rolesRegistryAddress) - createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft3, expirationDate.plus(TWO), rolesRegistryAddress) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft1, expirationDate, rolesRegistry) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft2, expirationDate.plus(ONE), rolesRegistry) + createMockRoleAssignment(RoleAssignmentId, revoker, grantee, nft3, expirationDate.plus(TWO), rolesRegistry) assert.entityCount('RoleAssignment', 3) assert.entityCount('Role', 3) @@ -152,8 +132,8 @@ describe('ERC-7432 RoleRevoked Handler', () => { assert.entityCount('RoleAssignment', 3) assert.entityCount('Role', 3) const revokerAccount = new Account(revoker) - validateRole(revokerAccount, granteeAccount, nft1, RoleAssignmentId, ONE, data, rolesRegistryAddress) - validateRole(revokerAccount, granteeAccount, nft2, RoleAssignmentId, ONE, data, rolesRegistryAddress) - validateRole(revokerAccount, granteeAccount, nft3, RoleAssignmentId, ONE, data, rolesRegistryAddress) + validateRole(revokerAccount, granteeAccount, nft1, RoleAssignmentId, ONE, data, rolesRegistry) + validateRole(revokerAccount, granteeAccount, nft2, RoleAssignmentId, ONE, data, rolesRegistry) + validateRole(revokerAccount, granteeAccount, nft3, RoleAssignmentId, ONE, data, rolesRegistry) }) }) From af1594d33dbc1be6b4353ba36bb2ea4d4326c0a5 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Wed, 25 Oct 2023 10:39:51 -0300 Subject: [PATCH 4/6] pr fixes --- schema.graphql | 1 - subgraph-goerli.yaml | 1 - subgraph-mumbai.yaml | 1 - subgraph-polygon.yaml | 1 - 4 files changed, 4 deletions(-) diff --git a/schema.graphql b/schema.graphql index 188ac40..a89731a 100644 --- a/schema.graphql +++ b/schema.graphql @@ -17,7 +17,6 @@ type Account @entity { type RoleAssignment @entity { id: ID! # rolesRegistryAddress + grantorAddress + tokenId + tokenAddress + granteeAddress + roleHash role: Role! - rolesRegistry: RolesRegistry! nft: Nft! grantor: Account! grantee: Account! diff --git a/subgraph-goerli.yaml b/subgraph-goerli.yaml index 582f976..b3223db 100644 --- a/subgraph-goerli.yaml +++ b/subgraph-goerli.yaml @@ -29,7 +29,6 @@ dataSources: network: goerli source: abi: ERC7432 - startBlock: 9815688 mapping: kind: ethereum/events apiVersion: 0.0.6 diff --git a/subgraph-mumbai.yaml b/subgraph-mumbai.yaml index 289c369..ad87b8d 100644 --- a/subgraph-mumbai.yaml +++ b/subgraph-mumbai.yaml @@ -9,7 +9,6 @@ dataSources: network: mumbai source: abi: ERC7432 - startBlock: 40877849 mapping: kind: ethereum/events apiVersion: 0.0.6 diff --git a/subgraph-polygon.yaml b/subgraph-polygon.yaml index d547ca5..e271834 100644 --- a/subgraph-polygon.yaml +++ b/subgraph-polygon.yaml @@ -29,7 +29,6 @@ dataSources: network: matic source: abi: ERC7432 - startBlock: 48672001 mapping: kind: ethereum/events apiVersion: 0.0.6 From 0f1e0a62df6c56ac5095ec56e3fbb6e83fc4d482 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Wed, 25 Oct 2023 10:40:24 -0300 Subject: [PATCH 5/6] pr fixes --- schema.graphql | 1 - 1 file changed, 1 deletion(-) diff --git a/schema.graphql b/schema.graphql index a89731a..21171cc 100644 --- a/schema.graphql +++ b/schema.graphql @@ -46,6 +46,5 @@ type RoleApproval @entity { type RolesRegistry @entity { id: ID! # contractAddress roles: [Role!] @derivedFrom(field: "rolesRegistry") - roleAssignments: [RoleAssignment!] @derivedFrom(field: "rolesRegistry") roleApprovals: [RoleApproval!] @derivedFrom(field: "rolesRegistry") } From 82f0405efb63dd1ca506b08f0e2d2b5e61b3f20e Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Wed, 25 Oct 2023 10:43:58 -0300 Subject: [PATCH 6/6] fix tests --- src/utils/helper.ts | 1 - tests/helpers/entities.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/utils/helper.ts b/src/utils/helper.ts index f1d8554..3c5dd9f 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -47,7 +47,6 @@ export function findOrCreateRoleAssignment( if (!roleAssignment) { roleAssignment = new RoleAssignment(roleAssignmentId) roleAssignment.role = findOrCreateRole(event.address.toHex(), nft, event.params._role).id - roleAssignment.rolesRegistry = findOrCreateRolesRegistry(event.address.toHex()).id roleAssignment.nft = nft.id roleAssignment.grantor = grantor.id roleAssignment.grantee = grantee.id diff --git a/tests/helpers/entities.ts b/tests/helpers/entities.ts index 954c7c0..26bda01 100644 --- a/tests/helpers/entities.ts +++ b/tests/helpers/entities.ts @@ -53,7 +53,6 @@ export function createMockRoleAssignment( newRoleAssignment.data = Bytes.fromUTF8('data') newRoleAssignment.createdAt = BigInt.fromI32(123) newRoleAssignment.updatedAt = BigInt.fromI32(123) - newRoleAssignment.rolesRegistry = rolesRegistryAddress newRoleAssignment.save() return newRoleAssignment }