diff --git a/.gitignore b/.gitignore index 128e54d..c4e982d 100644 --- a/.gitignore +++ b/.gitignore @@ -73,4 +73,6 @@ generated src/mapping.ts -src/uniswap/common/chain.ts \ No newline at end of file +src/uniswap/common/chain.ts + +CLAUDE.md \ No newline at end of file diff --git a/abis/v6/DataPortabilityGranteesImplementation.json b/abis/v6/DataPortabilityGranteesImplementation.json new file mode 100644 index 0000000..9222943 --- /dev/null +++ b/abis/v6/DataPortabilityGranteesImplementation.json @@ -0,0 +1,858 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyPublicKey", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "GranteeAlreadyRegistered", + "type": "error" + }, + { + "inputs": [], + "name": "GranteeNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" + } + ], + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "granteeAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "publicKey", + "type": "string" + } + ], + "name": "GranteeRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAINTAINER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERMISSION_MANAGER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "addPermissionToGrantee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + } + ], + "name": "grantee", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "granteeAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "publicKey", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "permissionIds", + "type": "uint256[]" + } + ], + "internalType": "struct IDataPortabilityGrantees.GranteeInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "granteeAddress", + "type": "address" + } + ], + "name": "granteeAddressToId", + "outputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "granteeAddress", + "type": "address" + } + ], + "name": "granteeByAddress", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "granteeAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "publicKey", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "permissionIds", + "type": "uint256[]" + } + ], + "internalType": "struct IDataPortabilityGrantees.GranteeInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + } + ], + "name": "granteeInfo", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "granteeAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "publicKey", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "permissionIds", + "type": "uint256[]" + } + ], + "internalType": "struct IDataPortabilityGrantees.GranteeInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + } + ], + "name": "granteePermissionIds", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + } + ], + "name": "granteePermissions", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "granteesCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "trustedForwarderAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "forwarder", + "type": "address" + } + ], + "name": "isTrustedForwarder", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "granteeAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "publicKey", + "type": "string" + } + ], + "name": "registerGrantee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "removePermissionFromGrantee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + } + ], + "name": "setRoleAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trustedForwarder", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "trustedForwarderAddress", + "type": "address" + } + ], + "name": "updateTrustedForwarder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ] diff --git a/abis/v6/DataPortabilityPermissionsImplementation.json b/abis/v6/DataPortabilityPermissionsImplementation.json new file mode 100644 index 0000000..d60f800 --- /dev/null +++ b/abis/v6/DataPortabilityPermissionsImplementation.json @@ -0,0 +1,1307 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [], + "name": "ECDSAInvalidSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ECDSAInvalidSignatureLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "ECDSAInvalidSignatureS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyGrant", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "GrantAlreadyUsed", + "type": "error" + }, + { + "inputs": [], + "name": "GranteeNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "InactivePermission", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedNonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "providedNonce", + "type": "uint256" + } + ], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "fileOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "requestor", + "type": "address" + } + ], + "name": "NotFileOwner", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "permissionOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "requestor", + "type": "address" + } + ], + "name": "NotPermissionGrantor", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" + } + ], + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "grant", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "fileIds", + "type": "uint256[]" + } + ], + "name": "PermissionAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "PermissionRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAINTAINER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "grant", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "fileIds", + "type": "uint256[]" + } + ], + "internalType": "struct IDataPortabilityPermissions.PermissionInput", + "name": "permissionInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "addPermission", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "dataPortabilityGrantees", + "outputs": [ + { + "internalType": "contract IDataPortabilityGrantees", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dataPortabilityServers", + "outputs": [ + { + "internalType": "contract IDataPortabilityServers", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dataRegistry", + "outputs": [ + { + "internalType": "contract IDataRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fileId", + "type": "uint256" + } + ], + "name": "filePermissionIds", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fileId", + "type": "uint256" + } + ], + "name": "filePermissions", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "grantHash", + "type": "bytes32" + } + ], + "name": "grantHashToPermissionId", + "outputs": [ + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "trustedForwarderAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "contract IDataRegistry", + "name": "dataRegistryAddress", + "type": "address" + }, + { + "internalType": "contract IDataPortabilityServers", + "name": "serversContractAddr", + "type": "address" + }, + { + "internalType": "contract IDataPortabilityGrantees", + "name": "granteesContractAddr", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "isActivePermission", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "forwarder", + "type": "address" + } + ], + "name": "isTrustedForwarder", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "permission", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "grantor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "granteeId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "grant", + "type": "string" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endBlock", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "fileIds", + "type": "uint256[]" + } + ], + "internalType": "struct IDataPortabilityPermissions.PermissionInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "permissionFileIds", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "grant", + "type": "string" + } + ], + "name": "permissionIdByGrant", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permissionsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "name": "revokePermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "permissionId", + "type": "uint256" + } + ], + "internalType": "struct IDataPortabilityPermissions.RevokePermissionInput", + "name": "revokePermissionInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "revokePermissionWithSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + } + ], + "name": "setRoleAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trustedForwarder", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IDataRegistry", + "name": "newDataRegistry", + "type": "address" + } + ], + "name": "updateDataRegistry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IDataPortabilityGrantees", + "name": "newGranteesContract", + "type": "address" + } + ], + "name": "updateGranteesContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IDataPortabilityServers", + "name": "newServersContract", + "type": "address" + } + ], + "name": "updateServersContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "trustedForwarderAddress", + "type": "address" + } + ], + "name": "updateTrustedForwarder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "user", + "outputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permissionIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "revokedPermissionIds", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "permissionIndex", + "type": "uint256" + } + ], + "name": "userPermissionIdsAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userPermissionIdsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userPermissionIdsValues", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "permissionIndex", + "type": "uint256" + } + ], + "name": "userRevokedPermissionIdsAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userRevokedPermissionIdsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userRevokedPermissionIdsValues", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + } + ] + diff --git a/abis/v6/DataPortabilityServersImplementation.json b/abis/v6/DataPortabilityServersImplementation.json new file mode 100644 index 0000000..1f30af3 --- /dev/null +++ b/abis/v6/DataPortabilityServersImplementation.json @@ -0,0 +1,1303 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [], + "name": "ECDSAInvalidSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ECDSAInvalidSignatureLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "ECDSAInvalidSignatureS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyPublicKey", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyUrl", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedNonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "providedNonce", + "type": "uint256" + } + ], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serverOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "requestor", + "type": "address" + } + ], + "name": "NotServerOwner", + "type": "error" + }, + { + "inputs": [], + "name": "ServerAlreadyRegistered", + "type": "error" + }, + { + "inputs": [], + "name": "ServerAlreadyTrusted", + "type": "error" + }, + { + "inputs": [], + "name": "ServerAlreadyUntrusted", + "type": "error" + }, + { + "inputs": [], + "name": "ServerNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "ServerNotTrusted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "existingUrl", + "type": "string" + }, + { + "internalType": "string", + "name": "providedUrl", + "type": "string" + } + ], + "name": "ServerUrlMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" + } + ], + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "serverAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "name": "ServerRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "ServerTrusted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "ServerUntrusted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "name": "ServerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAINTAINER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "string", + "name": "serverUrl", + "type": "string" + } + ], + "internalType": "struct IDataPortabilityServers.AndServerInput", + "name": "addAndTrustServerInput", + "type": "tuple" + } + ], + "name": "addAndTrustServer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "string", + "name": "serverUrl", + "type": "string" + } + ], + "internalType": "struct IDataPortabilityServers.AddAndTrustServerInput", + "name": "addAndTrustServerInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "addAndTrustServerWithSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "string", + "name": "serverUrl", + "type": "string" + } + ], + "internalType": "struct IDataPortabilityServers.AndServerInput", + "name": "addServerInput", + "type": "tuple" + } + ], + "name": "addServer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "trustedForwarderAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "isActiveServer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "isActiveServerForUser", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "forwarder", + "type": "address" + } + ], + "name": "isTrustedForwarder", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "server", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "internalType": "struct IDataPortabilityServers.ServerInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + } + ], + "name": "serverAddressToId", + "outputs": [ + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + } + ], + "name": "serverByAddress", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "serverAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "internalType": "struct IDataPortabilityServers.ServerInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "serversCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + } + ], + "name": "setRoleAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "setUserNonce", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "trustServer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "internalType": "struct IDataPortabilityServers.TrustServerInput", + "name": "trustServerInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "trustServerWithSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "trustedForwarder", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "name": "untrustServer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + } + ], + "internalType": "struct IDataPortabilityServers.UntrustServerInput", + "name": "untrustServerInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "untrustServerWithSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serverId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "name": "updateServer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "trustedForwarderAddress", + "type": "address" + } + ], + "name": "updateTrustedForwarder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "user", + "outputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "trustedServerIds", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serverIndex", + "type": "uint256" + } + ], + "name": "userServerIdsAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userServerIdsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + } + ], + "name": "userServerIdsValues", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + } + ] diff --git a/config/moksha.json b/config/moksha.json index 8b249cf..3324acc 100644 --- a/config/moksha.json +++ b/config/moksha.json @@ -19,7 +19,13 @@ "vanaEpoch": true, "dlpPerformance": true, "queryEngine": true, - "dataRefinerRegistry": true + "dataRefinerRegistry": true, + "dataPermission": false + }, + "v6": { + "dataPortabilityGrantees": true, + "dataPortabilityPermissions": true, + "dataPortabilityServers": true }, "uniswap": { "v3": true diff --git a/config/vana.json b/config/vana.json index 63695d4..668cdf3 100644 --- a/config/vana.json +++ b/config/vana.json @@ -19,7 +19,13 @@ "vanaEpoch": true, "dlpPerformance": true, "queryEngine": true, - "dataRefinerRegistry": true + "dataRefinerRegistry": true, + "dataPermission": false + }, + "v6": { + "dataPortabilityGrantees": true, + "dataPortabilityPermissions": true, + "dataPortabilityServers": true }, "uniswap": { "v3": true diff --git a/schema.graphql b/schema.graphql index b993b73..f86ae75 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1,6 +1,12 @@ type User @entity(immutable: false) { id: ID! fileContributions: [DataRegistryProof!] @derivedFrom(field: "user") + "All files owned by this user" + files: [File!]! @derivedFrom(field: "owner") + "All permissions granted by this user" + permissions: [Permission!]! @derivedFrom(field: "grantor") + "All server trust relationships for this user" + serverTrusts: [UserServer!]! @derivedFrom(field: "user") } type UserTotals @entity(immutable: false) { @@ -50,11 +56,6 @@ type Epoch @entity(immutable: false) { performances: [DlpPerformance!]! @derivedFrom(field: "epoch") } -type FileOwner @entity(immutable: false) { - id: ID! - ownerAddress: Bytes! -} - type DataRegistryProof @entity(immutable: false) { id: ID! user: User # Optional for v1 @@ -134,6 +135,116 @@ type PerformanceDlpEpochUser @entity(immutable: false) { id: ID! } +type File @entity(immutable: false) { + "The unique ID of the file, equivalent to the on-chain fileId." + id: ID! + "The owner of the file." + owner: User! + "The URL where the file data is stored (e.g., IPFS)." + url: String! + "The schema ID associated with this file, if any." + schemaId: BigInt! + "The block number when the file was added." + addedAtBlock: BigInt! + "The timestamp when the file was added." + addedAtTimestamp: BigInt! + "The transaction hash of the file addition." + transactionHash: Bytes! +} + +type Grantee @entity(immutable: false) { + "The unique ID of the grantee, equivalent to the on-chain granteeId." + id: ID! + "The owner who registered this grantee." + owner: User! + "The address of the grantee." + address: Bytes! + "The public key of the grantee." + publicKey: String! + "Permissions associated with this grantee." + permissions: [Permission!]! @derivedFrom(field: "grantee") + "The block number when the grantee was registered." + registeredAtBlock: BigInt! + "The timestamp when the grantee was registered." + registeredAtTimestamp: BigInt! + "The transaction hash of the grantee registration." + transactionHash: Bytes! +} + +type Permission @entity(immutable: false) { + "The unique ID of the permission, equivalent to the on-chain permissionId." + id: ID! + "The user who granted the permission." + grantor: User! + "The grantee who received the permission." + grantee: Grantee! + "The content identifier (e.g., IPFS URL) for the grant details." + grant: String! + "The nonce used for this permission grant." + nonce: BigInt! + "The signature provided by the user." + signature: Bytes! + "The block number when the permission starts." + startBlock: BigInt! + "The block number when the permission ends (null if no end)." + endBlock: BigInt + "File permissions for this permission." + filePermissions: [PermissionFile!]! @derivedFrom(field: "permission") + "The block number when the permission was granted." + addedAtBlock: BigInt! + "The timestamp when the permission was granted." + addedAtTimestamp: BigInt! + "The transaction hash of the permission grant." + transactionHash: Bytes! +} + +type PermissionFile @entity(immutable: false) { + "Composite ID: permissionId-fileId" + id: ID! + "The permission." + permission: Permission! + "The file." + file: File! +} + +type Server @entity(immutable: false) { + "The unique ID of the server, using serverId." + id: ID! + "The owner who registered this server." + owner: User! + "The server's address." + serverAddress: Bytes! + "The public key of the server." + publicKey: Bytes! + "The URL of the server." + url: String! + "User trust relationships for this server." + userTrusts: [UserServer!]! @derivedFrom(field: "server") + "The block number when the server was registered." + registeredAtBlock: BigInt! + "The timestamp when the server was registered." + registeredAtTimestamp: BigInt! + "The transaction hash of the server registration." + transactionHash: Bytes! +} + +type UserServer @entity(immutable: false) { + "Composite ID: userId-serverId" + id: ID! + "The user who trusts the server." + user: User! + "The server that is trusted." + server: Server! + "Timestamp of when the trust was established." + trustedAt: BigInt! + "Block number when the trust was established." + trustedAtBlock: BigInt! + "Block number when the trust was revoked (null if still trusted)." + untrustedAtBlock: BigInt + "The transaction hash of the trust establishment." + transactionHash: Bytes! +} + type Factory @entity { # factory address id: ID! diff --git a/src/lib/contract/shared.ts b/src/lib/contract/shared.ts index f8db9bd..034e2bd 100644 --- a/src/lib/contract/shared.ts +++ b/src/lib/contract/shared.ts @@ -1,7 +1,7 @@ -import {Dlp, Token, User} from "../../../generated/schema"; -import {getOrCreateTotals, getTotalsDlpId} from "../entity/totals"; -import {Address, BigDecimal, BigInt, Bytes} from "@graphprotocol/graph-ts"; -import {REFERENCE_TOKEN} from "../../uniswap/common/chain"; +import { Address, BigDecimal, BigInt, Bytes } from "@graphprotocol/graph-ts"; +import { REFERENCE_TOKEN } from "../../uniswap/common/chain"; +import { Dlp, User, Token } from "../../../generated/schema"; +import { getOrCreateTotals, getTotalsDlpId } from "../entity/totals"; export function getOrCreateUser(userId: string): User { let user = User.load(userId); @@ -35,27 +35,17 @@ export function getTokenAmountInVana( tokenAddress = Address.fromString(REFERENCE_TOKEN); } - // //temporary fix until we have uniswap integrated - // if (tokenAddress == Address.fromString(REFERENCE_TOKEN) ) { - // const decimals = 18 as u8; - // - // let precision = BigInt.fromI32(10).pow(decimals); - // - // return amount.toBigDecimal().div(precision.toBigDecimal()); - // } else { - // return BigDecimal.fromString("0"); - // } - const token = Token.load(tokenAddress); if (!token) { throw new Error(`Token not found: ${tokenAddress.toHex()}`); } + // @ts-ignore const decimals = Number.parseInt(token.decimals.toString()) as u8; - let precision = BigInt.fromI32(10).pow(decimals); + const precision = BigInt.fromI32(10).pow(decimals); const decimalAmount = amount.toBigDecimal().div(precision.toBigDecimal()); return decimalAmount.times(token.derivedETH); -} \ No newline at end of file +} diff --git a/src/lib/contract/shared/constants.ts b/src/lib/contract/shared/constants.ts new file mode 100644 index 0000000..90c19ef --- /dev/null +++ b/src/lib/contract/shared/constants.ts @@ -0,0 +1,18 @@ +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; + +/** + * Common constants used across contract handlers + */ + +// Common BigInt values +export const ONE = GraphBigInt.fromI32(1); +export const ZERO = GraphBigInt.fromI32(0); + +// Error messages +export const ERROR_NO_EPOCH = "No epoch found for block"; +export const ERROR_DLP_NOT_FOUND = "DLP not found for proof"; +export const ERROR_NO_FILE_OWNER = + "Cannot update totals: file not found or has no owner"; + +// Default values +export const DEFAULT_SCHEMA_ID = ZERO; diff --git a/src/lib/contract/shared/entity-factory.ts b/src/lib/contract/shared/entity-factory.ts new file mode 100644 index 0000000..1f9cdf8 --- /dev/null +++ b/src/lib/contract/shared/entity-factory.ts @@ -0,0 +1,58 @@ +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; + +/** + * Generic function to get or create an entity with initialization + * @param id - The entity ID + * @param loadFunction - Function to load the entity + * @param createFunction - Function to create the entity + * @param initFunction - Function to initialize the entity + * @returns The loaded or created entity + */ +export function getOrCreateEntity( + id: string, + loadFunction: (id: string) => T | null, + createFunction: (id: string) => T, + initFunction?: (entity: T) => void, +): T { + let entity = loadFunction(id); + if (entity == null) { + entity = createFunction(id); + if (initFunction) { + initFunction(entity); + } + // Note: entities should be saved in the initFunction or by the caller + } + return entity; +} + +/** + * Generic initialization function for entities with zero BigInt fields + * @param entity - The entity to initialize + * @param fields - Array of field names to initialize with zero + */ +export function initializeZeroFields(entity: any, fields: string[]): void { + for (let i = 0; i < fields.length; i++) { + entity[fields[i]] = GraphBigInt.zero(); + } +} + +/** + * Creates an entity with the save operation + * @param id - The entity ID + * @param entityConstructor - Constructor function for the entity + * @param initFunction - Optional initialization function + * @returns The created and saved entity + */ +export function createAndSaveEntity( + id: string, + entityConstructor: (id: string) => T, + initFunction?: (entity: T) => void, +): T { + const entity = entityConstructor(id); + if (initFunction) { + initFunction(entity); + } + // Assuming all entities have a save method + (entity as any).save(); + return entity; +} diff --git a/src/lib/contract/shared/entity-utils.ts b/src/lib/contract/shared/entity-utils.ts new file mode 100644 index 0000000..92a4088 --- /dev/null +++ b/src/lib/contract/shared/entity-utils.ts @@ -0,0 +1,55 @@ +import { log } from "@graphprotocol/graph-ts"; + +/** + * Generic entity loader with error handling + * @param entityType - The entity type (for logging) + * @param entityId - The entity ID to load + * @param loadFunction - Function to load the entity + * @param context - Optional context for error logging + * @returns The loaded entity or null if not found + */ +export function loadEntityWithErrorHandling( + entityType: string, + entityId: string, + loadFunction: (id: string) => T | null, + context?: string, +): T | null { + const entity = loadFunction(entityId); + if (entity == null) { + const message = context + ? `${entityType} not found for ${context}: {}` + : `${entityType} not found: {}`; + log.error(message, [entityId]); + } + return entity; +} + +/** + * Safely adds an item to an array if it doesn't already exist + * @param array - The array to add to + * @param item - The item to add + * @returns True if item was added, false if it already existed + */ +export function addToArrayIfNotExists(array: T[], item: T): boolean { + const index = array.indexOf(item); + if (index === -1) { + array.push(item); + return true; + } + return false; +} + +/** + * Safely removes an item from an array + * @param array - The array to remove from + * @param item - The item to remove + * @returns True if item was removed, false if it wasn't found + */ +export function removeFromArray(array: T[], item: T): boolean { + const index = array.indexOf(item); + if (index !== -1) { + array.splice(index, 1); + return true; + } + return false; +} diff --git a/src/lib/contract/shared/event-utils.ts b/src/lib/contract/shared/event-utils.ts new file mode 100644 index 0000000..df4c9aa --- /dev/null +++ b/src/lib/contract/shared/event-utils.ts @@ -0,0 +1,78 @@ +import { log, ethereum, BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; + +/** + * Standard logging format for all contract events + * @param eventName - The name of the event being handled + * @param transactionHash - The transaction hash + */ +export function logEventWithTxHash( + eventName: string, + transactionHash: string, +): void { + log.info("Handling {} with transaction hash: {}", [ + eventName, + transactionHash, + ]); +} + +/** + * Logs an entity not found error with context + * @param entityType - The type of entity (e.g., "DLP", "User", "Epoch") + * @param entityId - The ID of the entity that was not found + * @param context - Additional context about where the error occurred + */ +export function logEntityNotFound( + entityType: string, + entityId: string, + context?: string, +): void { + const message = context + ? `${entityType} not found for ${context}: {}` + : `${entityType} not found: {}`; + log.error(message, [entityId]); +} + +/** + * Sets common blockchain metadata fields on an entity + * @param entity - The entity to set metadata on + * @param block - The block information + * @param transaction - The transaction information + * @param logIndex - Optional log index for the event + */ +export function setBlockchainMetadata( + entity: any, + block: ethereum.Block, + transaction: ethereum.Transaction, + logIndex?: GraphBigInt, +): void { + entity.createdAt = block.timestamp; + entity.createdAtBlock = block.number; + entity.createdTxHash = transaction.hash; + + if (logIndex) { + entity.logIndex = logIndex; + } +} + +/** + * Creates a composite ID from multiple parts + * @param parts - Array of string parts to join + * @param separator - Separator to use (defaults to "-") + * @returns The composite ID + */ +export function createCompositeId(parts: string[], separator = "-"): string { + return parts.join(separator); +} + +/** + * Creates a transaction-based ID + * @param transactionHash - The transaction hash + * @param logIndex - The log index + * @returns The transaction-based ID + */ +export function createTransactionId( + transactionHash: string, + logIndex: GraphBigInt, +): string { + return `${transactionHash}-${logIndex.toString()}`; +} diff --git a/src/lib/contract/shared/file-handlers.ts b/src/lib/contract/shared/file-handlers.ts new file mode 100644 index 0000000..be37e1e --- /dev/null +++ b/src/lib/contract/shared/file-handlers.ts @@ -0,0 +1,58 @@ +import { BigInt as GraphBigInt, log, ethereum } from "@graphprotocol/graph-ts"; +import { File } from "../../../../generated/schema"; +import { getOrCreateUser } from "../shared"; + +/** + * Creates a new File entity from a FileAdded event + * @param fileId - The unique file ID + * @param ownerAddress - The owner's address + * @param url - The file URL + * @param block - The block information + * @param transaction - The transaction information + * @param schemaId - The schema ID (defaults to 0 for versions that don't support it) + * @returns The created File entity + */ +export function createFileFromEvent( + fileId: string, + ownerAddress: string, + url: string, + block: ethereum.Block, + transaction: ethereum.Transaction, + schemaId: GraphBigInt = GraphBigInt.fromI32(0), +): File { + log.info("Creating file {} for owner {} with transaction hash: {}", [ + fileId, + ownerAddress, + transaction.hash.toHex(), + ]); + + // Create user entity if it doesn't exist + const user = getOrCreateUser(ownerAddress); + + // Create new File entity + const file = new File(fileId); + file.owner = user.id; + file.url = url; + file.addedAtBlock = block.number; + file.addedAtTimestamp = block.timestamp; + file.transactionHash = transaction.hash; + file.schemaId = schemaId; + + file.save(); + return file; +} + +/** + * Standard logging format for DataRegistry events + * @param eventName - The name of the event being handled + * @param transactionHash - The transaction hash + */ +export function logDataRegistryEvent( + eventName: string, + transactionHash: string, +): void { + log.info("Handling DataRegistry {} with transaction hash: {}", [ + eventName, + transactionHash, + ]); +} diff --git a/src/lib/contract/shared/index.ts b/src/lib/contract/shared/index.ts new file mode 100644 index 0000000..daa25de --- /dev/null +++ b/src/lib/contract/shared/index.ts @@ -0,0 +1,15 @@ +// Re-export all shared utilities for easy importing +export * from "./file-handlers"; +export * from "./proof-handlers"; +export * from "./totals-updater"; +export * from "./constants"; +export * from "./event-utils"; +export * from "./entity-utils"; +export * from "./entity-factory"; + +// Keep the original shared.ts exports for backward compatibility +export { + getOrCreateUser, + getOrCreateDlp, + getTokenAmountInVana, +} from "../shared"; diff --git a/src/lib/contract/shared/proof-handlers.ts b/src/lib/contract/shared/proof-handlers.ts new file mode 100644 index 0000000..ae151f3 --- /dev/null +++ b/src/lib/contract/shared/proof-handlers.ts @@ -0,0 +1,60 @@ +import { + BigInt as GraphBigInt, + log, + ethereum, + Bytes, +} from "@graphprotocol/graph-ts"; +import { DataRegistryProof } from "../../../../generated/schema"; + +/** + * Creates a DataRegistryProof entity with common fields + * @param transactionHash - The transaction hash (used as entity ID) + * @param epochId - The epoch ID + * @param fileId - The file ID + * @param proofIndex - The proof index + * @param block - The block information + * @param transaction - The transaction information + * @param userId - Optional user ID (for V3+) + * @param dlpId - Optional DLP ID (for V2+) + * @param attestor - Optional attestor address (for versions that support it) + * @returns The created DataRegistryProof entity + */ +export function createDataRegistryProof( + transactionHash: string, + epochId: string, + fileId: GraphBigInt, + proofIndex: GraphBigInt, + block: ethereum.Block, + transaction: ethereum.Transaction, + userId: string | null = null, + dlpId: string | null = null, + attestor: Bytes | null = null, +): DataRegistryProof { + log.info("Creating DataRegistry proof for transaction hash: {}", [ + transactionHash, + ]); + + const proof = new DataRegistryProof(transactionHash); + + // Set common fields + proof.epoch = epochId; + proof.fileId = fileId; + proof.proofIndex = proofIndex; + proof.createdAt = block.timestamp; + proof.createdAtBlock = block.number; + proof.createdTxHash = transaction.hash; + + // Set optional fields if provided + if (userId) { + proof.user = userId; + } + if (dlpId) { + proof.dlp = dlpId; + } + if (attestor) { + proof.attestor = attestor; + } + + proof.save(); + return proof; +} diff --git a/src/lib/contract/shared/totals-updater.ts b/src/lib/contract/shared/totals-updater.ts new file mode 100644 index 0000000..27726b9 --- /dev/null +++ b/src/lib/contract/shared/totals-updater.ts @@ -0,0 +1,107 @@ +import { BigInt as GraphBigInt, log } from "@graphprotocol/graph-ts"; +import { File } from "../../../../generated/schema"; +import { + getOrCreateUserTotals, + getUserTotalsId, + getUserTotalsIdDlp, +} from "../../entity/usertotals"; +import { + getOrCreateTotals, + getTotalsDlpId, + TOTALS_ID_GLOBAL, +} from "../../entity/totals"; + +/** + * Updates global totals for file contributions + * @param userId - The user ID who contributed + */ +export function updateGlobalTotals(userId: string): void { + // Update user totals + const userTotalsId = getUserTotalsId(userId); + const userTotals = getOrCreateUserTotals(userTotalsId); + userTotals.fileContributionsCount = userTotals.fileContributionsCount.plus( + GraphBigInt.fromI32(1), + ); + userTotals.save(); + + // Update global file contribution totals + const totals = getOrCreateTotals(TOTALS_ID_GLOBAL); + totals.totalFileContributions = totals.totalFileContributions.plus( + GraphBigInt.fromI32(1), + ); + + // If this is the user's first contribution, increment unique contributors + if (userTotals.fileContributionsCount.toI32() === 1) { + totals.uniqueFileContributors = totals.uniqueFileContributors.plus( + GraphBigInt.fromI32(1), + ); + } + + totals.save(); +} + +/** + * Updates DLP-specific totals for file contributions + * @param userId - The user ID who contributed + * @param dlpId - The DLP ID + */ +export function updateDlpTotals(userId: string, dlpId: string): void { + // Create or load DLP user totals + const dlpUserTotalsId = getUserTotalsIdDlp(userId, dlpId); + const dlpUserTotals = getOrCreateUserTotals(dlpUserTotalsId); + dlpUserTotals.fileContributionsCount = + dlpUserTotals.fileContributionsCount.plus(GraphBigInt.fromI32(1)); + dlpUserTotals.save(); + + // Update DLP file contribution totals + const dlpTotalsId = getTotalsDlpId(dlpId); + const dlpTotals = getOrCreateTotals(dlpTotalsId); + dlpTotals.totalFileContributions = dlpTotals.totalFileContributions.plus( + GraphBigInt.fromI32(1), + ); + + // If this is the user's first contribution to this DLP, increment unique contributors + if (dlpUserTotals.fileContributionsCount.toI32() === 1) { + dlpTotals.uniqueFileContributors = dlpTotals.uniqueFileContributors.plus( + GraphBigInt.fromI32(1), + ); + } + + dlpTotals.save(); +} + +/** + * Updates both global and DLP totals for file contributions + * @param userId - The user ID who contributed + * @param dlpId - The DLP ID (optional, if not provided only global totals are updated) + */ +export function updateAllTotals( + userId: string, + dlpId: string | null = null, +): void { + updateGlobalTotals(userId); + + if (dlpId) { + updateDlpTotals(userId, dlpId); + } +} + +/** + * Updates totals based on file owner (used in V1 where we need to get user from file) + * @param fileId - The file ID to look up the owner + * @param dlpId - Optional DLP ID + */ +export function updateTotalsFromFile( + fileId: string, + dlpId: string | null = null, +): void { + const file = File.load(fileId); + if (!file || !file.owner) { + log.warning("Cannot update totals: file {} not found or has no owner", [ + fileId, + ]); + return; + } + + updateAllTotals(file.owner, dlpId); +} diff --git a/src/lib/contract/v1/data-registry.ts b/src/lib/contract/v1/data-registry.ts index 03530cc..53f3c2f 100644 --- a/src/lib/contract/v1/data-registry.ts +++ b/src/lib/contract/v1/data-registry.ts @@ -1,93 +1,56 @@ -import { BigInt as GraphBigInt, log } from "@graphprotocol/graph-ts"; - -import { - DataRegistryProof, - EpochReference, - FileOwner, -} from "../../../../generated/schema"; +import { log } from "@graphprotocol/graph-ts"; import { FileAdded as FileAddedEvent, ProofAdded as FileProofAdded, } from "../../../../generated/DataRegistryImplementationV1/DataRegistryImplementationV1"; -import { EPOCH_REFERENCE_ID_CURRENT } from "../../entity/epoch"; -import { - getOrCreateUserTotals, - getUserTotalsId, -} from "../../entity/usertotals"; -import { getOrCreateTotals, TOTALS_ID_GLOBAL } from "../../entity/totals"; import { getEpochForBlock } from "../../entity/epoch"; +import { + createFileFromEvent, + logDataRegistryEvent, + createDataRegistryProof, + updateTotalsFromFile, + ERROR_NO_EPOCH, + DEFAULT_SCHEMA_ID, +} from "../shared/index"; export function handleFileAddedV1(event: FileAddedEvent): void { - log.info("Handling DataRegistry FileAdded with transaction hash: {}", [ - event.transaction.hash.toHex(), - ]); - - const ownership = new FileOwner(event.params.fileId.toString()); - ownership.ownerAddress = event.params.ownerAddress; - ownership.save(); + logDataRegistryEvent("FileAdded", event.transaction.hash.toHex()); + + // Create file entity using shared utility + // V1 of the contract does not support schemaId, so we use default (0) + createFileFromEvent( + event.params.fileId.toString(), + event.params.ownerAddress.toHex(), + event.params.url, + event.block, + event.transaction, + DEFAULT_SCHEMA_ID, + ); } export function handleDataRegistryProofAddedV1(event: FileProofAdded): void { - log.info("Handling DataRegistry ProofAdded with transaction hash: {}", [ - event.transaction.hash.toHex(), - ]); + logDataRegistryEvent("ProofAdded", event.transaction.hash.toHex()); // Get epoch for the current block const epochId = getEpochForBlock(event.block.number); if (!epochId) { - log.error("No epoch found for block {}", [event.block.number.toString()]); + log.error(ERROR_NO_EPOCH + " {}", [event.block.number.toString()]); return; } - // Create a new DataRegistryProof entity - const proof = new DataRegistryProof(event.transaction.hash.toHex()); - - // Load File - const fileOwner = FileOwner.load(event.params.fileId.toString()); - if (fileOwner !== null) { - const userId = fileOwner.ownerAddress.toHex(); - proof.user = userId; - } else { - log.error("File ownership '{}' not found for data registry proof: {}", [ - event.params.fileId.toString(), - proof.id, - ]); - } - - // Populate fields based on the event data - proof.epoch = epochId; - proof.fileId = event.params.fileId; - proof.proofIndex = event.params.proofIndex; - proof.createdAt = event.block.timestamp; - proof.createdAtBlock = event.block.number; - proof.createdTxHash = event.transaction.hash; - - // Save the proof to the store - proof.save(); - - if (!fileOwner) { - return; - } - const userId = fileOwner.ownerAddress.toHex(); - - // Update user totals - const userTotalsId = getUserTotalsId(userId); - const userTotals = getOrCreateUserTotals(userTotalsId); - userTotals.fileContributionsCount = userTotals.fileContributionsCount.plus( - GraphBigInt.fromI32(1), + // Create proof using shared utility + // V1 doesn't have user or DLP associations in the proof + createDataRegistryProof( + event.transaction.hash.toHex(), + epochId, + event.params.fileId, + event.params.proofIndex, + event.block, + event.transaction, ); - userTotals.save(); - // Update global file contribution totals - const totals = getOrCreateTotals(TOTALS_ID_GLOBAL); - totals.totalFileContributions = totals.totalFileContributions.plus( - GraphBigInt.fromI32(1), - ); - if (userTotals.fileContributionsCount.toI32() === 1) { - totals.uniqueFileContributors = totals.uniqueFileContributors.plus( - GraphBigInt.fromI32(1), - ); - } - totals.save(); + // Update totals using shared utility + // V1 only has global totals, no DLP-specific totals + updateTotalsFromFile(event.params.fileId.toString()); } diff --git a/src/lib/contract/v2/data-registry.ts b/src/lib/contract/v2/data-registry.ts index f3477e0..6ccf962 100644 --- a/src/lib/contract/v2/data-registry.ts +++ b/src/lib/contract/v2/data-registry.ts @@ -1,127 +1,74 @@ -import { BigInt as GraphBigInt, log, Bytes } from "@graphprotocol/graph-ts"; +import { log } from "@graphprotocol/graph-ts"; -import { - DataRegistryProof, - FileOwner, - Epoch, -} from "../../../../generated/schema"; +import { Dlp, File } from "../../../../generated/schema"; import { FileAdded as FileAddedEvent, ProofAdded as FileProofAdded, } from "../../../../generated/DataRegistryImplementationV2/DataRegistryImplementationV2"; -import { - getOrCreateUserTotals, - getUserTotalsId, - getUserTotalsIdDlp, -} from "../../entity/usertotals"; -import { - getOrCreateTotals, - getTotalsDlpId, - TOTALS_ID_GLOBAL, -} from "../../entity/totals"; import { getEpochForBlock } from "../../entity/epoch"; -import {getOrCreateDlp} from "../shared"; +import { + createFileFromEvent, + logDataRegistryEvent, + createDataRegistryProof, + updateAllTotals, + ERROR_NO_EPOCH, + ERROR_DLP_NOT_FOUND, + DEFAULT_SCHEMA_ID, +} from "../shared/index"; export function handleFileAddedV2(event: FileAddedEvent): void { - log.info("Handling DataRegistry FileAdded with transaction hash: {}", [ - event.transaction.hash.toHex(), - ]); - - const ownership = new FileOwner(event.params.fileId.toString()); - ownership.ownerAddress = event.params.ownerAddress; - ownership.save(); + logDataRegistryEvent("FileAdded", event.transaction.hash.toHex()); + + // Create file entity using shared utility + // V2 of the contract does not support schemaId, so we use default (0) + createFileFromEvent( + event.params.fileId.toString(), + event.params.ownerAddress.toHex(), + event.params.url, + event.block, + event.transaction, + DEFAULT_SCHEMA_ID, + ); } export function handleDataRegistryProofAddedV2(event: FileProofAdded): void { - log.info("Handling DataRegistry ProofAdded with transaction hash: {}", [ - event.transaction.hash.toHex(), - ]); + logDataRegistryEvent("ProofAdded", event.transaction.hash.toHex()); // Get epoch for the current block const epochId = getEpochForBlock(event.block.number); - if (!epochId) { - log.error("No epoch found for block {}", [event.block.number.toString()]); + // Check for "-1" explicitly, as it is a truthy string + if (epochId == "-1") { + log.error(ERROR_NO_EPOCH + " {}", [event.block.number.toString()]); return; } - // Ensure the Dlp entity exists - const dlp = getOrCreateDlp(event.params.dlpId.toString()); - - // Create a new DataRegistryProof entity - const proof = new DataRegistryProof(event.transaction.hash.toHex()); - - // Load File - const fileOwner = FileOwner.load(event.params.fileId.toString()); - if (fileOwner !== null) { - const userId = fileOwner.ownerAddress.toHex(); - proof.user = userId; - } else { - log.warning( - "File '{}' not found for data registry proof (could not set user id): {}", - [event.params.fileId.toString(), proof.id], - ); - } - - // Populate fields based on the event data - proof.dlp = dlp.id; - proof.epoch = epochId; - proof.fileId = event.params.fileId; - proof.proofIndex = event.params.proofIndex; - proof.createdAt = event.block.timestamp; - proof.createdAtBlock = event.block.number; - proof.createdTxHash = event.transaction.hash; - - // Save the proof to the store - proof.save(); - - if (!fileOwner) { + // Load DLP instead of creating it to handle non-existent DLP case gracefully + const dlp = Dlp.load(event.params.dlpId.toString()); + if (dlp == null) { + log.error(ERROR_DLP_NOT_FOUND + ": {}", [event.params.dlpId.toString()]); return; } - const userId = fileOwner.ownerAddress.toHex(); - // Update user totals - const userTotalsId = getUserTotalsId(userId); - const userTotals = getOrCreateUserTotals(userTotalsId); - userTotals.fileContributionsCount = userTotals.fileContributionsCount.plus( - GraphBigInt.fromI32(1), + // Create proof using shared utility + // V2 has DLP association but no user association in the proof + createDataRegistryProof( + event.transaction.hash.toHex(), + epochId, + event.params.fileId, + event.params.proofIndex, + event.block, + event.transaction, + null, // no userId in V2 proof + dlp.id, ); - userTotals.save(); - // Update global unique file contribution totals - const totals = getOrCreateTotals(TOTALS_ID_GLOBAL); - totals.totalFileContributions = totals.totalFileContributions.plus( - GraphBigInt.fromI32(1), - ); - if (userTotals.fileContributionsCount.toI32() === 1) { - totals.uniqueFileContributors = totals.uniqueFileContributors.plus( - GraphBigInt.fromI32(1), - ); + // Update totals using shared utility + // V2 has both global and DLP totals + const file = File.load(event.params.fileId.toString()); + if (!file || !file.owner) { + return; } - totals.save(); - // Create or load dlp user totals - const dlpUserTotalsId = getUserTotalsIdDlp( - userId, - event.params.dlpId.toString(), - ); - const dlpUserTotals = getOrCreateUserTotals(dlpUserTotalsId); - dlpUserTotals.fileContributionsCount = - dlpUserTotals.fileContributionsCount.plus(GraphBigInt.fromI32(1)); - dlpUserTotals.save(); - - // Update dlp file contribution totals - const dlpTotalsId = getTotalsDlpId(event.params.dlpId.toString()); - const dlpTotals = getOrCreateTotals(dlpTotalsId); - - dlpTotals.totalFileContributions = dlpTotals.totalFileContributions.plus( - GraphBigInt.fromI32(1), - ); - - if (dlpUserTotals.fileContributionsCount.toI32() === 1) { - dlpTotals.uniqueFileContributors = dlpTotals.uniqueFileContributors.plus( - GraphBigInt.fromI32(1), - ); - } - dlpTotals.save(); + updateAllTotals(file.owner, event.params.dlpId.toString()); } diff --git a/src/lib/contract/v3/data-registry.ts b/src/lib/contract/v3/data-registry.ts index 5fceed3..0202080 100644 --- a/src/lib/contract/v3/data-registry.ts +++ b/src/lib/contract/v3/data-registry.ts @@ -1,48 +1,48 @@ -import {BigInt as GraphBigInt, Bytes, log} from "@graphprotocol/graph-ts"; +import { BigInt as GraphBigInt, log } from "@graphprotocol/graph-ts"; -import { - DataRegistryProof, - Epoch, - FileOwner, PerformanceDlpEpochUser, -} from "../../../../generated/schema"; +import { Epoch, PerformanceDlpEpochUser } from "../../../../generated/schema"; import { FileAdded as FileAddedEvent, ProofAdded as FileProofAdded, } from "../../../../generated/DataRegistryImplementationV3/DataRegistryImplementationV3"; -import { - getOrCreateUserTotals, - getUserTotalsId, - getUserTotalsIdDlp, -} from "../../entity/usertotals"; -import { - getOrCreateTotals, getOrCreateTotalsForDlpEpochPerformance, - getTotalsDlpId, - TOTALS_ID_GLOBAL, -} from "../../entity/totals"; -import {getOrCreateDlp, getOrCreateUser} from "../shared"; +import { getOrCreateTotalsForDlpEpochPerformance } from "../../entity/totals"; import { getEpochForBlock } from "../../entity/epoch"; -import {getDlpEpochUserId, getOrCreateDlpEpochUser} from "../../entity/dlpEpochUser"; -import {dlps} from "../../../mapping"; +import { getDlpEpochUserId } from "../../entity/dlpEpochUser"; +import { + getOrCreateDlp, + getOrCreateUser, + createFileFromEvent, + logDataRegistryEvent, + createDataRegistryProof, + updateAllTotals, + ERROR_NO_EPOCH, + DEFAULT_SCHEMA_ID, + ONE, +} from "../shared/index"; export function handleFileAddedV3(event: FileAddedEvent): void { - log.info("Handling DataRegistry FileAdded with transaction hash: {}", [ - event.transaction.hash.toHex(), - ]); - - const ownership = new FileOwner(event.params.fileId.toString()); - ownership.ownerAddress = event.params.ownerAddress; - ownership.save(); + logDataRegistryEvent("FileAdded", event.transaction.hash.toHex()); + + // Create file entity using shared utility + // V3 of the contract does not support schemaId, so we use default (0) + createFileFromEvent( + event.params.fileId.toString(), + event.params.ownerAddress.toHex(), + event.params.url, + event.block, + event.transaction, + DEFAULT_SCHEMA_ID, + ); } export function handleDataRegistryProofAddedV3(event: FileProofAdded): void { - log.info("Handling DataRegistry ProofAdded with transaction hash: {}", [ - event.transaction.hash.toHex(), - ]); + logDataRegistryEvent("ProofAdded", event.transaction.hash.toHex()); const epochId = getEpochForBlock(event.block.number); - if (!epochId) { - log.error("No epoch found for block {}", [event.block.number.toString()]); + // Check for "-1" explicitly, as it is a truthy string + if (epochId == "-1") { + log.error(ERROR_NO_EPOCH + " {}", [event.block.number.toString()]); return; } @@ -52,80 +52,35 @@ export function handleDataRegistryProofAddedV3(event: FileProofAdded): void { const dlp = getOrCreateDlp(dlpId); getOrCreateUser(userId); - createDataRegistryProof(event, epochId, dlp.id, userId); - updateTotals(userId, dlpId); - updateDlpEpochUser(event, epochId, userId, dlpId); -} - -function createDataRegistryProof( - event: FileProofAdded, - epochId: string, - dlpId: string, - userId: string, -): void { - const proof = new DataRegistryProof(event.transaction.hash.toHex()); - proof.user = userId; - proof.dlp = dlpId; - proof.epoch = epochId; - proof.fileId = event.params.fileId; - proof.proofIndex = event.params.proofIndex; - proof.createdAt = event.block.timestamp; - proof.createdAtBlock = event.block.number; - proof.createdTxHash = event.transaction.hash; - proof.save(); -} - -function updateTotals(userId: string, dlpId: string): void { - // Update user totals - const userTotalsId = getUserTotalsId(userId); - const userTotals = getOrCreateUserTotals(userTotalsId); - userTotals.fileContributionsCount = userTotals.fileContributionsCount.plus( - GraphBigInt.fromI32(1), + // Create proof using shared utility + // V3 has both user and DLP associations in the proof + createDataRegistryProof( + event.transaction.hash.toHex(), + epochId, + event.params.fileId, + event.params.proofIndex, + event.block, + event.transaction, + userId, + dlp.id, ); - userTotals.save(); - // Update global unique file contribution totals - const totals = getOrCreateTotals(TOTALS_ID_GLOBAL); - totals.totalFileContributions = totals.totalFileContributions.plus( - GraphBigInt.fromI32(1), - ); - if (userTotals.fileContributionsCount.toI32() === 1) { - totals.uniqueFileContributors = totals.uniqueFileContributors.plus( - GraphBigInt.fromI32(1), - ); - } - totals.save(); - - // Create or load dlp user totals - const dlpUserTotalsId = getUserTotalsIdDlp( - userId, - dlpId, - ); - const dlpUserTotals = getOrCreateUserTotals(dlpUserTotalsId); - dlpUserTotals.fileContributionsCount = - dlpUserTotals.fileContributionsCount.plus(GraphBigInt.fromI32(1)); - dlpUserTotals.save(); - - // Update dlp file contribution totals - const dlpTotalsId = getTotalsDlpId(dlpId); - const dlpTotals = getOrCreateTotals(dlpTotalsId); - dlpTotals.totalFileContributions = dlpTotals.totalFileContributions.plus( - GraphBigInt.fromI32(1), - ); - if (dlpUserTotals.fileContributionsCount.toI32() === 1) { - dlpTotals.uniqueFileContributors = dlpTotals.uniqueFileContributors.plus( - GraphBigInt.fromI32(1), - ); - } - dlpTotals.save(); + // Update totals using shared utility + updateAllTotals(userId, dlpId); + // Update DLP epoch user (V3 specific functionality) + updateDlpEpochUser(event, epochId, userId, dlpId); } +// Removed: now using shared createDataRegistryProof function + +// Removed: now using shared updateAllTotals function + function updateDlpEpochUser( - event: FileProofAdded, - epochId: string, - userId: string, - dlpId: string, + event: FileProofAdded, + epochId: string, + userId: string, + dlpId: string, ): void { const epoch = Epoch.load(epochId); const dlp = getOrCreateDlp(dlpId); @@ -141,14 +96,13 @@ function updateDlpEpochUser( const verificationBlock = dlp.verificationBlockNumber!; const eligibilityStartBlock = epoch.startBlock.gt(verificationBlock) - ? epoch.startBlock - : verificationBlock; + ? epoch.startBlock + : verificationBlock; if (!event.block.number.ge(eligibilityStartBlock)) { return; } - const id = getDlpEpochUserId(dlpId, epochId, userId); let dlpEpochUser = PerformanceDlpEpochUser.load(id); @@ -160,16 +114,17 @@ function updateDlpEpochUser( dlpEpochUser.save(); } - const dlpEpochTotals = getOrCreateTotalsForDlpEpochPerformance(dlpId, epochId); - dlpEpochTotals.totalFileContributions = dlpEpochTotals.totalFileContributions.plus( - GraphBigInt.fromI32(1), + const dlpEpochTotals = getOrCreateTotalsForDlpEpochPerformance( + dlpId, + epochId, ); + dlpEpochTotals.totalFileContributions = + dlpEpochTotals.totalFileContributions.plus(ONE); if (firstContributionInEpoch) { - dlpEpochTotals.uniqueFileContributors = dlpEpochTotals.uniqueFileContributors.plus( - GraphBigInt.fromI32(1), - ); + dlpEpochTotals.uniqueFileContributors = + dlpEpochTotals.uniqueFileContributors.plus(ONE); } dlpEpochTotals.save(); -} \ No newline at end of file +} diff --git a/src/lib/contract/v4/query-engine.ts b/src/lib/contract/v4/query-engine.ts index 301a2c2..bbc9e17 100644 --- a/src/lib/contract/v4/query-engine.ts +++ b/src/lib/contract/v4/query-engine.ts @@ -1,8 +1,12 @@ import { log } from "@graphprotocol/graph-ts"; import { PaymentReceived, Refiner } from "../../../../generated/schema"; import { PaymentReceived as PaymentReceivedEvent } from "../../../../generated/QueryEngineImplementation/QueryEngineImplementation"; -import { getOrCreateTotals, getOrCreateTotalsGlobal, getTotalsDlpId } from "../../entity/totals"; -import {getTokenAmountInVana} from "../shared"; +import { + getOrCreateTotals, + getOrCreateTotalsGlobal, + getTotalsDlpId, +} from "../../entity/totals"; +import { getTokenAmountInVana } from "../shared"; export function handlePaymentReceived(event: PaymentReceivedEvent): void { // Create unique ID from transaction hash and log index @@ -32,21 +36,20 @@ export function handlePaymentReceived(event: PaymentReceivedEvent): void { // Save the entity payment.save(); - const amountInVana = getTokenAmountInVana(event.params.token, event.params.amount); + const amountInVana = getTokenAmountInVana( + event.params.token, + event.params.amount, + ); //save totals // Update global unique file contribution totals const totals = getOrCreateTotalsGlobal(); - totals.dataAccessFees = totals.dataAccessFees.plus( - amountInVana, - ); + totals.dataAccessFees = totals.dataAccessFees.plus(amountInVana); totals.save(); // Update dlp file contribution totals const dlpTotalsId = getTotalsDlpId(refiner.dlp); const dlpTotals = getOrCreateTotals(dlpTotalsId); - dlpTotals.dataAccessFees = dlpTotals.dataAccessFees.plus( - amountInVana, - ); + dlpTotals.dataAccessFees = dlpTotals.dataAccessFees.plus(amountInVana); dlpTotals.save(); } diff --git a/src/lib/contract/v5/dlp-registry.ts b/src/lib/contract/v5/dlp-registry.ts index 86150b6..cc532a8 100644 --- a/src/lib/contract/v5/dlp-registry.ts +++ b/src/lib/contract/v5/dlp-registry.ts @@ -1,4 +1,4 @@ -import { BigInt, log } from "@graphprotocol/graph-ts"; +import { BigInt as GraphBigInt, log } from "@graphprotocol/graph-ts"; import { DlpRegistered, DlpUpdated, @@ -9,7 +9,7 @@ import { import { Dlp } from "../../../../generated/schema"; import { getOrCreateDlpList } from "../../../../src/lib/entity/dlp-list"; -import {getOrCreateDlp, getOrCreateUser} from "../shared"; +import { getOrCreateDlp, getOrCreateUser } from "../shared"; // Mirrored from DLPRegistry.IDLPRegistry.DlpStatus enum dlpStatus { @@ -43,11 +43,10 @@ export function handleDlpRegisteredV5(event: DlpRegistered): void { dlp.createdAt = event.block.timestamp; dlp.createdTxHash = event.transaction.hash; dlp.createdAtBlock = event.block.number; - dlp.status = BigInt.fromI32(dlpStatus.REGISTERED); - + dlp.status = GraphBigInt.fromI32(dlpStatus.REGISTERED); // Keep staking fields for backward compatibility but set to zero - dlp.performanceRating = BigInt.zero(); + dlp.performanceRating = GraphBigInt.zero(); dlp.save(); @@ -97,7 +96,7 @@ export function handleDlpStatusUpdatedV5(event: DlpStatusUpdated): void { if (dlp != null) { const newStatus = event.params.newStatus; - dlp.status = BigInt.fromI32(newStatus); + dlp.status = GraphBigInt.fromI32(newStatus); dlp.save(); } else { @@ -128,8 +127,15 @@ export function handleDlpTokenUpdatedV5(event: DlpTokenUpdated): void { event.transaction.hash.toHexString(), ]); - // Ensure the Dlp entity exists - const dlp = getOrCreateDlp(event.params.dlpId.toString()); + // Load DLP instead of creating it to handle non-existent DLP case gracefully + const dlp = Dlp.load(event.params.dlpId.toString()); + + if (dlp == null) { + log.error("DLP not found for token update: {}", [ + event.params.dlpId.toString(), + ]); + return; + } dlp.token = event.params.tokenAddress; dlp.save(); diff --git a/src/lib/contract/v5/vana-epoch.ts b/src/lib/contract/v5/vana-epoch.ts index 9366a19..a1f98de 100644 --- a/src/lib/contract/v5/vana-epoch.ts +++ b/src/lib/contract/v5/vana-epoch.ts @@ -1,4 +1,4 @@ -import { BigInt, log } from "@graphprotocol/graph-ts"; +import { log } from "@graphprotocol/graph-ts"; import { EpochCreated, EpochDlpRewardAdded, @@ -6,12 +6,9 @@ import { EpochRewardAmountUpdated, EpochSizeUpdated, } from "../../../../generated/VanaEpochImplementationV5/VanaEpochImplementationV5"; -import { Epoch, EpochReference } from "../../../../generated/schema"; +import { Epoch } from "../../../../generated/schema"; import { getOrCreateCurrentParams } from "../../entity/params"; -import { - EPOCH_REFERENCE_ID_CURRENT, - saveCurrentEpochReference, -} from "../../entity/epoch"; +import { saveCurrentEpochReference } from "../../entity/epoch"; export function handleEpochCreatedV5(event: EpochCreated): void { log.info("handleEpochCreatedV5: {}", [event.transaction.hash.toHexString()]); diff --git a/src/lib/contract/v6/data-portability-grantees.ts b/src/lib/contract/v6/data-portability-grantees.ts new file mode 100644 index 0000000..2ebfad9 --- /dev/null +++ b/src/lib/contract/v6/data-portability-grantees.ts @@ -0,0 +1,36 @@ +import { + log, + BigInt as GraphBigInt, +} from "@graphprotocol/graph-ts"; +import { + GranteeRegistered, +} from "../../../../generated/DataPortabilityGranteesImplementation/DataPortabilityGranteesImplementation"; +import { Grantee } from "../../../../generated/schema"; +import { getOrCreateUser } from "../shared"; + +export function handleGranteeRegistered(event: GranteeRegistered): void { + log.info("Handling GranteeRegistered with granteeId: {}, owner: {}, and granteeAddress: {}", [ + event.params.granteeId.toString(), + event.params.owner.toHexString(), + event.params.granteeAddress.toHexString(), + ]); + + const granteeId = event.params.granteeId.toString(); + let grantee = Grantee.load(granteeId); + + if (grantee == null) { + grantee = new Grantee(granteeId); + } + + // Get or create the owner user + const owner = getOrCreateUser(event.params.owner.toHex()); + + grantee.owner = owner.id; + grantee.address = event.params.granteeAddress; + grantee.publicKey = event.params.publicKey; + grantee.registeredAtBlock = event.block.number; + grantee.registeredAtTimestamp = event.block.timestamp; + grantee.transactionHash = event.transaction.hash; + + grantee.save(); +} \ No newline at end of file diff --git a/src/lib/contract/v6/data-portability-permissions.ts b/src/lib/contract/v6/data-portability-permissions.ts new file mode 100644 index 0000000..d574946 --- /dev/null +++ b/src/lib/contract/v6/data-portability-permissions.ts @@ -0,0 +1,112 @@ +import { + log, + store, + BigInt as GraphBigInt, + Bytes, +} from "@graphprotocol/graph-ts"; +import { + PermissionAdded, + PermissionRevoked, + DataPortabilityPermissionsImplementation, +} from "../../../../generated/DataPortabilityPermissionsImplementation/DataPortabilityPermissionsImplementation"; +import { Permission, Grantee, PermissionFile, File } from "../../../../generated/schema"; +import { getOrCreateUser } from "../shared"; + +export function handlePermissionAdded(event: PermissionAdded): void { + log.info("Handling PermissionAdded with permissionId: {} for user: {} and granteeId: {}", [ + event.params.permissionId.toString(), + event.params.user.toHexString(), + event.params.granteeId.toString(), + ]); + + const grantor = getOrCreateUser(event.params.user.toHex()); + const permissionId = event.params.permissionId.toString(); + const granteeId = event.params.granteeId.toString(); + + // Ensure grantee exists + let grantee = Grantee.load(granteeId); + if (grantee == null) { + log.error("Grantee with id {} not found for permission {}", [granteeId, permissionId]); + return; + } + + // Create permission + const permission = new Permission(permissionId); + permission.grantor = grantor.id; + permission.grantee = grantee.id; + permission.grant = event.params.grant; + permission.addedAtBlock = event.block.number; + permission.addedAtTimestamp = event.block.timestamp; + permission.transactionHash = event.transaction.hash; + + // Get nonce and signature from contract + const contract = DataPortabilityPermissionsImplementation.bind(event.address); + const permissionData = contract.try_permission(event.params.permissionId); + + if (!permissionData.reverted) { + permission.nonce = permissionData.value.nonce; + permission.signature = permissionData.value.signature; + permission.startBlock = permissionData.value.startBlock; + permission.endBlock = permissionData.value.endBlock; + } else { + log.warning( + "Could not get permission data for id {}. Nonce and signature will be zero.", + [permissionId], + ); + permission.nonce = GraphBigInt.zero(); + permission.signature = new Bytes(0); + permission.startBlock = event.block.number; + permission.endBlock = null; + } + + permission.save(); + + // Create PermissionFile entities for each fileId + const fileIds = event.params.fileIds; + for (let i = 0; i < fileIds.length; i++) { + const fileId = fileIds[i]; + const permissionFileId = `${permissionId}-${fileId.toString()}`; + + let permissionFile = PermissionFile.load(permissionFileId); + if (permissionFile == null) { + permissionFile = new PermissionFile(permissionFileId); + permissionFile.permission = permission.id; + + // Load or create the file + let file = File.load(fileId.toString()); + if (file == null) { + // Create a placeholder file if it doesn't exist + file = new File(fileId.toString()); + file.owner = grantor.id; + file.url = ""; + file.addedAtBlock = event.block.number; + file.addedAtTimestamp = event.block.timestamp; + file.transactionHash = event.transaction.hash; + file.save(); + } + + permissionFile.file = file.id; + permissionFile.save(); + } + } +} + +export function handlePermissionRevoked(event: PermissionRevoked): void { + log.info("Handling PermissionRevoked for permissionId: {}", [ + event.params.permissionId.toString(), + ]); + + const permissionId = event.params.permissionId.toString(); + const permission = Permission.load(permissionId); + + if (permission) { + // Set endBlock to indicate when the permission was revoked + permission.endBlock = event.block.number; + permission.save(); + } else { + log.warning( + "Received revoke event for a permission not found in subgraph: {}", + [permissionId], + ); + } +} \ No newline at end of file diff --git a/src/lib/contract/v6/data-portability-servers.ts b/src/lib/contract/v6/data-portability-servers.ts new file mode 100644 index 0000000..84376aa --- /dev/null +++ b/src/lib/contract/v6/data-portability-servers.ts @@ -0,0 +1,110 @@ +import { + log, + store, +} from "@graphprotocol/graph-ts"; +import { + ServerRegistered, + ServerUpdated, + ServerTrusted, + ServerUntrusted, +} from "../../../../generated/DataPortabilityServersImplementation/DataPortabilityServersImplementation"; +import { Server, UserServer } from "../../../../generated/schema"; +import { getOrCreateUser } from "../shared"; + +export function handleServerRegistered(event: ServerRegistered): void { + log.info("Handling ServerRegistered with serverId: {}, owner: {}, serverAddress: {}, and url: {}", [ + event.params.serverId.toString(), + event.params.owner.toHexString(), + event.params.serverAddress.toHexString(), + event.params.url, + ]); + + const serverId = event.params.serverId.toString(); + let server = Server.load(serverId); + + if (server == null) { + server = new Server(serverId); + } + + // Get or create the owner user + const owner = getOrCreateUser(event.params.owner.toHex()); + + server.owner = owner.id; + server.serverAddress = event.params.serverAddress; + server.publicKey = event.params.publicKey; + server.url = event.params.url; + server.registeredAtBlock = event.block.number; + server.registeredAtTimestamp = event.block.timestamp; + server.transactionHash = event.transaction.hash; + + server.save(); +} + +export function handleServerUpdated(event: ServerUpdated): void { + log.info("Handling ServerUpdated for serverId: {} with new url: {}", [ + event.params.serverId.toString(), + event.params.url, + ]); + + const serverId = event.params.serverId.toString(); + const server = Server.load(serverId); + + if (server) { + server.url = event.params.url; + server.save(); + } else { + log.warning("Received update event for a server not found in subgraph: {}", [serverId]); + } +} + +export function handleServerTrusted(event: ServerTrusted): void { + log.info("Handling ServerTrusted for user {} and serverId {}", [ + event.params.user.toHex(), + event.params.serverId.toString(), + ]); + + const user = getOrCreateUser(event.params.user.toHex()); + const serverId = event.params.serverId.toString(); + const compositeId = `${user.id}-${serverId}`; + + // Ensure server exists + let server = Server.load(serverId); + if (server == null) { + log.error("Server with id {} not found for trust relationship", [serverId]); + return; + } + + let userServer = UserServer.load(compositeId); + if (userServer == null) { + userServer = new UserServer(compositeId); + userServer.user = user.id; + userServer.server = server.id; + } + + userServer.trustedAt = event.block.timestamp; + userServer.trustedAtBlock = event.block.number; + userServer.transactionHash = event.transaction.hash; + userServer.save(); +} + +export function handleServerUntrusted(event: ServerUntrusted): void { + log.info("Handling ServerUntrusted for user {} and serverId {}", [ + event.params.user.toHex(), + event.params.serverId.toString(), + ]); + + const userId = event.params.user.toHex(); + const serverId = event.params.serverId.toString(); + const compositeId = `${userId}-${serverId}`; + + const userServer = UserServer.load(compositeId); + if (userServer != null) { + // Set the untrusted block instead of removing the entity + userServer.untrustedAtBlock = event.block.number; + userServer.save(); + } else { + log.warning("Attempted to untrust a server relationship that was not found: {}", [ + compositeId, + ]); + } +} \ No newline at end of file diff --git a/src/lib/contract/v6/index.ts b/src/lib/contract/v6/index.ts new file mode 100644 index 0000000..edc1f6a --- /dev/null +++ b/src/lib/contract/v6/index.ts @@ -0,0 +1,15 @@ +export { + handleGranteeRegistered, +} from "./data-portability-grantees"; + +export { + handlePermissionAdded, + handlePermissionRevoked, +} from "./data-portability-permissions"; + +export { + handleServerRegistered, + handleServerUpdated, + handleServerTrusted, + handleServerUntrusted, +} from "./data-portability-servers"; \ No newline at end of file diff --git a/src/lib/entity/bootstrap/bootstrap.ts b/src/lib/entity/bootstrap/bootstrap.ts index a5323f3..af68688 100644 --- a/src/lib/entity/bootstrap/bootstrap.ts +++ b/src/lib/entity/bootstrap/bootstrap.ts @@ -3,9 +3,11 @@ import {dlps} from "../../../mapping"; import {getOrCreateDlp} from "../../contract/shared"; export function handleBootstrap(block: ethereum.Block): void { - for (let i = 0; i < dlps.length; i++) { - const dlp = getOrCreateDlp(dlps[i].id.toString()); - dlp.verificationBlockNumber = BigInt.fromI32(dlps[i].verificationBlockNumber); + for (let i = 0; i < dlps.length; i++) { + const dlp = getOrCreateDlp(dlps[i].id.toString()); + dlp.verificationBlockNumber = BigInt.fromI32( + dlps[i].verificationBlockNumber, + ); dlp.save(); } diff --git a/src/lib/entity/dlpEpochUser/constants.ts b/src/lib/entity/dlpEpochUser/constants.ts index 5889fde..81343d6 100644 --- a/src/lib/entity/dlpEpochUser/constants.ts +++ b/src/lib/entity/dlpEpochUser/constants.ts @@ -1,4 +1,7 @@ - -export function getDlpEpochUserId(dlpId: string, epochId: string, userId: string): string { +export function getDlpEpochUserId( + dlpId: string, + epochId: string, + userId: string, +): string { return `dlp-${dlpId}-epoch-${epochId}-user-${userId}`; } diff --git a/src/lib/entity/dlpEpochUser/dlp-epoch-user.ts b/src/lib/entity/dlpEpochUser/dlp-epoch-user.ts index 31599ca..5cb5c00 100644 --- a/src/lib/entity/dlpEpochUser/dlp-epoch-user.ts +++ b/src/lib/entity/dlpEpochUser/dlp-epoch-user.ts @@ -1,8 +1,12 @@ import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; import { getDlpEpochUserId } from "./constants"; -import {PerformanceDlpEpochUser} from "../../../../generated/schema"; +import { PerformanceDlpEpochUser } from "../../../../generated/schema"; -export function getOrCreateDlpEpochUser(dlpId: string, epochId: string, userId: string): PerformanceDlpEpochUser { +export function getOrCreateDlpEpochUser( + dlpId: string, + epochId: string, + userId: string, +): PerformanceDlpEpochUser { const id = getDlpEpochUserId(dlpId, epochId, userId); let dlpEpochUser = PerformanceDlpEpochUser.load(id); if (dlpEpochUser == null) { diff --git a/src/lib/entity/epoch/epoch-reference.ts b/src/lib/entity/epoch/epoch-reference.ts index 6a2a4b0..bde29cf 100644 --- a/src/lib/entity/epoch/epoch-reference.ts +++ b/src/lib/entity/epoch/epoch-reference.ts @@ -1,4 +1,4 @@ -import { BigInt, log } from "@graphprotocol/graph-ts"; +import { BigInt as GraphBigInt, log } from "@graphprotocol/graph-ts"; import { Epoch, EpochReference } from "../../../../generated/schema"; import { EPOCH_REFERENCE_ID_CURRENT } from "./constants"; import { epochRanges } from "../../../mapping"; @@ -24,7 +24,7 @@ export function saveCurrentEpochReference(newEpochId: string): EpochReference { return currentEpoch; } -export function getEpochForBlock(blockNumber: BigInt): string { +export function getEpochForBlock(blockNumber: GraphBigInt): string { const currentEpochRef = getCurrentEpochReference(); if (!currentEpochRef || !currentEpochRef.epoch) { return getEpochFromRanges(blockNumber); @@ -35,15 +35,15 @@ export function getEpochForBlock(blockNumber: BigInt): string { return getEpochFromRanges(blockNumber); } - if (currentEpoch.endBlock.le(BigInt.zero())) { + if (currentEpoch.endBlock.le(GraphBigInt.zero())) { return currentEpoch.id; } // If the current epoch is in the past, we need to use the next epoch if (blockNumber.gt(currentEpoch.endBlock)) { // Get the next epoch by incrementing the current epoch ID - const nextEpochId = BigInt.fromString(currentEpoch.id) - .plus(BigInt.fromI32(1)) + const nextEpochId = GraphBigInt.fromString(currentEpoch.id) + .plus(GraphBigInt.fromI32(1)) .toString(); const nextEpoch = Epoch.load(nextEpochId); if (nextEpoch) { @@ -56,7 +56,8 @@ export function getEpochForBlock(blockNumber: BigInt): string { return currentEpoch.id; } -function getEpochFromRanges(blockNumber: BigInt): string { +function getEpochFromRanges(blockNumber: GraphBigInt): string { + // @ts-ignore const blockNumberInt = Number.parseInt(blockNumber.toString()); for (let i = 0; i < epochRanges.length; i++) { diff --git a/src/lib/entity/totals/constants.ts b/src/lib/entity/totals/constants.ts index e16c297..b9bbf69 100644 --- a/src/lib/entity/totals/constants.ts +++ b/src/lib/entity/totals/constants.ts @@ -4,6 +4,9 @@ export function getTotalsDlpId(dlpId: string): string { return `dlp-${dlpId}`; } -export function getTotalsDlpEpochPerformanceId(dlpId: string, epochId: string): string { +export function getTotalsDlpEpochPerformanceId( + dlpId: string, + epochId: string, +): string { return `performance-dlp-${dlpId}-epoch-${epochId}`; } diff --git a/src/lib/entity/totals/totals.ts b/src/lib/entity/totals/totals.ts index ec80854..6244d21 100644 --- a/src/lib/entity/totals/totals.ts +++ b/src/lib/entity/totals/totals.ts @@ -5,11 +5,13 @@ import { Totals } from "../../../../generated/schema"; import { getTotalsDlpEpochPerformanceId, TOTALS_ID_GLOBAL } from "./constants"; export function getOrCreateTotalsGlobal(): Totals { - const totalsId = TOTALS_ID_GLOBAL; - return getOrCreateTotals(totalsId); + return getOrCreateTotals(TOTALS_ID_GLOBAL); } -export function getOrCreateTotalsForDlpEpochPerformance(dlpId: string, epochId: string): Totals { +export function getOrCreateTotalsForDlpEpochPerformance( + dlpId: string, + epochId: string, +): Totals { const totalsId = getTotalsDlpEpochPerformanceId(dlpId, epochId); return getOrCreateTotals(totalsId); } diff --git a/src/mapping.ts.template b/src/mapping.ts.template index 54fa4a4..4f5553a 100644 --- a/src/mapping.ts.template +++ b/src/mapping.ts.template @@ -79,9 +79,23 @@ export * from "./lib/contract/v5/vana-epoch"; {{#includes.v5.dlpPerformance}} export * from "./lib/contract/v5/dlp-performance"; {{/includes.v5.dlpPerformance}} +{{#includes.v5.dataPermission}} +export * from "./lib/contract/v5/data-permission"; +{{/includes.v5.dataPermission}} + +// V6 +{{#includes.v6.dataPortabilityGrantees}} +export * from "./lib/contract/v6/data-portability-grantees"; +{{/includes.v6.dataPortabilityGrantees}} +{{#includes.v6.dataPortabilityPermissions}} +export * from "./lib/contract/v6/data-portability-permissions"; +{{/includes.v6.dataPortabilityPermissions}} +{{#includes.v6.dataPortabilityServers}} +export * from "./lib/contract/v6/data-portability-servers"; +{{/includes.v6.dataPortabilityServers}} //uniswap {{#includes.uniswap.v3}} export * from "./uniswap/v3/mappings/factory"; export * from "./uniswap/v3/mappings/core"; -{{/includes.uniswap.v3}} +{{/includes.uniswap.v3}} \ No newline at end of file diff --git a/subgraph.moksha.yaml b/subgraph.moksha.yaml index 2a26a5f..f3963df 100644 --- a/subgraph.moksha.yaml +++ b/subgraph.moksha.yaml @@ -35,7 +35,7 @@ dataSources: blockHandlers: - handler: handleBootstrap file: ./src/lib/entity/bootstrap/bootstrap.ts - # v1 +# v1 - kind: ethereum/contract name: DataRegistryImplementationV1 network: moksha @@ -61,7 +61,7 @@ dataSources: handler: handleDataRegistryProofAddedV1 file: ./src/mapping.ts - # v2 +# v2 - kind: ethereum/contract name: DataRegistryImplementationV2 network: moksha @@ -240,6 +240,84 @@ dataSources: handler: handleEpochDlpPerformancesSavedV5 file: ./src/mapping.ts +# v6 + - kind: ethereum/contract + name: DataPortabilityGranteesImplementation + network: moksha + source: + address: "0x8325C0A0948483EdA023A1A2Fd895e62C5131234" + abi: DataPortabilityGranteesImplementation + startBlock: 3608836 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Grantee + abis: + - name: DataPortabilityGranteesImplementation + file: ./abis/v6/DataPortabilityGranteesImplementation.json + eventHandlers: + - event: GranteeRegistered(indexed uint256,indexed address,indexed address,string) + handler: handleGranteeRegistered + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataPortabilityPermissionsImplementation + network: moksha + source: + address: "0xD54523048AdD05b4d734aFaE7C68324Ebb7373eF" + abi: DataPortabilityPermissionsImplementation + startBlock: 3608836 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Permission + - User + - Grantee + abis: + - name: DataPortabilityPermissionsImplementation + file: ./abis/v6/DataPortabilityPermissionsImplementation.json + eventHandlers: + - event: PermissionAdded(indexed uint256,indexed address,indexed uint256,string,uint256[]) + handler: handlePermissionAdded + - event: PermissionRevoked(indexed uint256) + handler: handlePermissionRevoked + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataPortabilityServersImplementation + network: moksha + source: + address: "0x1483B1F634DBA75AeaE60da7f01A679aabd5ee2c" + abi: DataPortabilityServersImplementation + startBlock: 3608836 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Server + - UserServer + - User + abis: + - name: DataPortabilityServersImplementation + file: ./abis/v6/DataPortabilityServersImplementation.json + eventHandlers: + - event: ServerRegistered(indexed uint256,indexed address,indexed address,bytes,string) + handler: handleServerRegistered + - event: ServerUpdated(indexed uint256,string) + handler: handleServerUpdated + - event: ServerTrusted(indexed address,indexed uint256) + handler: handleServerTrusted + - event: ServerUntrusted(indexed address,indexed uint256) + handler: handleServerUntrusted + file: ./src/mapping.ts + + +# unuiswap - kind: ethereum/contract name: Factory network: moksha diff --git a/subgraph.vana-moksha.yaml b/subgraph.vana-moksha.yaml index 7a962a7..f486ce2 100644 --- a/subgraph.vana-moksha.yaml +++ b/subgraph.vana-moksha.yaml @@ -184,6 +184,8 @@ dataSources: handler: handleDlpVerificationBlockUpdatedV5 - event: DlpTokenUpdated(indexed uint256,address) handler: handleDlpTokenUpdatedV5 + - event: DlpSubEligibilityThresholdUpdated(uint256) + handler: handleDlpSubEligibilityThresholdUpdatedV5 - event: DlpRegistrationDepositAmountUpdated(uint256) handler: handleDlpRegistrationDepositAmountUpdatedV5 file: ./src/mapping.ts @@ -242,6 +244,105 @@ dataSources: handler: handleEpochDlpPerformancesSavedV5 file: ./src/mapping.ts + - kind: ethereum/contract + name: DataPortabilityGranteesImplementation + network: vana-moksha + source: + address: "0x8325C0A0948483EdA023A1A2Fd895e62C5131234" + abi: DataPortabilityGranteesImplementation + startBlock: 3608836 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Grantee + abis: + - name: DataPortabilityGranteesImplementation + file: ./abis/v6/DataPortabilityGranteesImplementation.json + eventHandlers: + - event: GranteeRegistered(indexed uint256,indexed address,indexed address,string) + handler: handleGranteeRegistered + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataPortabilityPermissionsImplementation + network: vana-moksha + source: + address: "0xD54523048AdD05b4d734aFaE7C68324Ebb7373eF" + abi: DataPortabilityPermissionsImplementation + startBlock: 3608836 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Permission + - User + - Grantee + abis: + - name: DataPortabilityPermissionsImplementation + file: ./abis/v6/DataPortabilityPermissionsImplementation.json + eventHandlers: + - event: PermissionAdded(indexed uint256,indexed address,indexed uint256,string,uint256[]) + handler: handlePermissionAdded + - event: PermissionRevoked(indexed uint256) + handler: handlePermissionRevoked + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataPortabilityServersImplementation + network: vana-moksha + source: + address: "0x1483B1F634DBA75AeaE60da7f01A679aabd5ee2c" + abi: DataPortabilityServersImplementation + startBlock: 3608836 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Server + - UserServer + - User + abis: + - name: DataPortabilityServersImplementation + file: ./abis/v6/DataPortabilityServersImplementation.json + eventHandlers: + - event: ServerRegistered(indexed uint256,indexed address,indexed address,bytes,string) + handler: handleServerRegistered + - event: ServerUpdated(indexed uint256,string) + handler: handleServerUpdated + - event: ServerTrusted(indexed address,indexed uint256) + handler: handleServerTrusted + - event: ServerUntrusted(indexed address,indexed uint256) + handler: handleServerUntrusted + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataRegistryImplementationV5 + network: vana-moksha + source: + address: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C" + abi: DataRegistryImplementationV5 + startBlock: 3425120 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - EpochReference + - DataRegistryProof + abis: + - name: DataRegistryImplementationV5 + file: ./abis/v5/DataRegistryImplementation.json + eventHandlers: + - event: FileAdded(indexed uint256,indexed address,string) + handler: handleFileAddedV3 + - event: ProofAdded(indexed uint256,indexed address,uint256,indexed uint256,uint256,string) + handler: handleDataRegistryProofAddedV3 + file: ./src/mapping.ts + - kind: ethereum/contract name: Factory network: vana-moksha diff --git a/subgraph.vana.light.yaml b/subgraph.vana.light.yaml deleted file mode 100644 index 34f9a3a..0000000 --- a/subgraph.vana.light.yaml +++ /dev/null @@ -1,307 +0,0 @@ -#use this file to deploy the light version of the subgraph (without unswap) -specVersion: 0.0.9 -description: Subgraph for DLPRoot, DataRegistry, VanaEpoch, DLPPerformance -repository: "https://github.com/vana-com/vana-subgraph" - -schema: - file: ./schema.graphql - -# Stub for grafting on existing subgraphs -# -#features: -# - grafting -#graft: -# base: -# block: - -dataSources: - - kind: ethereum/contract - name: Bootstrap - network: vana - source: - address: "0x0000000000000000000000000000000000000000" # dummy - abi: Bootstrap - startBlock: 2558883 - endBlock: 2558883 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Epoch - - Dlp - abis: - - name: Bootstrap - file: ./abis/v1/empty.json - blockHandlers: - - handler: handleBootstrap - file: ./src/lib/entity/bootstrap/bootstrap.ts -# # v1 -# - kind: ethereum/contract -# name: DataRegistryImplementationV1 -# network: vana -# source: -# address: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C" -# abi: DataRegistryImplementationV1 -# startBlock: 700000 -# endBlock: 1283120 -# mapping: -# kind: ethereum/events -# apiVersion: 0.0.6 -# language: wasm/assemblyscript -# entities: -# - EpochReference -# - DataRegistryProof -# abis: -# - name: DataRegistryImplementationV1 -# file: ./abis/v1/DataRegistryImplementation.json -# eventHandlers: -# - event: FileAdded(indexed uint256,indexed address,string) -# handler: handleFileAddedV1 -# - event: ProofAdded(indexed uint256,indexed uint256) -# handler: handleDataRegistryProofAddedV1 -# file: ./src/mapping.ts -# -# #v2 -# - kind: ethereum/contract -# name: DataRegistryImplementationV2 -# network: vana -# source: -# address: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C" -# abi: DataRegistryImplementationV2 -# startBlock: 1283121 -# endBlock: 2109974 -# mapping: -# kind: ethereum/events -# apiVersion: 0.0.6 -# language: wasm/assemblyscript -# entities: -# - EpochReference -# - DataRegistryProof -# abis: -# - name: DataRegistryImplementationV2 -# file: ./abis/v2/DataRegistryImplementation.json -# eventHandlers: -# - event: FileAdded(indexed uint256,indexed address,string) -# handler: handleFileAddedV2 -# - event: ProofAdded(indexed uint256,indexed uint256,indexed uint256,uint256) -# handler: handleDataRegistryProofAddedV2 -# file: ./src/mapping.ts - #v3 - - kind: ethereum/contract - name: DataRegistryImplementationV3 - network: vana - source: - address: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C" - abi: DataRegistryImplementationV3 - startBlock: 2558883 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - EpochReference - - DataRegistryProof - abis: - - name: DataRegistryImplementationV3 - file: ./abis/v3/DataRegistryImplementation.json - eventHandlers: - - event: FileAdded(indexed uint256,indexed address,string) - handler: handleFileAddedV3 - - event: ProofAdded(indexed uint256,indexed address,uint256,indexed uint256,uint256,string) - handler: handleDataRegistryProofAddedV3 - file: ./src/mapping.ts - - # v4 - - kind: ethereum/contract - name: QueryEngineImplementation - network: vana - source: - address: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490" - abi: QueryEngineImplementation - startBlock: 2558883 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - PaymentReceived - abis: - - name: QueryEngineImplementation - file: ./abis/v4/QueryEngineImplementation.json - eventHandlers: - - event: PaymentReceived(indexed address,uint256,uint256,uint256) - handler: handlePaymentReceived - file: ./src/mapping.ts - - - kind: ethereum/contract - name: DataRefinerRegistryImplementation - network: vana - source: - address: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c" - abi: DataRefinerRegistryImplementation - startBlock: 2556371 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Refiner - abis: - - name: DataRefinerRegistryImplementation - file: ./abis/v4/DataRefinerRegistryImplementation.json - eventHandlers: - - event: RefinerAdded(indexed uint256,indexed uint256,string,string,string) - handler: handleRefinerAdded - file: ./src/mapping.ts - - #v5 - - kind: ethereum/contract - name: DLPRegistryImplementationV5 - network: vana - source: - address: "0x4D59880a924526d1dD33260552Ff4328b1E18a43" - abi: DLPRegistryImplementationV5 - startBlock: 3157613 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Dlp - - DlpList - - Params - abis: - - name: DLPRegistryImplementationV5 - file: ./abis/v5/DLPRegistryImplementation.json - eventHandlers: - - event: DlpRegistered(indexed uint256,indexed address,address,address,string,string,string,string) - handler: handleDlpRegisteredV5 - - event: DlpUpdated(indexed uint256,indexed address,address,address,string,string,string,string) - handler: handleDlpUpdatedV5 - - event: DlpStatusUpdated(indexed uint256,uint8) - handler: handleDlpStatusUpdatedV5 - - event: DlpVerificationBlockUpdated(indexed uint256,uint256) - handler: handleDlpVerificationBlockUpdatedV5 - - event: DlpTokenUpdated(indexed uint256,address) - handler: handleDlpTokenUpdatedV5 - file: ./src/mapping.ts - - - kind: ethereum/contract - name: VanaEpochImplementationV5 - network: vana - source: - address: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0" - abi: VanaEpochImplementationV5 - startBlock: 3157613 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Epoch - - EpochReference - - Params - abis: - - name: VanaEpochImplementationV5 - file: ./abis/v5/VanaEpochImplementation.json - eventHandlers: - - event: EpochCreated(uint256,uint256,uint256,uint256) - handler: handleEpochCreatedV5 - - event: EpochDlpRewardAdded(uint256,uint256,uint256) - handler: handleEpochDlpRewardAddedV5 - - event: EpochFinalized(uint256) - handler: handleEpochFinalizedV5 - - event: EpochSizeUpdated(uint256) - handler: handleEpochSizeUpdatedV5 - - event: EpochRewardAmountUpdated(uint256) - handler: handleEpochRewardAmountUpdatedV5 - file: ./src/mapping.ts - - - kind: ethereum/contract - name: DLPPerformanceImplementationV5 - network: vana - source: - address: "0x847715C7DB37cF286611182Be0bD333cbfa29cc1" - abi: DLPPerformanceImplementationV5 - startBlock: 3157613 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Epoch - - Dlp - - DlpPerformance - abis: - - name: DLPPerformanceImplementationV5 - file: ./abis/v5/DLPPerformanceImplementation.json - eventHandlers: - - event: EpochDlpPerformancesSaved(indexed uint256,indexed uint256,uint256,uint256,uint256,uint256) - handler: handleEpochDlpPerformancesSavedV5 - file: ./src/mapping.ts - -# - kind: ethereum/contract -# name: Factory -# network: vana -# source: -# address: "0xc2a0d530e57B1275fbce908031DA636f95EA1E38" -# abi: Factory -# startBlock: 763744 -# mapping: -# kind: ethereum/events -# apiVersion: 0.0.6 -# language: wasm/assemblyscript -# entities: -# - Pool -# - Token -# abis: -# - name: Factory -# file: ./abis/uniswap/factory.json -# - name: ERC20 -# file: ./abis/uniswap/ERC20.json -# - name: ERC20SymbolBytes -# file: ./abis/uniswap/ERC20SymbolBytes.json -# - name: ERC20NameBytes -# file: ./abis/uniswap/ERC20NameBytes.json -# - name: Pool -# file: ./abis/uniswap/pool.json -# eventHandlers: -# - event: PoolCreated(indexed address,indexed address,indexed uint24,int24,address) -# handler: handlePoolCreated -# file: ./src/mapping.ts -# -#templates: -# - kind: ethereum/contract -# name: Pool -# network: vana -# source: -# abi: Pool -# mapping: -# kind: ethereum/events -# apiVersion: 0.0.6 -# language: wasm/assemblyscript -# entities: -# - Pool -# - Token -# abis: -# - name: Pool -# file: ./abis/uniswap/pool.json -# - name: Factory -# file: ./abis/uniswap/factory.json -# - name: ERC20 -# file: ./abis/uniswap/ERC20.json -# eventHandlers: -# - event: Initialize(uint160,int24) -# handler: handleInitialize -# - event: Swap(indexed address,indexed address,int256,int256,uint160,uint128,int24) -# handler: handleSwap -# - event: Mint(address,indexed address,indexed int24,indexed -# int24,uint128,uint256,uint256) -# handler: handleMint -# - event: Burn(indexed address,indexed int24,indexed int24,uint128,uint256,uint256) -# handler: handleBurn -# - event: Collect(indexed address,address,indexed int24,indexed -# int24,uint128,uint128) -# handler: handleCollect -# file: ./src/mapping.ts \ No newline at end of file diff --git a/subgraph.vana.yaml b/subgraph.vana.yaml index d641212..963257a 100644 --- a/subgraph.vana.yaml +++ b/subgraph.vana.yaml @@ -240,6 +240,81 @@ dataSources: handler: handleEpochDlpPerformancesSavedV5 file: ./src/mapping.ts + - kind: ethereum/contract + name: DataPortabilityGranteesImplementation + network: vana + source: + address: "0x8325C0A0948483EdA023A1A2Fd895e62C5131234" + abi: DataPortabilityGranteesImplementation + startBlock: 4052868 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Grantee + abis: + - name: DataPortabilityGranteesImplementation + file: ./abis/v6/DataPortabilityGranteesImplementation.json + eventHandlers: + - event: GranteeRegistered(indexed uint256,indexed address,indexed address,string) + handler: handleGranteeRegistered + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataPortabilityPermissionsImplementation + network: vana + source: + address: "0xD54523048AdD05b4d734aFaE7C68324Ebb7373eF" + abi: DataPortabilityPermissionsImplementation + startBlock: 4052868 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Permission + - User + - Grantee + abis: + - name: DataPortabilityPermissionsImplementation + file: ./abis/v6/DataPortabilityPermissionsImplementation.json + eventHandlers: + - event: PermissionAdded(indexed uint256,indexed address,indexed uint256,string,uint256[]) + handler: handlePermissionAdded + - event: PermissionRevoked(indexed uint256) + handler: handlePermissionRevoked + file: ./src/mapping.ts + + - kind: ethereum/contract + name: DataPortabilityServersImplementation + network: vana + source: + address: "0x1483B1F634DBA75AeaE60da7f01A679aabd5ee2c" + abi: DataPortabilityServersImplementation + startBlock: 4052868 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Server + - UserServer + - User + abis: + - name: DataPortabilityServersImplementation + file: ./abis/v6/DataPortabilityServersImplementation.json + eventHandlers: + - event: ServerRegistered(indexed uint256,indexed address,indexed address,bytes,string) + handler: handleServerRegistered + - event: ServerUpdated(indexed uint256,string) + handler: handleServerUpdated + - event: ServerTrusted(indexed address,indexed uint256) + handler: handleServerTrusted + - event: ServerUntrusted(indexed address,indexed uint256) + handler: handleServerUntrusted + file: ./src/mapping.ts + - kind: ethereum/contract name: Factory network: vana diff --git a/tests/unit/contract/utils/file-owner.ts b/tests/unit/contract/utils/file-owner.ts index 1af6280..ac163ee 100644 --- a/tests/unit/contract/utils/file-owner.ts +++ b/tests/unit/contract/utils/file-owner.ts @@ -1,17 +1,23 @@ -import { FileOwner } from "../../../../generated/schema"; -import { Address } from "@graphprotocol/graph-ts"; +import { Address, BigInt } from "@graphprotocol/graph-ts"; +import { File } from "../../../../generated/schema"; -export function fileOwnerDefaults(id: string, ownerAddress: string): FileOwner { - const file = new FileOwner(id); - file.ownerAddress = Address.fromString(ownerAddress); +export function fileDefaults(id: string, ownerAddress: string, url: string): File { + const file = new File(id); + file.owner = ownerAddress; + file.url = url; + file.schemaId = BigInt.zero(); + file.addedAtBlock = BigInt.zero(); + file.addedAtTimestamp = BigInt.zero(); + file.transactionHash = Address.zero(); return file; } -export function createNewFileOwner( +export function createNewFile( id: string, ownerAddress: string, -): FileOwner { - const file = fileOwnerDefaults(id, ownerAddress); + url: string, +): File { + const file = fileDefaults(id, ownerAddress, url); file.save(); return file; } diff --git a/tests/unit/contract/v1/data-registry-refactored.test.ts b/tests/unit/contract/v1/data-registry-refactored.test.ts new file mode 100644 index 0000000..4b6dd6c --- /dev/null +++ b/tests/unit/contract/v1/data-registry-refactored.test.ts @@ -0,0 +1,137 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; +import { + handleFileAddedV1, + handleDataRegistryProofAddedV1 +} from "../../../../src/lib/contract/v1/data-registry"; +import { createFileAddedEvent } from "./utils/data-registry-events"; +import { createProofAddedEvent } from "./utils/data-registry-events"; +import { createNewEpoch, createNewEpochReference } from "../utils"; +import { EPOCH_REFERENCE_ID_CURRENT } from "../../../../src/lib/entity/epoch"; + +// Hook to clear the store before each test +beforeEach(() => { + clearStore(); +}); + +describe("V1 Data Registry Refactored Handlers", () => { + test("handleFileAddedV1 creates File and User entities using shared utilities", () => { + // ARRANGE + const fileId = 1; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const url = "ipfs://QmTest123"; + + const fileAddedEvent = createFileAddedEvent(fileId, ownerAddress, url); + + // ACT + handleFileAddedV1(fileAddedEvent); + + // ASSERT + // Check that File entity was created with correct properties + assert.entityCount("File", 1); + assert.fieldEquals("File", fileId.toString(), "id", fileId.toString()); + assert.fieldEquals("File", fileId.toString(), "owner", ownerAddress); + assert.fieldEquals("File", fileId.toString(), "url", url); + assert.fieldEquals("File", fileId.toString(), "schemaId", "0"); // V1 should use default schema ID + assert.fieldEquals("File", fileId.toString(), "addedAtBlock", fileAddedEvent.block.number.toString()); + assert.fieldEquals("File", fileId.toString(), "addedAtTimestamp", fileAddedEvent.block.timestamp.toString()); + assert.fieldEquals("File", fileId.toString(), "transactionHash", fileAddedEvent.transaction.hash.toHexString()); + + // Check that User entity was created + assert.entityCount("User", 1); + assert.fieldEquals("User", ownerAddress, "id", ownerAddress); + }); + + test("handleDataRegistryProofAddedV1 creates proof and updates totals using shared utilities", () => { + // ARRANGE + const fileId = 1; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const url = "ipfs://QmTest123"; + const proofIndex = 0; + + // Create required entities first + const fileEvent = createFileAddedEvent(fileId, ownerAddress, url); + handleFileAddedV1(fileEvent); + + // Create epoch entities + createNewEpoch("1"); + createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); + + const proofEvent = createProofAddedEvent(fileId, proofIndex); + + // ACT + handleDataRegistryProofAddedV1(proofEvent); + + // ASSERT + // Check that DataRegistryProof entity was created + assert.entityCount("DataRegistryProof", 1); + const proofId = proofEvent.transaction.hash.toHexString(); + assert.fieldEquals("DataRegistryProof", proofId, "id", proofId); + assert.fieldEquals("DataRegistryProof", proofId, "epoch", "1"); + assert.fieldEquals("DataRegistryProof", proofId, "fileId", fileId.toString()); + assert.fieldEquals("DataRegistryProof", proofId, "proofIndex", proofIndex.toString()); + assert.fieldEquals("DataRegistryProof", proofId, "createdAt", proofEvent.block.timestamp.toString()); + assert.fieldEquals("DataRegistryProof", proofId, "createdAtBlock", proofEvent.block.number.toString()); + assert.fieldEquals("DataRegistryProof", proofId, "createdTxHash", proofEvent.transaction.hash.toHexString()); + + // Check that totals were updated (V1 only has global totals) + assert.entityCount("Totals", 1); + assert.fieldEquals("Totals", "global", "totalFileContributions", "1"); + assert.fieldEquals("Totals", "global", "uniqueFileContributors", "1"); + + // Check that UserTotals was created + assert.entityCount("UserTotals", 1); + const userTotalsId = `user-${ownerAddress}`; + assert.fieldEquals("UserTotals", userTotalsId, "fileContributionsCount", "1"); + }); + + test("handleDataRegistryProofAddedV1 handles missing epoch gracefully", () => { + // ARRANGE + const fileId = 1; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const url = "ipfs://QmTest123"; + const proofIndex = 0; + + // Create file but NO epoch + const fileEvent = createFileAddedEvent(fileId, ownerAddress, url); + handleFileAddedV1(fileEvent); + + const proofEvent = createProofAddedEvent(fileId, proofIndex); + + // ACT + handleDataRegistryProofAddedV1(proofEvent); + + // ASSERT + // Should not create any proof or totals when epoch is missing + assert.entityCount("DataRegistryProof", 0); + assert.entityCount("Totals", 0); + assert.entityCount("UserTotals", 0); + }); + + test("handleDataRegistryProofAddedV1 handles missing file gracefully", () => { + // ARRANGE + const fileId = 999; // Non-existent file + const proofIndex = 0; + + // Create epoch but NO file + createNewEpoch("1"); + createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); + + const proofEvent = createProofAddedEvent(fileId, proofIndex); + + // ACT + handleDataRegistryProofAddedV1(proofEvent); + + // ASSERT + // Should create proof but not update totals when file is missing + assert.entityCount("DataRegistryProof", 1); + assert.entityCount("Totals", 0); + assert.entityCount("UserTotals", 0); + }); +}); \ No newline at end of file diff --git a/tests/unit/contract/v1/data-registry.test.ts b/tests/unit/contract/v1/data-registry.test.ts new file mode 100644 index 0000000..7f94ac7 --- /dev/null +++ b/tests/unit/contract/v1/data-registry.test.ts @@ -0,0 +1,48 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; +import { handleFileAddedV1 } from "../../../../src/lib/contract/v1/data-registry"; +import { createFileAddedEvent } from "./utils/data-registry-events"; + +// Hook to clear the store before each test, ensuring test isolation +beforeEach(() => { + clearStore(); +}); + +describe("handleFileAddedV1", () => { + test("creates a File entity and associated User", () => { + // 1. ARRANGE: Set up test data and create the mock event + const fileId = 1; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const url = "ipfs://Qm..."; + + const fileAddedEvent = createFileAddedEvent(fileId, ownerAddress, url); + + // 2. ACT: Call the handler function with the mock event + handleFileAddedV1(fileAddedEvent); + + // 3. ASSERT: Check that the store is in the correct state + + // Check that a File entity was created + assert.entityCount("File", 1); + assert.fieldEquals("File", fileId.toString(), "id", fileId.toString()); + assert.fieldEquals("File", fileId.toString(), "owner", ownerAddress); + assert.fieldEquals("File", fileId.toString(), "url", url); + assert.fieldEquals("File", fileId.toString(), "schemaId", "0"); // Important check for V1 + assert.fieldEquals( + "File", + fileId.toString(), + "transactionHash", + fileAddedEvent.transaction.hash.toHexString(), + ); + + // Check that the associated User was created + assert.entityCount("User", 1); + assert.fieldEquals("User", ownerAddress, "id", ownerAddress); + }); +}); diff --git a/tests/unit/contract/v1/utils/data-registry-events.ts b/tests/unit/contract/v1/utils/data-registry-events.ts new file mode 100644 index 0000000..c3da23d --- /dev/null +++ b/tests/unit/contract/v1/utils/data-registry-events.ts @@ -0,0 +1,48 @@ +import { Address, ethereum } from "@graphprotocol/graph-ts"; +import { newMockEvent } from "matchstick-as/assembly/index"; +import { + FileAdded as FileAddedEvent, + ProofAdded as ProofAddedEvent +} from "../../../../../generated/DataRegistryImplementationV1/DataRegistryImplementationV1"; + +export function createFileAddedEvent( + fileId: i32, + ownerAddress: string, + url: string, +): FileAddedEvent { + const normalizedAddr = ownerAddress.toLowerCase(); + const fileAddedEvent = changetype(newMockEvent()); + fileAddedEvent.parameters = new Array(); + + fileAddedEvent.parameters.push( + new ethereum.EventParam("fileId", ethereum.Value.fromI32(fileId)), + ); + fileAddedEvent.parameters.push( + new ethereum.EventParam( + "ownerAddress", + ethereum.Value.fromAddress(Address.fromString(normalizedAddr)), + ), + ); + fileAddedEvent.parameters.push( + new ethereum.EventParam("url", ethereum.Value.fromString(url)), + ); + + return fileAddedEvent; +} + +export function createProofAddedEvent( + fileId: i32, + proofIndex: i32, +): ProofAddedEvent { + const proofAddedEvent = changetype(newMockEvent()); + proofAddedEvent.parameters = new Array(); + + proofAddedEvent.parameters.push( + new ethereum.EventParam("fileId", ethereum.Value.fromI32(fileId)), + ); + proofAddedEvent.parameters.push( + new ethereum.EventParam("proofIndex", ethereum.Value.fromI32(proofIndex)), + ); + + return proofAddedEvent; +} diff --git a/tests/unit/contract/v2/data-registry.test.ts b/tests/unit/contract/v2/data-registry.test.ts index 7144b1e..1ce66e2 100644 --- a/tests/unit/contract/v2/data-registry.test.ts +++ b/tests/unit/contract/v2/data-registry.test.ts @@ -22,7 +22,7 @@ import { createNewUser, } from "../utils"; import { EPOCH_REFERENCE_ID_CURRENT } from "../../../../src/lib/entity/epoch"; -import { createNewFileOwner } from "../utils/file-owner"; +import { createNewFile } from "../utils/file-owner"; import { createNewUserTotals } from "../utils/user-totals"; import { getTotalsDlpId, @@ -43,7 +43,7 @@ describe("handleDataRegistryProofAddedV2", () => { createNewEpoch("1"); createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); createNewDlp("1", user.id, "dlp-1"); - createNewFileOwner("1", "0x334e8bbf9c7822fc3f66b11cb0d8ef84c5a4b5ce"); + createNewFile("1", "0x334e8bbf9c7822fc3f66b11cb0d8ef84c5a4b5ce", "ipfs://test"); const proofEvent = createProofAddedEvent( 1, // fileId @@ -127,7 +127,7 @@ describe("handleDataRegistryProofAddedV2", () => { createNewEpoch("1"); createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); createNewDlp("1", user.id, "dlp-1"); - createNewFileOwner("1", "0x334e8bbf9c7822fc3f66b11cb0d8ef84c5a4b5ce"); + createNewFile("1", "0x334e8bbf9c7822fc3f66b11cb0d8ef84c5a4b5ce", "ipfs://test"); const globalTotals = createNewTotals(TOTALS_ID_GLOBAL); globalTotals.totalFileContributions = GraphBigInt.fromString("5"); diff --git a/tests/unit/contract/v3/data-registry.test.ts b/tests/unit/contract/v3/data-registry.test.ts index 899fa98..7b82557 100644 --- a/tests/unit/contract/v3/data-registry.test.ts +++ b/tests/unit/contract/v3/data-registry.test.ts @@ -22,7 +22,7 @@ import { createNewUser, } from "../utils"; import { EPOCH_REFERENCE_ID_CURRENT } from "../../../../src/lib/entity/epoch"; -import { createNewFileOwner } from "../utils/file-owner"; +import { createNewFile } from "../utils/file-owner"; import { createNewUserTotals } from "../utils/user-totals"; import { getTotalsDlpId, @@ -128,7 +128,7 @@ describe("handleDataRegistryProofAddedV3", () => { createNewEpoch("1"); createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); createNewDlp("1", user.id, "dlp-1"); - createNewFileOwner("1", "0x334e8bbf9c7822fc3f66b11cb0d8ef84c5a4b5ce"); + createNewFile("1", "0x334e8bbf9c7822fc3f66b11cb0d8ef84c5a4b5ce", "ipfs://test"); const globalTotals = createNewTotals(TOTALS_ID_GLOBAL); globalTotals.totalFileContributions = GraphBigInt.fromString("5"); diff --git a/tests/unit/integration/refactored-handlers.test.ts b/tests/unit/integration/refactored-handlers.test.ts new file mode 100644 index 0000000..ed79948 --- /dev/null +++ b/tests/unit/integration/refactored-handlers.test.ts @@ -0,0 +1,190 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; +import { + handleFileAddedV1, + handleDataRegistryProofAddedV1 +} from "../../../src/lib/contract/v1/data-registry"; +import { + handleFileAddedV2, + handleDataRegistryProofAddedV2 +} from "../../../src/lib/contract/v2/data-registry"; +import { + handleFileAddedV3, + handleDataRegistryProofAddedV3 +} from "../../../src/lib/contract/v3/data-registry"; +import { createFileAddedEvent } from "../contract/v1/utils/data-registry-events"; +import { createProofAddedEvent } from "../contract/v1/utils/data-registry-events"; +import { createFileAddedEvent as createFileAddedEventV2 } from "../contract/v2/utils/data-registry-events"; +import { createProofAddedEvent as createProofAddedEventV2 } from "../contract/v2/utils/data-registry-events"; +import { createFileAddedEvent as createFileAddedEventV3 } from "../contract/v3/utils/data-registry-events"; +import { createProofAddedEvent as createProofAddedEventV3 } from "../contract/v3/utils/data-registry-events"; +import { + createNewEpoch, + createNewEpochReference, + createNewDlp, + createNewUser +} from "../contract/utils"; +import { EPOCH_REFERENCE_ID_CURRENT } from "../../../src/lib/entity/epoch"; + +// Hook to clear the store before each test +beforeEach(() => { + clearStore(); +}); + +describe("Integration Tests for Refactored Handlers", () => { + test("V1, V2, and V3 handlers all use shared utilities correctly", () => { + // ARRANGE + const fileId1 = 1; + const fileId2 = 2; + const fileId3 = 3; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const dlpId = "1"; + const url = "ipfs://QmTest123"; + + // Create required entities + createNewEpoch("1"); + createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); + createNewUser(ownerAddress); + createNewDlp(dlpId, ownerAddress, "Test DLP"); + + // Create file events for all versions + const fileEventV1 = createFileAddedEvent(fileId1, ownerAddress, url); + const fileEventV2 = createFileAddedEventV2(fileId2, ownerAddress, url); + const fileEventV3 = createFileAddedEventV3(fileId3, ownerAddress, url); + + // ACT - Handle file events + handleFileAddedV1(fileEventV1); + handleFileAddedV2(fileEventV2); + handleFileAddedV3(fileEventV3); + + // ASSERT - All versions should create File entities with correct schema IDs + assert.entityCount("File", 3); + assert.fieldEquals("File", fileId1.toString(), "schemaId", "0"); // V1 default + assert.fieldEquals("File", fileId2.toString(), "schemaId", "0"); // V2 default + assert.fieldEquals("File", fileId3.toString(), "schemaId", "0"); // V3 default + + // All should have same owner + assert.fieldEquals("File", fileId1.toString(), "owner", ownerAddress); + assert.fieldEquals("File", fileId2.toString(), "owner", ownerAddress); + assert.fieldEquals("File", fileId3.toString(), "owner", ownerAddress); + + // Only one User entity should be created (shared utility) + assert.entityCount("User", 1); + assert.fieldEquals("User", ownerAddress, "id", ownerAddress); + }); + + test("V1, V2, and V3 proof handlers create different proof structures", () => { + // ARRANGE + const fileId1 = 1; + const fileId2 = 2; + const fileId3 = 3; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const dlpId = "1"; + const url = "ipfs://QmTest123"; + const proofIndex = 0; + + // Create required entities + createNewEpoch("1"); + createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); + createNewUser(ownerAddress); + createNewDlp(dlpId, ownerAddress, "Test DLP"); + + // Create files first + const fileEventV1 = createFileAddedEvent(fileId1, ownerAddress, url); + const fileEventV2 = createFileAddedEventV2(fileId2, ownerAddress, url); + const fileEventV3 = createFileAddedEventV3(fileId3, ownerAddress, url); + + handleFileAddedV1(fileEventV1); + handleFileAddedV2(fileEventV2); + handleFileAddedV3(fileEventV3); + + // Create proof events + const proofEventV1 = createProofAddedEvent(fileId1, proofIndex); + const proofEventV2 = createProofAddedEventV2(fileId2, proofIndex, parseInt(dlpId), 100); + const proofEventV3 = createProofAddedEventV3(fileId3, ownerAddress, parseInt(dlpId), proofIndex, 100, "test"); + + // ACT - Handle proof events + handleDataRegistryProofAddedV1(proofEventV1); + handleDataRegistryProofAddedV2(proofEventV2); + handleDataRegistryProofAddedV3(proofEventV3); + + // ASSERT - All versions should create DataRegistryProof entities + assert.entityCount("DataRegistryProof", 3); + + // V1 proof should not have user or DLP + const proofIdV1 = proofEventV1.transaction.hash.toHexString(); + assert.fieldEquals("DataRegistryProof", proofIdV1, "epoch", "1"); + assert.fieldEquals("DataRegistryProof", proofIdV1, "fileId", fileId1.toString()); + + // V2 proof should have DLP but not user + const proofIdV2 = proofEventV2.transaction.hash.toHexString(); + assert.fieldEquals("DataRegistryProof", proofIdV2, "dlp", dlpId); + assert.fieldEquals("DataRegistryProof", proofIdV2, "epoch", "1"); + + // V3 proof should have both user and DLP + const proofIdV3 = proofEventV3.transaction.hash.toHexString(); + assert.fieldEquals("DataRegistryProof", proofIdV3, "user", ownerAddress); + assert.fieldEquals("DataRegistryProof", proofIdV3, "dlp", dlpId); + assert.fieldEquals("DataRegistryProof", proofIdV3, "epoch", "1"); + }); + + test("Totals are updated correctly across all versions", () => { + // ARRANGE + const fileId1 = 1; + const fileId2 = 2; + const fileId3 = 3; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const dlpId = "1"; + const url = "ipfs://QmTest123"; + const proofIndex = 0; + + // Create required entities + createNewEpoch("1"); + createNewEpochReference(EPOCH_REFERENCE_ID_CURRENT, "1"); + createNewUser(ownerAddress); + createNewDlp(dlpId, ownerAddress, "Test DLP"); + + // Create files + const fileEventV1 = createFileAddedEvent(fileId1, ownerAddress, url); + const fileEventV2 = createFileAddedEventV2(fileId2, ownerAddress, url); + const fileEventV3 = createFileAddedEventV3(fileId3, ownerAddress, url); + + handleFileAddedV1(fileEventV1); + handleFileAddedV2(fileEventV2); + handleFileAddedV3(fileEventV3); + + // Create proof events + const proofEventV1 = createProofAddedEvent(fileId1, proofIndex); + const proofEventV2 = createProofAddedEventV2(fileId2, proofIndex, parseInt(dlpId), 100); + const proofEventV3 = createProofAddedEventV3(fileId3, ownerAddress, parseInt(dlpId), proofIndex, 100, "test"); + + // ACT - Handle proof events + handleDataRegistryProofAddedV1(proofEventV1); + handleDataRegistryProofAddedV2(proofEventV2); + handleDataRegistryProofAddedV3(proofEventV3); + + // ASSERT - Check global totals + assert.entityCount("Totals", 2); // Global + DLP totals + assert.fieldEquals("Totals", "global", "totalFileContributions", "3"); + assert.fieldEquals("Totals", "global", "uniqueFileContributors", "1"); // Same user + + // Check DLP totals (V2 and V3 should contribute) + const dlpTotalsId = `dlp-${dlpId}`; + assert.fieldEquals("Totals", dlpTotalsId, "totalFileContributions", "2"); + assert.fieldEquals("Totals", dlpTotalsId, "uniqueFileContributors", "1"); + + // Check user totals + const userTotalsId = `user-${ownerAddress}`; + assert.fieldEquals("UserTotals", userTotalsId, "fileContributionsCount", "3"); + + // Check DLP user totals + const dlpUserTotalsId = `user-${ownerAddress}-dlp-${dlpId}`; + assert.fieldEquals("UserTotals", dlpUserTotalsId, "fileContributionsCount", "2"); + }); +}); \ No newline at end of file diff --git a/tests/unit/lib/contract/shared/constants.test.ts b/tests/unit/lib/contract/shared/constants.test.ts new file mode 100644 index 0000000..c467901 --- /dev/null +++ b/tests/unit/lib/contract/shared/constants.test.ts @@ -0,0 +1,40 @@ +import { + assert, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; +import { + ONE, + ZERO, + ERROR_NO_EPOCH, + ERROR_DLP_NOT_FOUND, + ERROR_NO_FILE_OWNER, + DEFAULT_SCHEMA_ID +} from "../../../../../src/lib/contract/shared/constants"; + +describe("Shared Constants", () => { + test("BigInt constants are correct", () => { + // ASSERT + assert.bigIntEquals(ONE, GraphBigInt.fromI32(1)); + assert.bigIntEquals(ZERO, GraphBigInt.fromI32(0)); + assert.bigIntEquals(DEFAULT_SCHEMA_ID, ZERO); + }); + + test("Error message constants are defined", () => { + // ASSERT + assert.stringEquals(ERROR_NO_EPOCH, "No epoch found for block"); + assert.stringEquals(ERROR_DLP_NOT_FOUND, "DLP not found for proof"); + assert.stringEquals(ERROR_NO_FILE_OWNER, "Cannot update totals: file not found or has no owner"); + }); + + test("Constants are usable in computations", () => { + // ARRANGE & ACT + const result = ONE.plus(ZERO); + const doubled = ONE.times(GraphBigInt.fromI32(2)); + + // ASSERT + assert.bigIntEquals(result, GraphBigInt.fromI32(1)); + assert.bigIntEquals(doubled, GraphBigInt.fromI32(2)); + }); +}); \ No newline at end of file diff --git a/tests/unit/lib/contract/shared/event-utils.test.ts b/tests/unit/lib/contract/shared/event-utils.test.ts new file mode 100644 index 0000000..ca9506c --- /dev/null +++ b/tests/unit/lib/contract/shared/event-utils.test.ts @@ -0,0 +1,160 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt, ethereum } from "@graphprotocol/graph-ts"; +import { newMockEvent } from "matchstick-as/assembly/index"; +import { + logEventWithTxHash, + logEntityNotFound, + setBlockchainMetadata, + createCompositeId, + createTransactionId +} from "../../../../../src/lib/contract/shared/event-utils"; + +// Hook to clear the store before each test +beforeEach(() => { + clearStore(); +}); + +describe("logEventWithTxHash", () => { + test("logs event without throwing", () => { + // ARRANGE + const eventName = "TestEvent"; + const transactionHash = "0xabcd1234"; + + // ACT - this should not throw + logEventWithTxHash(eventName, transactionHash); + + // ASSERT - if we reach here, the function didn't throw + assert.assertTrue(true); + }); +}); + +describe("logEntityNotFound", () => { + test("logs entity not found without throwing", () => { + // ARRANGE + const entityType = "TestEntity"; + const entityId = "123"; + + // ACT - this should not throw + logEntityNotFound(entityType, entityId); + + // ASSERT - if we reach here, the function didn't throw + assert.assertTrue(true); + }); + + test("logs entity not found with context without throwing", () => { + // ARRANGE + const entityType = "TestEntity"; + const entityId = "456"; + const context = "test operation"; + + // ACT - this should not throw + logEntityNotFound(entityType, entityId, context); + + // ASSERT - if we reach here, the function didn't throw + assert.assertTrue(true); + }); +}); + +describe("setBlockchainMetadata", () => { + test("sets blockchain metadata on entity", () => { + // ARRANGE + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + const logIndex = GraphBigInt.fromI32(5); + + // Create a simple entity-like object + const entity = new Map(); + + // ACT + setBlockchainMetadata(entity, mockBlock, mockTransaction, logIndex); + + // ASSERT + // Note: In a real scenario, we'd test this with an actual entity + // but this tests that the function doesn't throw + assert.assertTrue(true); + }); + + test("sets blockchain metadata without log index", () => { + // ARRANGE + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + + const entity = new Map(); + + // ACT + setBlockchainMetadata(entity, mockBlock, mockTransaction); + + // ASSERT + assert.assertTrue(true); + }); +}); + +describe("createCompositeId", () => { + test("creates composite ID with default separator", () => { + // ARRANGE + const parts = ["user", "123", "dlp", "456"]; + + // ACT + const id = createCompositeId(parts); + + // ASSERT + assert.stringEquals(id, "user-123-dlp-456"); + }); + + test("creates composite ID with custom separator", () => { + // ARRANGE + const parts = ["prefix", "middle", "suffix"]; + const separator = "_"; + + // ACT + const id = createCompositeId(parts, separator); + + // ASSERT + assert.stringEquals(id, "prefix_middle_suffix"); + }); + + test("creates composite ID with single part", () => { + // ARRANGE + const parts = ["single"]; + + // ACT + const id = createCompositeId(parts); + + // ASSERT + assert.stringEquals(id, "single"); + }); +}); + +describe("createTransactionId", () => { + test("creates transaction-based ID", () => { + // ARRANGE + const transactionHash = "0xabcd1234567890"; + const logIndex = GraphBigInt.fromI32(42); + + // ACT + const id = createTransactionId(transactionHash, logIndex); + + // ASSERT + assert.stringEquals(id, "0xabcd1234567890-42"); + }); + + test("creates transaction-based ID with zero log index", () => { + // ARRANGE + const transactionHash = "0xdef456789abc"; + const logIndex = GraphBigInt.fromI32(0); + + // ACT + const id = createTransactionId(transactionHash, logIndex); + + // ASSERT + assert.stringEquals(id, "0xdef456789abc-0"); + }); +}); \ No newline at end of file diff --git a/tests/unit/lib/contract/shared/file-handlers.test.ts b/tests/unit/lib/contract/shared/file-handlers.test.ts new file mode 100644 index 0000000..5cefc4b --- /dev/null +++ b/tests/unit/lib/contract/shared/file-handlers.test.ts @@ -0,0 +1,95 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt, ethereum, Address, Bytes } from "@graphprotocol/graph-ts"; +import { newMockEvent } from "matchstick-as/assembly/index"; +import { createFileFromEvent, logDataRegistryEvent } from "../../../../../src/lib/contract/shared/file-handlers"; + +// Hook to clear the store before each test +beforeEach(() => { + clearStore(); +}); + +describe("createFileFromEvent", () => { + test("creates a File entity with all required fields", () => { + // ARRANGE + const fileId = "123"; + const ownerAddress = "0x1234567890123456789012345678901234567890"; + const url = "ipfs://QmTest123"; + const schemaId = GraphBigInt.fromI32(42); + + // Create mock block and transaction + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + + // ACT + const file = createFileFromEvent( + fileId, + ownerAddress, + url, + mockBlock, + mockTransaction, + schemaId + ); + + // ASSERT + assert.entityCount("File", 1); + assert.fieldEquals("File", fileId, "id", fileId); + assert.fieldEquals("File", fileId, "owner", ownerAddress); + assert.fieldEquals("File", fileId, "url", url); + assert.fieldEquals("File", fileId, "schemaId", schemaId.toString()); + assert.fieldEquals("File", fileId, "addedAtBlock", mockBlock.number.toString()); + assert.fieldEquals("File", fileId, "addedAtTimestamp", mockBlock.timestamp.toString()); + assert.fieldEquals("File", fileId, "transactionHash", mockTransaction.hash.toHexString()); + + // Check that User entity was created + assert.entityCount("User", 1); + assert.fieldEquals("User", ownerAddress, "id", ownerAddress); + }); + + test("creates a File entity with default schema ID", () => { + // ARRANGE + const fileId = "456"; + const ownerAddress = "0x2345678901234567890123456789012345678901"; + const url = "ipfs://QmTest456"; + + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + + // ACT - don't provide schemaId, should use default + const file = createFileFromEvent( + fileId, + ownerAddress, + url, + mockBlock, + mockTransaction + ); + + // ASSERT + assert.entityCount("File", 1); + assert.fieldEquals("File", fileId, "schemaId", "0"); // Default should be 0 + }); +}); + +describe("logDataRegistryEvent", () => { + test("logs event without throwing", () => { + // This test ensures the logging function doesn't throw errors + // In matchstick, we can't directly test log output, but we can ensure it doesn't crash + + // ARRANGE + const eventName = "FileAdded"; + const transactionHash = "0xabcd1234"; + + // ACT - this should not throw + logDataRegistryEvent(eventName, transactionHash); + + // ASSERT - if we reach here, the function didn't throw + assert.assertTrue(true); + }); +}); \ No newline at end of file diff --git a/tests/unit/lib/contract/shared/proof-handlers.test.ts b/tests/unit/lib/contract/shared/proof-handlers.test.ts new file mode 100644 index 0000000..52561d1 --- /dev/null +++ b/tests/unit/lib/contract/shared/proof-handlers.test.ts @@ -0,0 +1,109 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt, ethereum, Address, Bytes } from "@graphprotocol/graph-ts"; +import { newMockEvent } from "matchstick-as/assembly/index"; +import { createDataRegistryProof } from "../../../../../src/lib/contract/shared/proof-handlers"; + +// Hook to clear the store before each test +beforeEach(() => { + clearStore(); +}); + +describe("createDataRegistryProof", () => { + test("creates a DataRegistryProof entity with all required fields", () => { + // ARRANGE + const transactionHash = "0xabcd1234567890abcd1234567890abcd12345678"; + const epochId = "epoch-1"; + const fileId = GraphBigInt.fromI32(123); + const proofIndex = GraphBigInt.fromI32(456); + + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + + // ACT + const proof = createDataRegistryProof( + transactionHash, + epochId, + fileId, + proofIndex, + mockBlock, + mockTransaction + ); + + // ASSERT + assert.entityCount("DataRegistryProof", 1); + assert.fieldEquals("DataRegistryProof", transactionHash, "id", transactionHash); + assert.fieldEquals("DataRegistryProof", transactionHash, "epoch", epochId); + assert.fieldEquals("DataRegistryProof", transactionHash, "fileId", fileId.toString()); + assert.fieldEquals("DataRegistryProof", transactionHash, "proofIndex", proofIndex.toString()); + assert.fieldEquals("DataRegistryProof", transactionHash, "createdAt", mockBlock.timestamp.toString()); + assert.fieldEquals("DataRegistryProof", transactionHash, "createdAtBlock", mockBlock.number.toString()); + assert.fieldEquals("DataRegistryProof", transactionHash, "createdTxHash", mockTransaction.hash.toHexString()); + }); + + test("creates a DataRegistryProof entity with optional user and DLP", () => { + // ARRANGE + const transactionHash = "0xdef456789abcdef456789abcdef456789abcdef45"; + const epochId = "epoch-2"; + const fileId = GraphBigInt.fromI32(789); + const proofIndex = GraphBigInt.fromI32(101); + const userId = "0x1234567890123456789012345678901234567890"; + const dlpId = "dlp-123"; + + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + + // ACT + const proof = createDataRegistryProof( + transactionHash, + epochId, + fileId, + proofIndex, + mockBlock, + mockTransaction, + userId, + dlpId + ); + + // ASSERT + assert.entityCount("DataRegistryProof", 1); + assert.fieldEquals("DataRegistryProof", transactionHash, "user", userId); + assert.fieldEquals("DataRegistryProof", transactionHash, "dlp", dlpId); + }); + + test("creates a DataRegistryProof entity with null optional fields", () => { + // ARRANGE + const transactionHash = "0x987654321098765432109876543210987654321"; + const epochId = "epoch-3"; + const fileId = GraphBigInt.fromI32(999); + const proofIndex = GraphBigInt.fromI32(888); + + const mockEvent = newMockEvent(); + const mockBlock = mockEvent.block; + const mockTransaction = mockEvent.transaction; + + // ACT + const proof = createDataRegistryProof( + transactionHash, + epochId, + fileId, + proofIndex, + mockBlock, + mockTransaction, + null, + null + ); + + // ASSERT + assert.entityCount("DataRegistryProof", 1); + assert.fieldEquals("DataRegistryProof", transactionHash, "id", transactionHash); + // Optional fields should not be set when null is passed + }); +}); \ No newline at end of file diff --git a/tests/unit/lib/contract/shared/totals-updater.test.ts b/tests/unit/lib/contract/shared/totals-updater.test.ts new file mode 100644 index 0000000..46b849b --- /dev/null +++ b/tests/unit/lib/contract/shared/totals-updater.test.ts @@ -0,0 +1,175 @@ +import { + assert, + beforeEach, + clearStore, + describe, + test, +} from "matchstick-as/assembly/index"; +import { BigInt as GraphBigInt } from "@graphprotocol/graph-ts"; +import { + updateGlobalTotals, + updateDlpTotals, + updateAllTotals, + updateTotalsFromFile +} from "../../../../../src/lib/contract/shared/totals-updater"; +import { createNewUser } from "../../../contract/utils/user"; +import { createNewFile } from "../../../contract/utils/file-owner"; +import { createNewTotals } from "../../../contract/utils/totals"; +import { createNewUserTotals } from "../../../contract/utils/user-totals"; +import { + TOTALS_ID_GLOBAL, + getTotalsDlpId +} from "../../../../../src/lib/entity/totals"; +import { + getUserTotalsId, + getUserTotalsIdDlp +} from "../../../../../src/lib/entity/usertotals"; + +// Hook to clear the store before each test +beforeEach(() => { + clearStore(); +}); + +describe("updateGlobalTotals", () => { + test("updates global totals for first-time user", () => { + // ARRANGE + const userId = "0x1234567890123456789012345678901234567890"; + createNewUser(userId); + createNewTotals(TOTALS_ID_GLOBAL); + + // ACT + updateGlobalTotals(userId); + + // ASSERT + // Check user totals + const userTotalsId = getUserTotalsId(userId); + assert.entityCount("UserTotals", 1); + assert.fieldEquals("UserTotals", userTotalsId, "fileContributionsCount", "1"); + + // Check global totals + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "totalFileContributions", "1"); + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "uniqueFileContributors", "1"); + }); + + test("updates global totals for returning user", () => { + // ARRANGE + const userId = "0x1234567890123456789012345678901234567890"; + createNewUser(userId); + createNewTotals(TOTALS_ID_GLOBAL); + + // Create existing user totals with 2 contributions + const userTotalsId = getUserTotalsId(userId); + const userTotals = createNewUserTotals(userTotalsId); + userTotals.fileContributionsCount = GraphBigInt.fromI32(2); + userTotals.save(); + + // ACT + updateGlobalTotals(userId); + + // ASSERT + // Check user totals incremented + assert.fieldEquals("UserTotals", userTotalsId, "fileContributionsCount", "3"); + + // Check global totals - should increment total but not unique contributors + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "totalFileContributions", "1"); + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "uniqueFileContributors", "0"); + }); +}); + +describe("updateDlpTotals", () => { + test("updates DLP totals for first-time user", () => { + // ARRANGE + const userId = "0x1234567890123456789012345678901234567890"; + const dlpId = "dlp-123"; + createNewUser(userId); + + const dlpTotalsId = getTotalsDlpId(dlpId); + createNewTotals(dlpTotalsId); + + // ACT + updateDlpTotals(userId, dlpId); + + // ASSERT + // Check DLP user totals + const dlpUserTotalsId = getUserTotalsIdDlp(userId, dlpId); + assert.entityCount("UserTotals", 1); + assert.fieldEquals("UserTotals", dlpUserTotalsId, "fileContributionsCount", "1"); + + // Check DLP totals + assert.fieldEquals("Totals", dlpTotalsId, "totalFileContributions", "1"); + assert.fieldEquals("Totals", dlpTotalsId, "uniqueFileContributors", "1"); + }); +}); + +describe("updateAllTotals", () => { + test("updates both global and DLP totals when DLP provided", () => { + // ARRANGE + const userId = "0x1234567890123456789012345678901234567890"; + const dlpId = "dlp-456"; + createNewUser(userId); + createNewTotals(TOTALS_ID_GLOBAL); + createNewTotals(getTotalsDlpId(dlpId)); + + // ACT + updateAllTotals(userId, dlpId); + + // ASSERT + // Check global totals + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "totalFileContributions", "1"); + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "uniqueFileContributors", "1"); + + // Check DLP totals + const dlpTotalsId = getTotalsDlpId(dlpId); + assert.fieldEquals("Totals", dlpTotalsId, "totalFileContributions", "1"); + assert.fieldEquals("Totals", dlpTotalsId, "uniqueFileContributors", "1"); + }); + + test("updates only global totals when no DLP provided", () => { + // ARRANGE + const userId = "0x1234567890123456789012345678901234567890"; + createNewUser(userId); + createNewTotals(TOTALS_ID_GLOBAL); + + // ACT + updateAllTotals(userId, null); + + // ASSERT + // Check global totals + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "totalFileContributions", "1"); + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "uniqueFileContributors", "1"); + + // Should not create any DLP totals + assert.entityCount("Totals", 1); // Only global totals + }); +}); + +describe("updateTotalsFromFile", () => { + test("updates totals based on file owner", () => { + // ARRANGE + const fileId = "123"; + const userId = "0x1234567890123456789012345678901234567890"; + createNewUser(userId); + createNewFile(fileId, userId, "ipfs://test"); + createNewTotals(TOTALS_ID_GLOBAL); + + // ACT + updateTotalsFromFile(fileId, null); + + // ASSERT + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "totalFileContributions", "1"); + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "uniqueFileContributors", "1"); + }); + + test("handles non-existent file gracefully", () => { + // ARRANGE + const fileId = "999"; + createNewTotals(TOTALS_ID_GLOBAL); + + // ACT - should not throw + updateTotalsFromFile(fileId, null); + + // ASSERT - totals should remain unchanged + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "totalFileContributions", "0"); + assert.fieldEquals("Totals", TOTALS_ID_GLOBAL, "uniqueFileContributors", "0"); + }); +}); \ No newline at end of file