diff --git a/schema.graphql b/schema.graphql index fed3ff6..636fd88 100644 --- a/schema.graphql +++ b/schema.graphql @@ -23,7 +23,8 @@ type RoleAssignment @entity { expirationDate: BigInt! revocable: Boolean! data: Bytes! - timestamp: BigInt! + createdAt: BigInt! + updatedAt: 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..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.timestamp = event.block.timestamp + roleAssignment.updatedAt = 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..f91fc82 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) @@ -36,13 +36,15 @@ describe('ERC-7432 RoleGranted Handler', () => { ) handleRoleGranted(event) + assert.entityCount('Role', 0) assert.entityCount('RoleAssignment', 0) 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('Role', 0) assert.entityCount('Account', 1) const event = createNewRoleGrantedEvent( @@ -58,13 +60,15 @@ describe('ERC-7432 RoleGranted Handler', () => { handleRoleGranted(event) assert.entityCount('RoleAssignment', 0) + assert.entityCount('Role', 0) 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) + 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 601a3ac..ba8d5a6 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)) @@ -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 bf2503a..a3214f9 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()}` @@ -37,7 +43,8 @@ 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.updatedAt = BigInt.fromI32(123) newRoleAssignment.save() return newRoleAssignment } @@ -60,13 +67,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 { 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))