diff --git a/README.md b/README.md index fdcd1c58..8cbae83b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # Subgraphs Airstack Subgraphs + +## Verticals Supported in airstack-modules +1. NFT_MARKET_PLACE - [Check docs here](https://github.com/Airstack-xyz/Subgraphs/tree/main/airstack-modules/modules/airstack/nft-marketplace/Readme.md) + +2. DOMAIN_NAME - [Check docs here](https://github.com/Airstack-xyz/Subgraphs/tree/main/airstack-modules/modules/airstack/domain-name/Readme.md) \ No newline at end of file diff --git a/airstack-modules/bin/index.ts b/airstack-modules/bin/index.ts index 8db87356..d398de42 100755 --- a/airstack-modules/bin/index.ts +++ b/airstack-modules/bin/index.ts @@ -69,211 +69,18 @@ for (let index = START_INDEX; index < args.length; index++) { integrate(vertical, yaml, graphql, dataSources, templates) .then(() => { switch (vertical) { - case Vertical.Dex: - console.log(` - Integration done. Please call the following functions. - 1. Add pool - - function addDexPool( - poolAddress: string, - fee: BigInt, - inputTokens: Array, - weights: Array | null = null, - outputToken: string | null = null - ): void - - 2. Add pool - - function swap( - poolAddress: string, - inputAmounts: Array, - outputAmounts: Array, - inputTokenIndex: i32, - outputTokenIndex: i32, - from: string, - to: string, - hash: string, - logIndex: BigInt, - timestamp: BigInt, - blockNumber: BigInt - ): void - - For documentation and examples please check: https://github.com/Airstack-xyz/Subgraphs - `); - break; case Vertical.NftMarketplace: console.log(` - Integration done. Please call the following functions. - - 1. Track NFT trade transaction - trackNFTSaleTransactions( - chainID: string, - txHash: string, - txIndex: BigInt, - NftSales: Sale[], - protocolType: string, - protocolActionType: string, - timestamp: BigInt, - blockHeight: BigInt, - blockHash: string - ) - - For documentation and examples please check: https://github.com/Airstack-xyz/Subgraphs +Integration for NFT_MARKET_PLACE vertical done. For documentation and examples please check below link: +https://github.com/Airstack-xyz/Subgraphs/tree/main/airstack-modules/modules/airstack/nft-marketplace/Readme.md `); break; case Vertical.DomainName: console.log(` - Integration done. Please call the following functions. - - 1. Track domain owner change transaction - trackDomainOwnerChangedTransaction( - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - chainId: string, - newOwner: string, - transactionHash: string, - isMigrated: boolean, - node: Bytes, - label: Bytes, - tokenAddress: string, - fromOldRegistry: boolean, - ) - - 2. Track domain transfer transaction - trackDomainTransferTransaction( - node: string, - chainId: string, - newOwnerAddress: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - transactionHash: string, - tokenAddress: string, - fromOldRegistry: boolean, - ) - - 3. Track domain new resolver transaction - trackDomainNewResolverTransaction( - resolver: string, - node: string, - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - transactionHash: string, - logIndex: BigInt, - tokenAddress: string, - fromOldRegistry: boolean, - ) - - 4. Track domain new ttl transaction - trackDomainNewTTLTransaction( - node: string, - newTTL: BigInt, - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - transactionHash: string, - tokenAddress: string, - fromOldRegistry: boolean, - ) - - 5. Track name registered transaction - trackNameRegisteredTransaction( - transactionHash: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - chainId: string, - registrantAddress: string, - expiryTimestamp: BigInt, - cost: BigInt, - paymentToken: string, - labelId: BigInt, - rootNode: ByteArray, - tokenAddress: string, - ) - - 6. Track name renewed transaction - trackNameRenewedTransaction( - transactionHash: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - chainId: string, - cost: BigInt | null, - paymentToken: string, - renewer: string, - labelId: BigInt, - rootNode: ByteArray, - expiryTimestamp: BigInt, - tokenAddress: string, - ) - - 7. Track set name preimage transaction - trackSetNamePreImage( - name: string, - label: Bytes, - cost: BigInt, - paymentToken: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - chainId: string, - rootNode: ByteArray, - tokenAddress: string, - transactionHash: string, - renewer: string | null, - expiryTimestamp: BigInt | null, - fromRegistrationEvent: boolean, - ) - - 8. Track addr(resolvedAddress) changed transaction - trackAddrChangedTransaction( - chainId: string, - logIndex: BigInt, - resolverAddress: string, - addr: string, - node: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - transactionHash: string, - tokenAddress: string, - ) - - 9. Track resolver version changed transaction - trackResolverVersionChange( - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - node: string, - resolverAddress: string, - tokenAddress: string, - ) - - 10. Track set primary domain transaction - trackSetPrimaryDomainTransaction( - ensName: string, - chainId: string, - from: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - transactionHash: string, - tokenAddress: string, - ) - - For documentation and examples please check: https://github.com/Airstack-xyz/Subgraphs +Integration for DOMAIN_NAME vertical done. For documentation and examples please check below link: +https://github.com/Airstack-xyz/Subgraphs/tree/main/airstack-modules/modules/airstack/domain-name/Readme.md ` ); break; diff --git a/airstack-modules/graphql/airstack-domain-name-schema.graphql.ts b/airstack-modules/graphql/airstack-domain-name-schema.graphql.ts index 0d6463ee..805ead03 100644 --- a/airstack-modules/graphql/airstack-domain-name-schema.graphql.ts +++ b/airstack-modules/graphql/airstack-domain-name-schema.graphql.ts @@ -25,9 +25,16 @@ type AirEntityCounter @entity { lastUpdatedAt: AirBlock! } +type AirExtra @entity { + id: ID! # Concatenation of domainId and name + name: String! + value: String! +} + type AirAccount @entity { id: ID! address: String! + createdAt: AirBlock! } type AirToken @entity { @@ -39,7 +46,7 @@ type AirDomain @entity { id: ID! # The namehash of the name name: String # The human readable name, if known. Unknown portions replaced with hash in square brackets (eg, foo.[1234].eth) labelName: String # The human readable label name (imported from CSV), if known - labelHash: Bytes # keccak256(labelName) + labelHash: String # keccak256(labelName) tokenId: String # dec(labelHash) parent: AirDomain # The namehash (id) of the parent name subdomains: [AirDomain!]! @derivedFrom(field: "parent") # Can count domains from length of array @@ -47,14 +54,14 @@ type AirDomain @entity { resolvedAddress: AirAccount # Address logged from current resolver, if any owner: AirAccount! resolver: AirResolver - ttl: BigInt isPrimary: Boolean! # - NA # Is the primary domain for the resolved address expiryTimestamp: BigInt! registrationCost: BigInt! # Cost of domain registration in wei paymentToken: AirToken # Token used to pay for registration tokenAddress: AirToken! # Domain (eg: ens) token contract address createdAt: AirBlock! - lastBlock: AirBlock #- NA + lastUpdatedBlock: AirBlock #- NA + extras: [AirExtra!] } type AirDomainTransferTransaction implements AirDomainEvent @entity { @@ -105,14 +112,14 @@ type AirResolver @entity { id: ID! # Concatenation of resolver address and namehash domain: AirDomain address: AirAccount! # Address of resolver contract - resolvedAddress: AirAccount # Current value of addr record (per events) + resolvedAddress: AirAccount # Current value of resolved address record (per events) } -type AirAddrChanged implements AirDomainEvent @entity { +type AirResolvedAddressChanged implements AirDomainEvent @entity { id: ID! resolver: AirResolver! - previousResolvedAddress: AirAccount # previous addr record - newResolvedAddress: AirAccount! # new addr record + previousResolvedAddress: AirAccount # previous resolved address record + newResolvedAddress: AirAccount! # new resolved address record block: AirBlock! transactionHash: String! tokenId: String # dec(labelhash) - NA diff --git a/airstack-modules/modules/airstack/common/index.ts b/airstack-modules/modules/airstack/common/index.ts index 8dc75e56..b1f17b81 100644 --- a/airstack-modules/modules/airstack/common/index.ts +++ b/airstack-modules/modules/airstack/common/index.ts @@ -7,6 +7,9 @@ import { AirBlock, AirEntityCounter, AirMeta, + AirAccount, + AirExtra, + AirToken, } from "../../../generated/schema"; export const AIR_META_ID = "AIR_META"; @@ -17,9 +20,9 @@ export const BIG_INT_ZERO = BigInt.fromI32(0); export const SUBGRAPH_SCHEMA_VERSION = "1.0.0"; -export const SUBGRAPH_NAME = "AIRSTACK-SUBGRAPH"; -export const SUBGRAPH_VERSION = "AIRSTACK-SUBGRAPH"; -export const SUBGRAPH_SLUG = "AIRSTACK-SUBGRAPH"; +export const SUBGRAPH_NAME = "AIRSTACK_SUBGRAPH"; +export const SUBGRAPH_VERSION = "AIRSTACK_SUBGRAPH"; +export const SUBGRAPH_SLUG = "AIRSTACK_SUBGRAPH"; const AIR_NETWORK_MAP = new TypedMap(); AIR_NETWORK_MAP.set("arbitrum-one", "ARBITRUM_ONE"); @@ -44,12 +47,42 @@ AIR_NETWORK_MAP.set("osmosis", "OSMOSIS"); AIR_NETWORK_MAP.set("matic", "MATIC"); AIR_NETWORK_MAP.set("xdai", "XDAI"); -export function processNetwork(network: string): string { +const AIR_CHAIN_ID_MAP = new TypedMap(); +AIR_CHAIN_ID_MAP.set("arbitrum-one", "42161"); +AIR_CHAIN_ID_MAP.set("arweave-mainnet", "174"); +AIR_CHAIN_ID_MAP.set("aurora", "1313161554"); +AIR_CHAIN_ID_MAP.set("avalanche", "43114"); +AIR_CHAIN_ID_MAP.set("boba", "288"); +AIR_CHAIN_ID_MAP.set("bsc", "56"); +AIR_CHAIN_ID_MAP.set("celo", "42220"); +AIR_CHAIN_ID_MAP.set("COSMOS", "cosmos"); +AIR_CHAIN_ID_MAP.set("CRONOS", "25"); +AIR_CHAIN_ID_MAP.set("mainnet", "1"); +AIR_CHAIN_ID_MAP.set("fantom", "250"); +AIR_CHAIN_ID_MAP.set("fuse", "122"); +AIR_CHAIN_ID_MAP.set("harmony", "1666600000"); +AIR_CHAIN_ID_MAP.set("juno", "juno-1"); +AIR_CHAIN_ID_MAP.set("moonbeam", "1284"); +AIR_CHAIN_ID_MAP.set("moonriver", "1285"); +AIR_CHAIN_ID_MAP.set("near-mainnet", "1313161554"); +AIR_CHAIN_ID_MAP.set("optimism", "10"); +AIR_CHAIN_ID_MAP.set("osmosis", "osmosis-1"); +AIR_CHAIN_ID_MAP.set("matic", "137"); +AIR_CHAIN_ID_MAP.set("xdai", "100"); + +export function getNetwork(network: string): string { const value = AIR_NETWORK_MAP.get(network); const result: string = value !== null ? value : "unknown"; return result; } +export function getChainId(): string { + let network = dataSource.network(); + const value = AIR_CHAIN_ID_MAP.get(network); + const result: string = value !== null ? value : "unknown"; + return result; +} + //air entity funcitons /** @@ -90,7 +123,7 @@ export function createAirMeta( let meta = AirMeta.load(AIR_META_ID); if (meta == null) { meta = new AirMeta(AIR_META_ID); - meta.network = processNetwork(dataSource.network()); + meta.network = getNetwork(dataSource.network()); meta.schemaVersion = SUBGRAPH_SCHEMA_VERSION; meta.version = SUBGRAPH_VERSION; meta.slug = slug; @@ -100,6 +133,7 @@ export function createAirMeta( } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new air block entity * @param chainId chain id * @param blockHeight block number @@ -121,7 +155,63 @@ export function getOrCreateAirBlock( block.hash = blockHash; block.number = blockHeight; block.timestamp = blockTimestamp - block.save() } return block as AirBlock; +} + +/** + * @dev this function does not save the returned entity + * @dev this function gets or creates a new air account entity + * @param chainId chain id + * @param address account address + * @param block air block object + * @returns AirAccount entity + */ +export function getOrCreateAirAccount(chainId: string, address: string, block: AirBlock): AirAccount { + let id = chainId.concat("-").concat(address); + let entity = AirAccount.load(id); + if (entity == null) { + entity = new AirAccount(id); + entity.address = address; + entity.createdAt = block.id; + } + return entity as AirAccount; +} + +/** + * @dev this function does not save the returned entity + * @dev this function creates an air extra entity + * @param name air extra name + * @param value air extra value + * @param extraId air extra entity id + * @returns air extra entity + */ +export function createAirExtra( + name: string, + value: string, + id: string, +): AirExtra { + let entity = AirExtra.load(id); + if (entity == null) { + entity = new AirExtra(id); + entity.name = name; + entity.value = value; + } + return entity as AirExtra; +} + +/** + * @dev this function does not save the returned entity + * @dev this function gets or creates a new air token entity + * @param chainID chain id + * @param address token address + * @returns AirToken entity + */ +export function getOrCreateAirToken(chainID: string, address: string): AirToken { + let entity = AirToken.load(chainID + "-" + address); + if (entity == null) { + entity = new AirToken(chainID + "-" + address); + entity.address = address; + } + return entity as AirToken; } \ No newline at end of file diff --git a/airstack-modules/modules/airstack/domain-name/Readme.md b/airstack-modules/modules/airstack/domain-name/Readme.md new file mode 100644 index 00000000..c46caff9 --- /dev/null +++ b/airstack-modules/modules/airstack/domain-name/Readme.md @@ -0,0 +1,126 @@ +# DOMAIN_NAME vertical integration +### After module integration for DOMAIN_NAME vertical is done. Please call the below functions to track the transactions of the domain name vertical. +``` +1. Track transaction when a domain owner is changed + trackDomainOwnerChangedTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + parentDomainId: string, #air domain entity id for parent domain - needs to be unique for each domain + tokenId: string, #ERC721 token id - keccack256(labelHash) - needs to be unique for each token + labelHash: string, #hex value of a label + labelName: string | null, #label name - eg: 'airswap' in airswap.eth + name: string | null, #domain name - eg: 'airswap.eth' + newOwner: string, #new owner address + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +2. Track transaction when a domain is transferred + trackDomainTransferTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + newOwnerAddress: string, #address to which the domain is transferred + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +3. Track transaction when a domain resolver is changed + trackDomainNewResolverTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + resolver: string, #new resolver address linked to the domain + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +4. Track transaction when a domain TTL is changed + trackDomainNewTTLTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + newTTL: BigInt, #new TTL value for the domain + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +5. Track transaction when a domain is registered + trackNameRegisteredTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + registrantAddress: string, #address which registered the domain + expiryTimestamp: BigInt, #unix time at which domain expires + cost: BigInt, #cost of domain registration in wei + paymentToken: string, #address of token used for registration cost + labelName: string | null, #label name - eg: 'airswap' in airswap.eth + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +6. Track transaction when a domain is renewed + trackNameRenewedTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + domainId: string, #air domain entity id - needs to be unique for each domain + cost: BigInt | null, #cost of domain renewal in wei + paymentToken: string, #address of token used for renewal cost + renewer: string, #address which renewed the domain + expiryTimestamp: BigInt, #unix time at which domain expires + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +7. Track controller transaction when a domain is renewed or registered + trackNameRenewedOrRegistrationByController( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + domainId: string, #air domain entity id - needs to be unique for each domain + name: string, #domain name - eg: 'airswap.eth' + label: Bytes, #hex value of a label + cost: BigInt, #cost of domain registration or renewal in wei + paymentToken: string, #address of token used for registration or renewal cost + renewer: string | null, #address which renewed the domain + expiryTimestamp: BigInt | null, #unix time at which domain expires + fromRegistrationEvent: boolean, #true if the transaction is from a registration event + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +8. Track transaction when a domain's resolved address is changed + trackResolvedAddressChangedTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + resolverAddress: string, #address of the resolver contract + resolvedAddress: string, #address which the domain resolves to + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +9. Track transaction when a domain's resolver version is changed + trackResolverVersionChange( + block: ethereum.Block, #ethereum block object in subgraph + domainId: string, #air domain entity id - needs to be unique for each domain + resolverAddress: string, #address of the resolver contract + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +10. Track transaction when an resolved address's primary domain is changed + trackSetPrimaryDomainTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + domainName: string, #domain name - eg: 'airswap.eth' + from: string, #address which changed its primary domain to the domainName + tokenAddress: string, #token address for ERC721 token + ) +``` \ No newline at end of file diff --git a/airstack-modules/modules/airstack/domain-name/domain-name.ts b/airstack-modules/modules/airstack/domain-name/domain-name.ts index 71f1f52b..4567b951 100644 --- a/airstack-modules/modules/airstack/domain-name/domain-name.ts +++ b/airstack-modules/modules/airstack/domain-name/domain-name.ts @@ -5,6 +5,7 @@ import { log, ByteArray, ens, + ethereum, } from "@graphprotocol/graph-ts"; import { @@ -19,99 +20,74 @@ import { AirDomainNewTTLTransaction, AirNameRegisteredTransaction, AirNameRenewedTransaction, - AirAddrChanged, + AirResolvedAddressChanged, AirPrimaryDomainTransaction, ReverseRegistrar, PrimaryDomain, - DomainVsIsMigratedMapping, + AirExtra, } from "../../../generated/schema"; -import { uint256ToByteArray, AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID, AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID, AIR_ADDR_CHANGED_ENTITY_COUNTER_ID, AIR_NAME_RENEWED_ENTITY_COUNTER_ID, AIR_NAME_REGISTERED_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID, AIR_DOMAIN_TRANSFER_ENTITY_COUNTER_ID, ROOT_NODE, ZERO_ADDRESS, ETHEREUM_MAINNET_ID } from "./utils"; -import { BIGINT_ONE, BIG_INT_ZERO, EMPTY_STRING, updateAirEntityCounter, getOrCreateAirBlock } from "../common"; +import { AIR_EXTRA_TTL, AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID, AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID, AIR_ADDR_CHANGED_ENTITY_COUNTER_ID, AIR_NAME_RENEWED_ENTITY_COUNTER_ID, AIR_NAME_REGISTERED_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID, AIR_DOMAIN_TRANSFER_ENTITY_COUNTER_ID, ZERO_ADDRESS, ETHEREUM_MAINNET_ID } from "./utils"; +import { BIGINT_ONE, BIG_INT_ZERO, EMPTY_STRING, getChainId, updateAirEntityCounter, getOrCreateAirBlock, getOrCreateAirAccount, createAirExtra, getOrCreateAirToken } from "../common"; export namespace domain { /** * @dev This function tracks a domain owner change transaction - * @param blockHeight block number in the chain - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex txn log index - * @param chainId chain id - * @param newOwner specifies the new owner of the domain + * @param block ethreum block * @param transactionHash transaction hash - * @param isMigrated specifies if the domain is migrated - * @param node specifies the node of the domain - * @param label specifies the label of the domain + * @param logOrCallIndex txn log or call index + * @param domainId domain id + * @param parentDomainId specifies the parentDomainId + * @param tokenId token id + * @param labelHash specifies the label hash + * @param labelName label name + * @param name domain name + * @param newOwner specifies the new owner of the domain * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry - */ + */ export function trackDomainOwnerChangedTransaction( - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - chainId: string, - newOwner: string, + block: ethereum.Block, transactionHash: string, - isMigrated: boolean, - node: Bytes, - label: Bytes, + logOrCallIndex: BigInt, + domainId: string, + parentDomainId: string, + tokenId: string, + labelHash: string, + labelName: string | null, + name: string | null, + newOwner: string, tokenAddress: string, - fromOldRegistry: boolean, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domainId = createAirDomainEntityId(node, label); - let domain = getOrCreateAirDomain(new Domain(domainId, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domainId, block.id, isMigrated); - if (fromOldRegistry && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); let previousOwnerId = domain.owner; - let parent = getOrCreateAirDomain(new Domain( - node.toHexString(), + let parentDomain = getOrCreateAirDomain(new Domain( + parentDomainId, chainId, - block, + airBlock, tokenAddress, )); - if (domain.parent == null && parent != null) { - parent.subdomainCount = parent.subdomainCount.plus(BIGINT_ONE); - } - if (domain.name == null) { - let labelName = ens.nameByHash(label.toHexString()); - if (labelName != null) { - domain.labelName = labelName; - } - if (labelName === null) { - labelName = '[' + label.toHexString().slice(2) + ']'; - } - if (node.toHexString() == ROOT_NODE) { - domain.name = labelName; - } else { - let name = parent.name; - if (labelName && name) { - domain.name = labelName + '.' + name; - } - } + if (domain.parent == null) { + parentDomain.subdomainCount = parentDomain.subdomainCount.plus(BIGINT_ONE); + parentDomain.lastUpdatedBlock = airBlock.id; } - - let tokenId = BigInt.fromUnsignedBytes(label).toString(); - domain.owner = getOrCreateAirAccount(chainId, newOwner).id; - domain.parent = parent.id; - domain.labelHash = label; + domain.name = name; + domain.labelName = labelName; + let ownerAccount = getOrCreateAirAccount(chainId, newOwner, airBlock); + ownerAccount.save(); + domain.owner = ownerAccount.id; + domain.parent = parentDomain.id; + domain.labelHash = labelHash; domain.tokenId = tokenId; - domain.lastBlock = block.id; - recurseSubdomainCountDecrement(domain, chainId, block, tokenAddress); + domain.lastUpdatedBlock = airBlock.id; + parentDomain.save(); domain.save(); + recurseSubdomainCountDecrement(domain, chainId, airBlock, tokenAddress); - // creating reverse registrar to get domainId when setting primary domain - if (domain.name) { - createReverseRegistrar(domain.name!, domain.id, block); - } - // creating is migrated mapping - getOrCreateIsMigratedMapping(domainId, block.id, isMigrated); - getOrCreateAirDomainOwnerChangedTransaction( - block, - logIndex, + let txn = getOrCreateAirDomainOwnerChangedTransaction( + airBlock, + logOrCallIndex, chainId, previousOwnerId, newOwner, @@ -119,56 +95,48 @@ export namespace domain { tokenId, domain, ); + txn.save(); } /** - * @dev This function tracks a domain transfer transaction - * @param node specifies the node of the domain - * @param chainId chain id - * @param newOwnerAddress specifies the new owner of the domain - * @param blockHeight block number in the chain - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex txn log index - * @param transactionHash transaction hash - * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry + * @dev This function tracks a domain transfer transaction + * @param block ethereum block + * @param transactionHash transaction hash + * @param logOrCallIndex txn log or call index + * @param domainId domain id + * @param newOwnerAddress specifies the new owner of the domain + * @param tokenAddress contract address of nft token */ export function trackDomainTransferTransaction( - node: string, - chainId: string, - newOwnerAddress: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, + block: ethereum.Block, transactionHash: string, + logOrCallIndex: BigInt, + domainId: string, + newOwnerAddress: string, tokenAddress: string, - fromOldRegistry: boolean, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domain.id, block.id); - if (fromOldRegistry && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); let previousOwnerId = domain.owner; if (previousOwnerId == null) { - previousOwnerId = getOrCreateAirAccount(chainId, ZERO_ADDRESS).id; + let previousOwnerAccount = getOrCreateAirAccount(chainId, ZERO_ADDRESS, airBlock); + previousOwnerAccount.save(); + previousOwnerId = previousOwnerAccount.id; } - let id = createEntityId(transactionHash, blockHeight, logIndex); + // update domain owner here + let newOwnerAccount = getOrCreateAirAccount(chainId, newOwnerAddress, airBlock); + newOwnerAccount.save(); + domain.owner = newOwnerAccount.id; + domain.lastUpdatedBlock = airBlock.id; + domain.save(); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirDomainTransferTransaction.load(id); if (entity == null) { entity = new AirDomainTransferTransaction(id); entity.from = previousOwnerId; - entity.to = getOrCreateAirAccount(chainId, newOwnerAddress).id; - let airBlock = getOrCreateAirBlock( - chainId, - blockHeight, - blockHash, - blockTimestamp, - ); + entity.to = newOwnerAccount.id; entity.block = airBlock.id; entity.transactionHash = transactionHash; entity.tokenId = domain.tokenId; @@ -180,42 +148,32 @@ export namespace domain { /** * @dev This function tracks a new resolver transaction - * @param resolver resolver contract address - * @param node domain node - * @param chainId chain id - * @param blockHeight block number in the chain - * @param blockHash block hash - * @param blockTimestamp block timestamp + * @param block ethereum block * @param transactionHash transaction hash - * @param logIndex event log index + * @param logOrCallIndex txn log or call index + * @param domainId air domain id + * @param resolver resolver contract address * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry */ export function trackDomainNewResolverTransaction( - resolver: string, - node: string, - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, + block: ethereum.Block, transactionHash: string, - logIndex: BigInt, + logOrCallIndex: BigInt, + domainId: string, + resolver: string, tokenAddress: string, - fromOldRegistry: boolean, ): void { + let chainId = getChainId(); // get block - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); // get domain - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domain.id, block.id); - if (fromOldRegistry && node != ROOT_NODE && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); // get previous resolver let previousResolverId = domain.resolver; // create new resolver - let resolverEntity = getOrCreateAirResolver(domain, chainId, resolver); + let resolverEntity = getOrCreateAirResolver(domain, chainId, airBlock, resolver); + resolverEntity.save(); // update domain resolver domain.resolver = resolverEntity.id; // update domain resolved address @@ -223,236 +181,229 @@ export namespace domain { domain.resolvedAddress = resolverEntity.resolvedAddress; } // do recursive subdomain count decrement - domain.lastBlock = block.id; - recurseSubdomainCountDecrement(domain, chainId, block, tokenAddress); + domain.lastUpdatedBlock = airBlock.id; domain.save(); + recurseSubdomainCountDecrement(domain, chainId, airBlock, tokenAddress); // create new resolver transaction - getOrCreateAirDomainNewResolverTransaction( + let tnx = getOrCreateAirDomainNewResolverTransaction( previousResolverId, resolverEntity.address, - block, + airBlock, transactionHash, - logIndex, + logOrCallIndex, domain, - ) + ); + tnx.save(); } /** * @dev This function tracks a new TTL transaction - * @param node domain node - * @param newTTL new TTL - * @param chainId chain id - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex event log index + * @param block ethereum block * @param transactionHash transaction hash + * @param logOrCallIndex txn log or call index + * @param domainId air domain id + * @param newTTL new TTL * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry */ export function trackDomainNewTTLTransaction( - node: string, - newTTL: BigInt, - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, + block: ethereum.Block, transactionHash: string, + logOrCallIndex: BigInt, + domainId: string, + newTTL: BigInt, tokenAddress: string, - fromOldRegistry: boolean, ): void { + let chainId = getChainId(); // get block - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); // get domain - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domain.id, block.id); - if (fromOldRegistry && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); // get previous ttl let oldTTL: BigInt | null = null; - if (domain.ttl) { - oldTTL = domain.ttl; + // load extra entity for ttl + let extraId = domainId.concat("-").concat(AIR_EXTRA_TTL); + let extra = AirExtra.load(extraId); + if (extra != null) { + // if exists, assign oldTTL and update value with newTTL + oldTTL = BigInt.fromString(extra.value); + extra.value = newTTL.toString(); + } else { + // else create new extra entity for ttl + extra = createAirExtra(AIR_EXTRA_TTL, newTTL.toString(), extraId); } - // update domain ttl - domain.ttl = newTTL; - domain.lastBlock = block.id; + extra.save(); + // update domain extras + let extrasArray = new Array(); + if (domain.extras == null) { + extrasArray.push(extra.id); + } else { + extrasArray = domain.extras!; + if (extrasArray.indexOf(extra.id) == -1) { + extrasArray.push(extra.id); + } + } + domain.extras = extrasArray; + domain.lastUpdatedBlock = airBlock.id; domain.save(); // create AirDomainNewTTLTransaction - getOrCreateAirDomainNewTTLTransaction( + let txn = getOrCreateAirDomainNewTTLTransaction( transactionHash, block.number, - logIndex, + logOrCallIndex, oldTTL, newTTL, - block, + airBlock, domain, - ) + ); + txn.save(); } /** * @dev This function tracks a new name registered transaction + * @param block ethereum block * @param transactionHash transaction hash - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex event log index - * @param chainId chain id + * @param logOrCallIndex txn log or call index + * @param domainId air domain id * @param registrantAddress registrant address * @param expiryTimestamp domain expiry date * @param cost domain registration cost * @param paymentToken payment token address - * @param labelId label id - * @param rootNode root node byte array + * @param labelName domain label name * @param tokenAddress contract address of nft token */ export function trackNameRegisteredTransaction( + block: ethereum.Block, transactionHash: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - chainId: string, + logOrCallIndex: BigInt, + domainId: string, registrantAddress: string, expiryTimestamp: BigInt, - cost: BigInt, + cost: BigInt | null, paymentToken: string, - labelId: BigInt, - rootNode: ByteArray, + labelName: string | null, tokenAddress: string, ): void { + let chainId = getChainId(); // prep mapping data - let label = uint256ToByteArray(labelId); - let labelName = ens.nameByHash(label.toHexString()); - let domainId = crypto.keccak256(rootNode.concat(label)).toHex(); - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); let domain = getOrCreateAirDomain(new Domain( domainId, chainId, - block, + airBlock, tokenAddress, )); - if (labelName != null) { domain.labelName = labelName } domain.expiryTimestamp = expiryTimestamp; - domain.lastBlock = block.id; - domain.registrationCost = cost; - domain.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; + domain.lastUpdatedBlock = airBlock.id; + if (cost) { + domain.registrationCost = cost; + } + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + domain.paymentToken = airToken.id; domain.save(); // create name registered transaction - getOrCreateAirNameRegisteredTransaction( + let txn = getOrCreateAirNameRegisteredTransaction( chainId, - blockHeight, - blockHash, - blockTimestamp, + block.number, + block.hash.toHexString(), + block.timestamp, transactionHash, - logIndex, + logOrCallIndex, domain, cost, paymentToken, registrantAddress, expiryTimestamp, ); + txn.save(); } /** * @dev This function tracks a name renewal transaction + * @param block ethereum block * @param transactionHash transaction hash - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param chainId chain id - * @param logIndex txn log index + * @param domainId air domain id * @param cost cost of renewal * @param paymentToken payment token address * @param renewer renewer address - * @param labelId label id - * @param rootNode root node byte array * @param expiryTimestamp expiry date * @param tokenAddress token address */ export function trackNameRenewedTransaction( + block: ethereum.Block, transactionHash: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - chainId: string, + domainId: string, cost: BigInt | null, paymentToken: string, renewer: string, - labelId: BigInt, - rootNode: ByteArray, expiryTimestamp: BigInt, tokenAddress: string, ): void { - let label = uint256ToByteArray(labelId); - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domainId = crypto.keccak256(rootNode.concat(label)).toHex(); + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); let domain = getOrCreateAirDomain(new Domain( domainId, chainId, - block, + airBlock, tokenAddress, )); domain.expiryTimestamp = expiryTimestamp; - domain.lastBlock = block.id; + domain.lastUpdatedBlock = airBlock.id; domain.save(); // create name renewed transaction - getOrCreateAirNameRenewedTransaction( + let txn = getOrCreateAirNameRenewedTransaction( transactionHash, chainId, - block, + airBlock, domain, cost, paymentToken, renewer, expiryTimestamp, ); + txn.save(); } /** - * @dev This function tracks set name preimage transaction + * @dev This function tracks trackNameRenewedOrRegistrationByController transaction + * @param block ethereum block + * @param transactionHash transaction hash + * @param domainId air domain id * @param name domain name - * @param label label hash + * @param labelHash label hash * @param cost cost - still needs to be recorded * @param paymentToken payment token address - * @param blockHeight block height - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param chainId chain id - * @param rootNode root node ByteArray - * @param tokenAddress contract address of nft token - * @param transactionHash transaction hash * @param renewer renewer address - can be null * @param expiryTimestamp expiry date - can be null * @param fromRegistrationEvent true if called from a registration event + * @param tokenAddress contract address of nft token */ - export function trackSetNamePreImage( + export function trackNameRenewedOrRegistrationByController( + block: ethereum.Block, + transactionHash: string, + domainId: string, name: string, - label: Bytes, + labelHash: Bytes, cost: BigInt, paymentToken: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - chainId: string, - rootNode: ByteArray, - tokenAddress: string, - transactionHash: string, renewer: string | null, expiryTimestamp: BigInt | null, fromRegistrationEvent: boolean, + tokenAddress: string, ): void { - const labelHash = crypto.keccak256(ByteArray.fromUTF8(name)); - if (!labelHash.equals(label)) { + let chainId = getChainId(); + const calculatedLabelHash = crypto.keccak256(ByteArray.fromUTF8(name)); + if (!calculatedLabelHash.equals(labelHash)) { log.warning( "Expected '{}' to hash to {}, but got {} instead. Skipping.", - [name, labelHash.toHex(), label.toHex()] + [name, calculatedLabelHash.toHex(), labelHash.toHex()] ); return; } @@ -461,189 +412,190 @@ export namespace domain { log.warning("Invalid label '{}'. Skipping.", [name]); return; } - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); let domain = getOrCreateAirDomain(new Domain( - crypto.keccak256(rootNode.concat(label)).toHex(), + domainId, chainId, - block, + airBlock, tokenAddress, )); // tracking registration cost in domain entity - renewal cost is not being tracked yet if (fromRegistrationEvent) { domain.registrationCost = cost; - domain.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; - domain.lastBlock = block.id; + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + domain.paymentToken = airToken.id; } else { // name renewal event // updating renewal cost in name renewed transaction entity - getOrCreateAirNameRenewedTransaction( + domain.expiryTimestamp = expiryTimestamp!; + let txn = getOrCreateAirNameRenewedTransaction( transactionHash, chainId, - block, + airBlock, domain, cost, paymentToken, renewer!, expiryTimestamp!, ); + txn.save(); } if (domain.labelName !== name) { domain.labelName = name domain.name = name + '.eth' - domain.lastBlock = block.id; // creating reverse registrar to get domainId when setting primary domain if (domain.name) { - createReverseRegistrar(domain.name!, domain.id, block); + let reverseRegistrar = createReverseRegistrar(domain.name!, domain.id, airBlock); + reverseRegistrar.save(); } } + domain.lastUpdatedBlock = airBlock.id; domain.save(); //new name registered event } /** - * @dev This function tracks a addr changed transaction - * @param chainId chain id - * @param logIndex event log index - * @param resolverAddress resolver contract address - * @param addr new addr - * @param node domain node - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp + * @dev This function tracks a resolved address changed transaction + * @param block ethereum block * @param transactionHash transaction hash + * @param logOrCallIndex txn log or call index + * @param domainId air domain id + * @param resolverAddress resolver contract address + * @param resolvedAddress resolved address of domain * @param tokenAddress contract address of nft token */ - export function trackAddrChangedTransaction( - chainId: string, - logIndex: BigInt, - resolverAddress: string, - addr: string, - node: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, + export function trackResolvedAddressChangedTransaction( + block: ethereum.Block, transactionHash: string, + logOrCallIndex: BigInt, + domainId: string, + resolverAddress: string, + resolvedAddress: string, tokenAddress: string, ): void { - let addrAccount = getOrCreateAirAccount(chainId, addr); - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let addrAccount = getOrCreateAirAccount(chainId, resolvedAddress, airBlock); + addrAccount.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); let previousResolvedAddressId = domain.resolvedAddress; - let resolver = getOrCreateAirResolver(domain, chainId, resolverAddress, addr); + let resolver = getOrCreateAirResolver(domain, chainId, airBlock, resolverAddress, resolvedAddress); resolver.domain = domain.id; resolver.save() if (domain.resolver == resolver.id) { domain.resolvedAddress = addrAccount.id; - domain.lastBlock = block.id; + domain.lastUpdatedBlock = airBlock.id; domain.save(); } - getOrCreateAirAddrChanged( + let txn = getOrCreateAirResolvedAddressChanged( chainId, - logIndex, + logOrCallIndex, resolver, - block, + airBlock, transactionHash, previousResolvedAddressId, - addr, + resolvedAddress, domain, ); + txn.save(); } /** * @dev This function tracks a resolver version change - * @param chainId chaind id - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param node domain node + * @param block ethereum block + * @param domainId air domain id * @param resolverAddress resolver contract address * @param tokenAddress contract address of nft token */ export function trackResolverVersionChange( - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - node: string, + block: ethereum.Block, + domainId: string, resolverAddress: string, tokenAddress: string, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let resolver = getOrCreateAirResolver(domain, chainId, resolverAddress, null); - if (domain && domain.resolver === resolver.id) { + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); + let resolver = getOrCreateAirResolver(domain, chainId, airBlock, resolverAddress, null); + resolver.save(); + if (domain && domain.resolver == resolver.id) { domain.resolvedAddress = null - domain.lastBlock = block.id; - domain.save(); + domain.lastUpdatedBlock = airBlock.id; } + domain.save(); } /** * @dev This function tracks a set primary domain transaction - * @param ensName ens name - * @param chainId chain id + * @param block ethereum block + * @param transactionHash transaction hash + * @param domainName domain name * @param from event.from address - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp * @param tokenAddress contract address of nft token */ export function trackSetPrimaryDomainTransaction( - ensName: string, - chainId: string, - from: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, + block: ethereum.Block, transactionHash: string, + domainName: string, + from: string, tokenAddress: string, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let reverseRegistrar = getReverseRegistrar(ensName); + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let reverseRegistrar = getReverseRegistrar(domainName); if (reverseRegistrar == null) { - log.warning("Reverse registrar not found for name {} txhash {}", [ensName, transactionHash]); + log.warning("Reverse registrar not found for name {} txhash {}", [domainName, transactionHash]); return; } - log.info("Reverse registrar found for name {} domainId {} txHash {}", [ensName, reverseRegistrar.domain, transactionHash]) - let domain = getOrCreateAirDomain(new Domain(reverseRegistrar.domain, chainId, block, tokenAddress)); - let fromAccount = getOrCreateAirAccount(chainId, from); + log.info("Reverse registrar found for name {} domainId {} txHash {}", [domainName, reverseRegistrar.domain, transactionHash]) + let domain = getOrCreateAirDomain(new Domain(reverseRegistrar.domain, chainId, airBlock, tokenAddress)); + let fromAccount = getOrCreateAirAccount(chainId, from, airBlock); + fromAccount.save(); // when domain's resolvedAddress is set as from address if (domain.resolvedAddress == fromAccount.id) { // get or create primary domain entity - let primaryDomainEntity = getOrCreatePrimaryDomain(domain, fromAccount, block); + let primaryDomainEntity = getOrCreatePrimaryDomain(domain, fromAccount, airBlock); // when primary domain already exists for a resolved address and is not same as new domain if (primaryDomainEntity.domain != domain.id) { log.info("Primary domain already exists for resolvedAddressId {} oldDomain {} newDomain {}", [fromAccount.id, primaryDomainEntity.domain, domain.id]) // unset isPrimary on old domain - let oldPrimaryDomain = getOrCreateAirDomain(new Domain(primaryDomainEntity.domain, chainId, block, tokenAddress)); + let oldPrimaryDomain = getOrCreateAirDomain(new Domain(primaryDomainEntity.domain, chainId, airBlock, tokenAddress)); oldPrimaryDomain.isPrimary = false; - oldPrimaryDomain.lastBlock = block.id; + oldPrimaryDomain.lastUpdatedBlock = airBlock.id; oldPrimaryDomain.save(); // set new primary domain for resolved address primaryDomainEntity.domain = domain.id; - primaryDomainEntity.lastUpdatedAt = block.id; + primaryDomainEntity.lastUpdatedAt = airBlock.id; primaryDomainEntity.save(); } // set isPrimary on new domain domain.isPrimary = true; - domain.lastBlock = block.id; + domain.lastUpdatedBlock = airBlock.id; domain.save(); } // record a set primary domain transaction with new domain - getOrCreateAirPrimaryDomainTransaction( - block, + let txn = getOrCreateAirPrimaryDomainTransaction( + airBlock, transactionHash, domain, from, chainId, - ) + ); + txn.save(); } // end of track functions and start of get or create and helper functions + /** + * @dev this function does not save the returned entity * @dev This function gets or creates a primary domain entity * @param domain air domain * @param fromAccount air account @@ -661,13 +613,13 @@ export namespace domain { entity = new PrimaryDomain(id); entity.domain = domain.id; entity.lastUpdatedAt = block.id; - entity.save(); log.info("Primary domain now for resolvedAddressId {} domain {}", [fromAccount.id, domain.id]) } return entity as PrimaryDomain; } /** + * @dev this function does not save the returned entity * @dev This function gets or creates a air primary domain transaction * @param block air block * @param transactionHash transaction hash @@ -692,16 +644,18 @@ export namespace domain { entity.tokenId = domain.tokenId; entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID, block); - entity.resolvedAddress = getOrCreateAirAccount(chainId, resolvedAddress).id; //make sure to remove the old primary ens if changed - entity.save(); + let resolvedAddressAccount = getOrCreateAirAccount(chainId, resolvedAddress, block); //make sure to remove the old primary ens if changed + resolvedAddressAccount.save(); + entity.resolvedAddress = resolvedAddressAccount.id; } return entity as AirPrimaryDomainTransaction; } /** + * @dev this function does not save the returned entity * @dev This function gets or creates a AirAddrChanged entity * @param chainId chain id - * @param logIndex event log index + * @param logOrCallIndex txn log or index * @param resolver resolver contract address * @param block air block * @param transactionHash transaction hash @@ -710,31 +664,32 @@ export namespace domain { * @param domain domain * @returns AirAddrChanged entity */ - function getOrCreateAirAddrChanged( + function getOrCreateAirResolvedAddressChanged( chainId: string, - logIndex: BigInt, + logOrCallIndex: BigInt, resolver: AirResolver, block: AirBlock, transactionHash: string, previousResolvedAddressId: string | null, newResolvedAddress: string, domain: AirDomain, - ): AirAddrChanged { - let id = createEntityId(transactionHash, block.number, logIndex); - let entity = AirAddrChanged.load(id); + ): AirResolvedAddressChanged { + let id = createEntityId(transactionHash, block.number, logOrCallIndex); + let entity = AirResolvedAddressChanged.load(id); if (entity == null) { - entity = new AirAddrChanged(id); + entity = new AirResolvedAddressChanged(id); entity.resolver = resolver.id; entity.block = block.id; entity.transactionHash = transactionHash; entity.previousResolvedAddress = previousResolvedAddressId; - entity.newResolvedAddress = getOrCreateAirAccount(chainId, newResolvedAddress).id; + let newResolvedAddressAccount = getOrCreateAirAccount(chainId, newResolvedAddress, block); + newResolvedAddressAccount.save(); + entity.newResolvedAddress = newResolvedAddressAccount.id; entity.domain = domain.id; entity.tokenId = domain.tokenId; entity.index = updateAirEntityCounter(AIR_ADDR_CHANGED_ENTITY_COUNTER_ID, block); - entity.save(); } - return entity as AirAddrChanged; + return entity as AirResolvedAddressChanged; } /** @@ -751,35 +706,15 @@ export namespace domain { * @dev this is a generic function to create ids for entities * @param transactionHash transaction hash * @param blockHeight block number in the chain - * @param logIndex txn log index + * @param logOrCallIndex txn log or call index * @returns entity id in string format */ - function createEntityId(transactionHash: string, blockHeight: BigInt, logIndex: BigInt): string { - return transactionHash.concat("-").concat(blockHeight.toString()).concat('-').concat(logIndex.toString()); - } - - /** - * @dev this function creates subnode of the node and returns it as air domain entity id - * @param node takes the node param from the event - * @param label takes the label param from the event - * @returns returns a air domain entity id - */ - function createAirDomainEntityId(node: Bytes, label: Bytes): string { - let subnode = makeSubnode(node, label); - return subnode; - } - - /** - * @dev this function creates subnode of the node and label - * @param node takes the node param from the event - * @param label takes the label param from the event - * @returns returns a subnode in hex string format - */ - function makeSubnode(node: Bytes, label: Bytes): string { - return crypto.keccak256(node.concat(label)).toHexString() + function createEntityId(transactionHash: string, blockHeight: BigInt, logOrCallIndex: BigInt): string { + return transactionHash.concat("-").concat(blockHeight.toString()).concat('-').concat(logOrCallIndex.toString()); } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new AirNameRenewedTransaction entity * @param transactionHash transaction hash * @param chainId chain id @@ -811,30 +746,31 @@ export namespace domain { entity.domain = domain.id; entity.cost = cost; entity.index = updateAirEntityCounter(AIR_NAME_RENEWED_ENTITY_COUNTER_ID, block); - if (paymentToken) { - entity.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; - } - entity.renewer = getOrCreateAirAccount(chainId, renewer).id; + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + entity.paymentToken = airToken.id; + let renewerAccount = getOrCreateAirAccount(chainId, renewer, block); + renewerAccount.save(); + entity.renewer = renewerAccount.id; entity.expiryTimestamp = expiryTimestamp; - entity.save(); } // getting renewal events from 2 contracts, old contract gives cost, new contract gives null, so if old contract event is processed first, then we update the cost // if new contract event is processed first, then we don't update the cost if (cost && !entity.cost) { entity.cost = cost; - entity.save(); } return entity as AirNameRenewedTransaction; } /** + * @dev this function does not save the returned entity * @dev this function gets or creates an AirNameRegisteredTransaction entity * @param chainId chain id * @param blockHeight block height * @param blockHash block hash * @param blockTimestamp block timestamp * @param transactionHash transaction hash - * @param logIndex log index + * @param logOrCallIndex txn log or call index * @param domain air domain * @param cost cost of the transaction * @param paymentToken payment token - can be null @@ -848,15 +784,16 @@ export namespace domain { blockHash: string, blockTimestamp: BigInt, transactionHash: string, - logIndex: BigInt, + logOrCallIndex: BigInt, domain: AirDomain, - cost: BigInt, + cost: BigInt | null, paymentToken: string, registrant: string, expiryTimestamp: BigInt, ): AirNameRegisteredTransaction { let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let id = createEntityId(transactionHash, block.number, logIndex); + block.save(); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirNameRegisteredTransaction.load(id); if (entity == null) { entity = new AirNameRegisteredTransaction(id); @@ -866,27 +803,31 @@ export namespace domain { entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_NAME_REGISTERED_ENTITY_COUNTER_ID, block); entity.cost = cost; - if (paymentToken) { - entity.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; - } - entity.registrant = getOrCreateAirAccount(chainId, registrant).id; + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + entity.paymentToken = airToken.id; + let registrantAccount = getOrCreateAirAccount(chainId, registrant, block); + registrantAccount.save(); + entity.registrant = registrantAccount.id; entity.expiryTimestamp = expiryTimestamp; - entity.save(); } return entity as AirNameRegisteredTransaction; } /** + * @dev this function does not save the returned entity * @dev this function gets or creates an AirResolver entity * @param domain air domain entity * @param chainId chain id + * @param block air block * @param resolver resolver contract address - * @param addr address of addr record or null + * @param resolvedAddress address of resolved address or null * @returns AirResolver entity */ function getOrCreateAirResolver( domain: AirDomain, chainId: string, + block: AirBlock, resolver: string, resolvedAddress: string | null = EMPTY_STRING, ): AirResolver { @@ -894,23 +835,27 @@ export namespace domain { let entity = AirResolver.load(id); if (entity == null) { entity = new AirResolver(id); - entity.address = getOrCreateAirAccount(chainId, resolver).id; + let resolverAccount = getOrCreateAirAccount(chainId, resolver, block); + resolverAccount.save(); + entity.address = resolverAccount.id; entity.domain = domain.id; } if (resolvedAddress && resolvedAddress != EMPTY_STRING) { - entity.resolvedAddress = getOrCreateAirAccount(chainId, resolvedAddress).id; + let resolvedAddressAccount = getOrCreateAirAccount(chainId, resolvedAddress, block); + resolvedAddressAccount.save(); + entity.resolvedAddress = resolvedAddressAccount.id; } else if (resolvedAddress == null) { entity.resolvedAddress = null; } - entity.save(); return entity as AirResolver; } /** + * @dev this function does not save the returned entity * @dev This function gets or creates a new AirDomainNewTTLTransaction entity * @param transactionHash transaction hash * @param blockHeight block number in the chain - * @param logIndex txn log index + * @param logOrCallIndex txn log or call index * @param oldTTL old ttl value - can be null * @param newTTL new ttl value * @param block air block object @@ -920,13 +865,13 @@ export namespace domain { function getOrCreateAirDomainNewTTLTransaction( transactionHash: string, blockHeight: BigInt, - logIndex: BigInt, + logOrCallIndex: BigInt, oldTTL: BigInt | null, newTTL: BigInt, block: AirBlock, domain: AirDomain, ): AirDomainNewTTLTransaction { - let id = createEntityId(transactionHash, blockHeight, logIndex); + let id = createEntityId(transactionHash, blockHeight, logOrCallIndex); let entity = AirDomainNewTTLTransaction.load(id); if (entity == null) { entity = new AirDomainNewTTLTransaction(id); @@ -937,18 +882,18 @@ export namespace domain { entity.tokenId = domain.tokenId; entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER_ID, block); - entity.save(); } return entity as AirDomainNewTTLTransaction; } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new AirDomainNewResolverTransaction entity * @param previousResolverId previous resolver Id - can be null * @param newResolverId new resolver Id * @param block air block entity * @param transactionHash transaction hash - * @param logIndex log index + * @param logOrCallIndex txn log or call index * @param domain air domain entity * @returns AirDomainNewResolverTransaction entity */ @@ -957,10 +902,10 @@ export namespace domain { newResolverId: string, block: AirBlock, transactionHash: string, - logIndex: BigInt, + logOrCallIndex: BigInt, domain: AirDomain, ): AirDomainNewResolverTransaction { - let id = createEntityId(transactionHash, block.number, logIndex); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirDomainNewResolverTransaction.load(id); if (entity == null) { entity = new AirDomainNewResolverTransaction(id); @@ -971,30 +916,12 @@ export namespace domain { entity.tokenId = domain.tokenId; entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID, block); - entity.save(); } return entity as AirDomainNewResolverTransaction; } /** - * @dev this function creates a new DomainVsIsMigratedMapping entity - * @param domaiId air domain entity id - * @param blockId air block entity id - * @param isMigrated is migrated flag - only required when creating a new entity - * @returns DomainVsIsMigratedMapping entity - */ - function getOrCreateIsMigratedMapping(domainId: string, blockId: string, isMigrated: boolean = false): DomainVsIsMigratedMapping { - let entity = DomainVsIsMigratedMapping.load(domainId); - if (entity == null) { - entity = new DomainVsIsMigratedMapping(domainId); - entity.isMigrated = isMigrated; - entity.lastUpdatedAt = blockId; - entity.save(); - } - return entity as DomainVsIsMigratedMapping; - } - - /** + * @dev this function does not save the returned entity * @dev this function creates a new reverse registrar entity if it does not exist * @param name ens name, ex: 'schiller.eth' * @param domainId air domain id @@ -1013,7 +940,6 @@ export namespace domain { entity.name = name; entity.domain = domainId; entity.createdAt = block.id; - entity.save(); } return entity as ReverseRegistrar; } @@ -1031,6 +957,7 @@ export namespace domain { } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new air domain entity * @param domain Domain class object * @returns AirDomain entity @@ -1042,22 +969,36 @@ export namespace domain { if (entity == null) { entity = new AirDomain(domain.id); entity.subdomainCount = BIG_INT_ZERO; - entity.owner = getOrCreateAirAccount(domain.chainId, ZERO_ADDRESS).id; - entity.tokenAddress = getOrCreateAirToken(domain.chainId, domain.tokenAddress).id; + let ownerAccount = getOrCreateAirAccount(domain.chainId, ZERO_ADDRESS, domain.block); + ownerAccount.save(); + entity.owner = ownerAccount.id; + let airToken = getOrCreateAirToken(domain.chainId, domain.tokenAddress); + entity.tokenAddress = airToken.id; entity.isPrimary = false; entity.expiryTimestamp = BIG_INT_ZERO; entity.registrationCost = BIG_INT_ZERO; entity.createdAt = domain.block.id; - entity.lastBlock = domain.block.id; - entity.save(); + entity.lastUpdatedBlock = domain.block.id; } return entity as AirDomain; } /** + * @dev this function gets a air domain entity + * @param domainId air domain entity id + * @returns AirDomain entity - null if entity does not exist + */ + export function getAirDomain( + domainId: string, + ): AirDomain | null { + return AirDomain.load(domainId); + } + + /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new air domain owner changed transaction entity * @param block air block entity - * @param logIndex log index + * @param logOrCallIndex log or call index * @param chainId chain id * @param previousOwnerId previous owner id * @param newOwner new owner address @@ -1068,7 +1009,7 @@ export namespace domain { */ function getOrCreateAirDomainOwnerChangedTransaction( block: AirBlock, - logIndex: BigInt, + logOrCallIndex: BigInt, chainId: string, previousOwnerId: string, newOwner: string, @@ -1076,18 +1017,19 @@ export namespace domain { tokenId: string, domain: AirDomain, ): AirDomainOwnerChangedTransaction { - let id = createEntityId(transactionHash, block.number, logIndex); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirDomainOwnerChangedTransaction.load(id); if (entity == null) { entity = new AirDomainOwnerChangedTransaction(id); entity.previousOwner = previousOwnerId; - entity.newOwner = getOrCreateAirAccount(chainId, newOwner).id; + let newOwnerAccount = getOrCreateAirAccount(chainId, newOwner, block); + newOwnerAccount.save(); + entity.newOwner = newOwnerAccount.id; entity.transactionHash = transactionHash; entity.tokenId = tokenId; entity.domain = domain.id; entity.block = block.id; entity.index = updateAirEntityCounter(AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID, block); - entity.save(); } return entity as AirDomainOwnerChangedTransaction; } @@ -1098,58 +1040,20 @@ export namespace domain { * @param chainId chain id * @param block air block entity * @param tokenAddress contract address of nft token - * @returns air domain entity id */ - function recurseSubdomainCountDecrement(domain: AirDomain, chainId: string, block: AirBlock, tokenAddress: string): string | null { + function recurseSubdomainCountDecrement(domain: AirDomain, chainId: string, block: AirBlock, tokenAddress: string): void { if ((domain.resolver == null || domain.resolver!.split("-")[0] == ZERO_ADDRESS) && - domain.owner == getOrCreateAirAccount(chainId, ZERO_ADDRESS).id && domain.subdomainCount == BIG_INT_ZERO) { + domain.owner == getOrCreateAirAccount(chainId, ZERO_ADDRESS, block).id && domain.subdomainCount == BIG_INT_ZERO) { if (domain.parent) { const parentDomain = getOrCreateAirDomain(new Domain(domain.parent!, chainId, block, tokenAddress)); if (parentDomain) { parentDomain.subdomainCount = parentDomain.subdomainCount.minus(BIGINT_ONE) - parentDomain.lastBlock = block.id; + parentDomain.lastUpdatedBlock = block.id; parentDomain.save(); - return recurseSubdomainCountDecrement(parentDomain, chainId, block, tokenAddress) + recurseSubdomainCountDecrement(parentDomain, chainId, block, tokenAddress) } } - return null - } - return domain.id - } - - /** - * @dev this function gets or creates a new air token entity - * @param chainID chain id - * @param address token address - * @returns AirToken entity - */ - function getOrCreateAirToken(chainID: string, address: string): AirToken { - let entity = AirToken.load(chainID + "-" + address); - if (entity == null) { - entity = new AirToken(chainID + "-" + address); - entity.address = address; - entity.save(); - } - return entity as AirToken; - } - - /** - * @dev this function gets or creates a new air account entity - * @param chainId chain id - * @param address account address - * @returns AirAccount entity - */ - function getOrCreateAirAccount(chainId: string, address: string): AirAccount { - if (address == EMPTY_STRING) { - address = ZERO_ADDRESS; - } - let entity = AirAccount.load(chainId + "-" + address); - if (entity == null) { - entity = new AirAccount(chainId + "-" + address); - entity.address = address; - entity.save(); } - return entity as AirAccount; } /** diff --git a/airstack-modules/modules/airstack/domain-name/utils.ts b/airstack-modules/modules/airstack/domain-name/utils.ts index e2a311a8..e2afbe7a 100644 --- a/airstack-modules/modules/airstack/domain-name/utils.ts +++ b/airstack-modules/modules/airstack/domain-name/utils.ts @@ -1,8 +1,3 @@ -import { - BigInt, - ByteArray, -} from "@graphprotocol/graph-ts"; - export const AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID = "AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER"; export const AIR_DOMAIN_TRANSFER_ENTITY_COUNTER_ID = "AIR_DOMAIN_TRANSFER_ENTITY_COUNTER"; export const AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID = "AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER"; @@ -14,22 +9,7 @@ export const AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID = "AIR_SET_PRIMARY_DOMAIN_ export const AIR_META_ID = "AIR_META"; export const ETHEREUM_MAINNET_ID = "1"; +export const AIR_EXTRA_TTL = 'ttl'; export const ROOT_NODE = '0x0000000000000000000000000000000000000000000000000000000000000000' -export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; - -export function byteArrayFromHex(s: string): ByteArray { - if (s.length % 2 !== 0) { - throw new TypeError("Hex string must have an even number of characters") - } - let out = new Uint8Array(s.length / 2) - for (var i = 0; i < s.length; i += 2) { - out[i / 2] = parseInt(s.substring(i, i + 2), 16) as u32 - } - return changetype(out) -} - -export function uint256ToByteArray(i: BigInt): ByteArray { - let hex = i.toHex().slice(2).padStart(64, '0') - return byteArrayFromHex(hex) -} \ No newline at end of file +export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; \ No newline at end of file diff --git a/airstack-modules/modules/airstack/nft-marketplace/Readme.md b/airstack-modules/modules/airstack/nft-marketplace/Readme.md new file mode 100644 index 00000000..91df5ec7 --- /dev/null +++ b/airstack-modules/modules/airstack/nft-marketplace/Readme.md @@ -0,0 +1,47 @@ +# NFT_MARKET_PLACE vertical integration +### After module integration for NFT_MARKET_PLACE vertical is done. Please call the below functions to track the transactions of the domain name vertical. + +``` +1. Track NFT trade transaction + trackNFTSaleTransactions( + chainID: string, #chain id of the network + txHash: string, #transaction hash + txIndex: BigInt, #transaction index - call or log index + NftSales: Sale[], #array of Sale objects + protocolType: string, #protocol type - SALE + protocolActionType: string, #protocol action type - ["BUY", "SELL"] + timestamp: BigInt, #timestamp of the transaction block + blockHeight: BigInt, #block number of the transaction block + blockHash: string #block hash of the transaction block + ) +``` + +## Class definitions for NFT trade transaction + +``` +class Sale { + buyer: Address, #nft buyer address + seller: Address, #nft seller address + nft: NFT, #NFT class object + paymentAmount: BigInt, #payment amount in wei + paymentToken: Address, #payment token address used for payment amount + protocolFees: BigInt, #protocol fees in wei + protocolFeesBeneficiary: Address, #protocol fees beneficiary address + royalties: CreatorRoyalty[] #array of CreatorRoyalty class objects +} +``` + +``` +class CreatorRoyalty { + fee: BigInt, #royalty fee in wei + beneficiary: Address #royalty beneficiary address +} +``` +``` +class NFT { + collection: Address, #nft collection address + standard: string, #nft standard - ["ERC721", "ERC1155"] + tokenId: BigInt, #nft token id + amount: BigInt #nft amount - 1 for ERC721 and n for ERC1155 +} +``` \ No newline at end of file diff --git a/airstack-modules/modules/airstack/nft-marketplace/nft.ts b/airstack-modules/modules/airstack/nft-marketplace/nft.ts index 92e12006..920e8838 100644 --- a/airstack-modules/modules/airstack/nft-marketplace/nft.ts +++ b/airstack-modules/modules/airstack/nft-marketplace/nft.ts @@ -16,7 +16,7 @@ import { } from "../../../generated/schema"; import { AIR_NFT_SALE_ENTITY_ID } from "./utils"; -import { updateAirEntityCounter, getOrCreateAirBlock } from "../common"; +import { updateAirEntityCounter, getOrCreateAirBlock, getOrCreateAirAccount } from "../common"; export namespace nft { export function trackNFTSaleTransactions( @@ -42,10 +42,12 @@ export namespace nft { let paymentToken = getOrCreateAirToken(chainID, NftSales[i].paymentToken.toHexString()); // Account - let buyerAccount = handleAccountCreation(chainID, NftSales[i].buyer.toHexString(), block.id); - let sellerAccount = handleAccountCreation(chainID, NftSales[i].seller.toHexString(), block.id); - let feeAccount = handleAccountCreation(chainID, NftSales[i].protocolFeesBeneficiary.toHexString(), block.id); - + let buyerAccount = getOrCreateAirAccount(chainID, NftSales[i].buyer.toHexString(), block); + let sellerAccount = getOrCreateAirAccount(chainID, NftSales[i].seller.toHexString(), block); + let feeAccount = getOrCreateAirAccount(chainID, NftSales[i].protocolFeesBeneficiary.toHexString(), block); + buyerAccount.save(); + sellerAccount.save(); + feeAccount.save(); // Sale Token let saleToken = getOrCreateAirToken( chainID, NftSales[i].nft.collection.toHexString() @@ -86,12 +88,12 @@ export namespace nft { // Creator Royalty for (let j = 0; j < NftSales[i].royalties.length; j++) { - let royaltyAccount = handleAccountCreation( + let royaltyAccount = getOrCreateAirAccount( chainID, NftSales[i].royalties[j].beneficiary.toHexString(), - block.id + block ); - + royaltyAccount.save(); let royaltyId = transactionId + "-" + NftSales[i].royalties[j].beneficiary.toHexString(); let royalty = getOrCreateRoyalty(royaltyId); @@ -142,15 +144,6 @@ export namespace nft { return entity as AirToken; } - export function getOrCreateAirAccount(chainID: string, address: string): AirAccount { - let entity = AirAccount.load(chainID + "-" + address); - if (entity == null) { - entity = new AirAccount(chainID + "-" + address); - entity.address = address; - } - return entity as AirAccount; - } - export function getOrCreateAirNftTransaction( id: string ): AirNftTransaction { @@ -202,13 +195,4 @@ export namespace nft { ) { } } - export function handleAccountCreation(chainID: string, address: string, createdAt: string): AirAccount { - let account = AirAccount.load(chainID + "-" + address); - if (account == null) { - account = getOrCreateAirAccount(chainID, address); - account.createdAt = createdAt; - account.save(); - } - return account as AirAccount; - } } \ No newline at end of file diff --git a/airstack-modules/src/integrate.ts b/airstack-modules/src/integrate.ts index 6388d315..b5a8a7b4 100644 --- a/airstack-modules/src/integrate.ts +++ b/airstack-modules/src/integrate.ts @@ -284,9 +284,9 @@ function getAirMetaDetails(vertical: Vertical) { } let targetFile = path.resolve(__dirname, '../../../../../modules/airstack/common/index.ts'); let fileContent = fs.readFileSync(targetFile, { encoding: "utf8" }); - fileContent = fileContent.replace(/export const SUBGRAPH_NAME = ".*";/g, `\nexport const SUBGRAPH_NAME = "${SUBGRAPH_NAME}";`); + fileContent = fileContent.replace(/export const SUBGRAPH_NAME = ".*";/g, `export const SUBGRAPH_NAME = "${SUBGRAPH_NAME}";`); fileContent = fileContent.replace(/export const SUBGRAPH_VERSION = ".*";/g, `export const SUBGRAPH_VERSION = "${SUBGRAPH_VERSION}";`); - fileContent = fileContent.replace(/export const SUBGRAPH_SLUG = ".*";/g, `export const SUBGRAPH_SLUG = "${SUBGRAPH_SLUG}";\n`); + fileContent = fileContent.replace(/export const SUBGRAPH_SLUG = ".*";/g, `export const SUBGRAPH_SLUG = "${SUBGRAPH_SLUG}";`); // fileContent += `\nexport const SUBGRAPH_NAME = "${SUBGRAPH_NAME}";\nexport const SUBGRAPH_VERSION = "${SUBGRAPH_VERSION}";\nexport const SUBGRAPH_SLUG = "${SUBGRAPH_SLUG}";\n` fs.writeFileSync(targetFile, fileContent, { encoding: "utf8" }); } \ No newline at end of file diff --git a/ens/modules/airstack/common/index.ts b/ens/modules/airstack/common/index.ts index 0c729fe9..e00f2888 100644 --- a/ens/modules/airstack/common/index.ts +++ b/ens/modules/airstack/common/index.ts @@ -7,6 +7,9 @@ import { AirBlock, AirEntityCounter, AirMeta, + AirAccount, + AirExtra, + AirToken, } from "../../../generated/schema"; export const AIR_META_ID = "AIR_META"; @@ -17,12 +20,10 @@ export const BIG_INT_ZERO = BigInt.fromI32(0); export const SUBGRAPH_SCHEMA_VERSION = "1.0.0"; - export const SUBGRAPH_NAME = "ens"; export const SUBGRAPH_VERSION = "v1"; export const SUBGRAPH_SLUG = "ens-v1"; - const AIR_NETWORK_MAP = new TypedMap(); AIR_NETWORK_MAP.set("arbitrum-one", "ARBITRUM_ONE"); AIR_NETWORK_MAP.set("arweave-mainnet", "ARWEAVE_MAINNET"); @@ -46,12 +47,42 @@ AIR_NETWORK_MAP.set("osmosis", "OSMOSIS"); AIR_NETWORK_MAP.set("matic", "MATIC"); AIR_NETWORK_MAP.set("xdai", "XDAI"); -export function processNetwork(network: string): string { +const AIR_CHAIN_ID_MAP = new TypedMap(); +AIR_CHAIN_ID_MAP.set("arbitrum-one", "42161"); +AIR_CHAIN_ID_MAP.set("arweave-mainnet", "174"); +AIR_CHAIN_ID_MAP.set("aurora", "1313161554"); +AIR_CHAIN_ID_MAP.set("avalanche", "43114"); +AIR_CHAIN_ID_MAP.set("boba", "288"); +AIR_CHAIN_ID_MAP.set("bsc", "56"); +AIR_CHAIN_ID_MAP.set("celo", "42220"); +AIR_CHAIN_ID_MAP.set("COSMOS", "cosmos"); +AIR_CHAIN_ID_MAP.set("CRONOS", "25"); +AIR_CHAIN_ID_MAP.set("mainnet", "1"); +AIR_CHAIN_ID_MAP.set("fantom", "250"); +AIR_CHAIN_ID_MAP.set("fuse", "122"); +AIR_CHAIN_ID_MAP.set("harmony", "1666600000"); +AIR_CHAIN_ID_MAP.set("juno", "juno-1"); +AIR_CHAIN_ID_MAP.set("moonbeam", "1284"); +AIR_CHAIN_ID_MAP.set("moonriver", "1285"); +AIR_CHAIN_ID_MAP.set("near-mainnet", "1313161554"); +AIR_CHAIN_ID_MAP.set("optimism", "10"); +AIR_CHAIN_ID_MAP.set("osmosis", "osmosis-1"); +AIR_CHAIN_ID_MAP.set("matic", "137"); +AIR_CHAIN_ID_MAP.set("xdai", "100"); + +export function getNetwork(network: string): string { const value = AIR_NETWORK_MAP.get(network); const result: string = value !== null ? value : "unknown"; return result; } +export function getChainId(): string { + let network = dataSource.network(); + const value = AIR_CHAIN_ID_MAP.get(network); + const result: string = value !== null ? value : "unknown"; + return result; +} + //air entity funcitons /** @@ -92,7 +123,7 @@ export function createAirMeta( let meta = AirMeta.load(AIR_META_ID); if (meta == null) { meta = new AirMeta(AIR_META_ID); - meta.network = processNetwork(dataSource.network()); + meta.network = getNetwork(dataSource.network()); meta.schemaVersion = SUBGRAPH_SCHEMA_VERSION; meta.version = SUBGRAPH_VERSION; meta.slug = slug; @@ -102,6 +133,7 @@ export function createAirMeta( } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new air block entity * @param chainId chain id * @param blockHeight block number @@ -123,7 +155,63 @@ export function getOrCreateAirBlock( block.hash = blockHash; block.number = blockHeight; block.timestamp = blockTimestamp - block.save() } return block as AirBlock; +} + +/** + * @dev this function does not save the returned entity + * @dev this function gets or creates a new air account entity + * @param chainId chain id + * @param address account address + * @param block air block object + * @returns AirAccount entity + */ +export function getOrCreateAirAccount(chainId: string, address: string, block: AirBlock): AirAccount { + let id = chainId.concat("-").concat(address); + let entity = AirAccount.load(id); + if (entity == null) { + entity = new AirAccount(id); + entity.address = address; + entity.createdAt = block.id; + } + return entity as AirAccount; +} + +/** + * @dev this function does not save the returned entity + * @dev this function creates an air extra entity + * @param name air extra name + * @param value air extra value + * @param extraId air extra entity id + * @returns air extra entity + */ +export function createAirExtra( + name: string, + value: string, + id: string, +): AirExtra { + let entity = AirExtra.load(id); + if (entity == null) { + entity = new AirExtra(id); + entity.name = name; + entity.value = value; + } + return entity as AirExtra; +} + +/** + * @dev this function does not save the returned entity + * @dev this function gets or creates a new air token entity + * @param chainID chain id + * @param address token address + * @returns AirToken entity + */ +export function getOrCreateAirToken(chainID: string, address: string): AirToken { + let entity = AirToken.load(chainID + "-" + address); + if (entity == null) { + entity = new AirToken(chainID + "-" + address); + entity.address = address; + } + return entity as AirToken; } \ No newline at end of file diff --git a/ens/modules/airstack/domain-name/Readme.md b/ens/modules/airstack/domain-name/Readme.md new file mode 100644 index 00000000..c46caff9 --- /dev/null +++ b/ens/modules/airstack/domain-name/Readme.md @@ -0,0 +1,126 @@ +# DOMAIN_NAME vertical integration +### After module integration for DOMAIN_NAME vertical is done. Please call the below functions to track the transactions of the domain name vertical. +``` +1. Track transaction when a domain owner is changed + trackDomainOwnerChangedTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + parentDomainId: string, #air domain entity id for parent domain - needs to be unique for each domain + tokenId: string, #ERC721 token id - keccack256(labelHash) - needs to be unique for each token + labelHash: string, #hex value of a label + labelName: string | null, #label name - eg: 'airswap' in airswap.eth + name: string | null, #domain name - eg: 'airswap.eth' + newOwner: string, #new owner address + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +2. Track transaction when a domain is transferred + trackDomainTransferTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + newOwnerAddress: string, #address to which the domain is transferred + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +3. Track transaction when a domain resolver is changed + trackDomainNewResolverTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + resolver: string, #new resolver address linked to the domain + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +4. Track transaction when a domain TTL is changed + trackDomainNewTTLTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + newTTL: BigInt, #new TTL value for the domain + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +5. Track transaction when a domain is registered + trackNameRegisteredTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + registrantAddress: string, #address which registered the domain + expiryTimestamp: BigInt, #unix time at which domain expires + cost: BigInt, #cost of domain registration in wei + paymentToken: string, #address of token used for registration cost + labelName: string | null, #label name - eg: 'airswap' in airswap.eth + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +6. Track transaction when a domain is renewed + trackNameRenewedTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + domainId: string, #air domain entity id - needs to be unique for each domain + cost: BigInt | null, #cost of domain renewal in wei + paymentToken: string, #address of token used for renewal cost + renewer: string, #address which renewed the domain + expiryTimestamp: BigInt, #unix time at which domain expires + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +7. Track controller transaction when a domain is renewed or registered + trackNameRenewedOrRegistrationByController( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + domainId: string, #air domain entity id - needs to be unique for each domain + name: string, #domain name - eg: 'airswap.eth' + label: Bytes, #hex value of a label + cost: BigInt, #cost of domain registration or renewal in wei + paymentToken: string, #address of token used for registration or renewal cost + renewer: string | null, #address which renewed the domain + expiryTimestamp: BigInt | null, #unix time at which domain expires + fromRegistrationEvent: boolean, #true if the transaction is from a registration event + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +8. Track transaction when a domain's resolved address is changed + trackResolvedAddressChangedTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + logOrCallIndex: BigInt, #log or call index - used to differentiate between multiple logs or calls in a single transaction + domainId: string, #air domain entity id - needs to be unique for each domain + resolverAddress: string, #address of the resolver contract + resolvedAddress: string, #address which the domain resolves to + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +9. Track transaction when a domain's resolver version is changed + trackResolverVersionChange( + block: ethereum.Block, #ethereum block object in subgraph + domainId: string, #air domain entity id - needs to be unique for each domain + resolverAddress: string, #address of the resolver contract + tokenAddress: string, #token address for ERC721 token + ) +``` +``` +10. Track transaction when an resolved address's primary domain is changed + trackSetPrimaryDomainTransaction( + block: ethereum.Block, #ethereum block object in subgraph + transactionHash: string, #transaction hash + domainName: string, #domain name - eg: 'airswap.eth' + from: string, #address which changed its primary domain to the domainName + tokenAddress: string, #token address for ERC721 token + ) +``` \ No newline at end of file diff --git a/ens/modules/airstack/domain-name/domain-name.ts b/ens/modules/airstack/domain-name/domain-name.ts index 71f1f52b..4567b951 100644 --- a/ens/modules/airstack/domain-name/domain-name.ts +++ b/ens/modules/airstack/domain-name/domain-name.ts @@ -5,6 +5,7 @@ import { log, ByteArray, ens, + ethereum, } from "@graphprotocol/graph-ts"; import { @@ -19,99 +20,74 @@ import { AirDomainNewTTLTransaction, AirNameRegisteredTransaction, AirNameRenewedTransaction, - AirAddrChanged, + AirResolvedAddressChanged, AirPrimaryDomainTransaction, ReverseRegistrar, PrimaryDomain, - DomainVsIsMigratedMapping, + AirExtra, } from "../../../generated/schema"; -import { uint256ToByteArray, AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID, AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID, AIR_ADDR_CHANGED_ENTITY_COUNTER_ID, AIR_NAME_RENEWED_ENTITY_COUNTER_ID, AIR_NAME_REGISTERED_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID, AIR_DOMAIN_TRANSFER_ENTITY_COUNTER_ID, ROOT_NODE, ZERO_ADDRESS, ETHEREUM_MAINNET_ID } from "./utils"; -import { BIGINT_ONE, BIG_INT_ZERO, EMPTY_STRING, updateAirEntityCounter, getOrCreateAirBlock } from "../common"; +import { AIR_EXTRA_TTL, AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID, AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID, AIR_ADDR_CHANGED_ENTITY_COUNTER_ID, AIR_NAME_RENEWED_ENTITY_COUNTER_ID, AIR_NAME_REGISTERED_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER_ID, AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID, AIR_DOMAIN_TRANSFER_ENTITY_COUNTER_ID, ZERO_ADDRESS, ETHEREUM_MAINNET_ID } from "./utils"; +import { BIGINT_ONE, BIG_INT_ZERO, EMPTY_STRING, getChainId, updateAirEntityCounter, getOrCreateAirBlock, getOrCreateAirAccount, createAirExtra, getOrCreateAirToken } from "../common"; export namespace domain { /** * @dev This function tracks a domain owner change transaction - * @param blockHeight block number in the chain - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex txn log index - * @param chainId chain id - * @param newOwner specifies the new owner of the domain + * @param block ethreum block * @param transactionHash transaction hash - * @param isMigrated specifies if the domain is migrated - * @param node specifies the node of the domain - * @param label specifies the label of the domain + * @param logOrCallIndex txn log or call index + * @param domainId domain id + * @param parentDomainId specifies the parentDomainId + * @param tokenId token id + * @param labelHash specifies the label hash + * @param labelName label name + * @param name domain name + * @param newOwner specifies the new owner of the domain * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry - */ + */ export function trackDomainOwnerChangedTransaction( - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - chainId: string, - newOwner: string, + block: ethereum.Block, transactionHash: string, - isMigrated: boolean, - node: Bytes, - label: Bytes, + logOrCallIndex: BigInt, + domainId: string, + parentDomainId: string, + tokenId: string, + labelHash: string, + labelName: string | null, + name: string | null, + newOwner: string, tokenAddress: string, - fromOldRegistry: boolean, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domainId = createAirDomainEntityId(node, label); - let domain = getOrCreateAirDomain(new Domain(domainId, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domainId, block.id, isMigrated); - if (fromOldRegistry && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); let previousOwnerId = domain.owner; - let parent = getOrCreateAirDomain(new Domain( - node.toHexString(), + let parentDomain = getOrCreateAirDomain(new Domain( + parentDomainId, chainId, - block, + airBlock, tokenAddress, )); - if (domain.parent == null && parent != null) { - parent.subdomainCount = parent.subdomainCount.plus(BIGINT_ONE); - } - if (domain.name == null) { - let labelName = ens.nameByHash(label.toHexString()); - if (labelName != null) { - domain.labelName = labelName; - } - if (labelName === null) { - labelName = '[' + label.toHexString().slice(2) + ']'; - } - if (node.toHexString() == ROOT_NODE) { - domain.name = labelName; - } else { - let name = parent.name; - if (labelName && name) { - domain.name = labelName + '.' + name; - } - } + if (domain.parent == null) { + parentDomain.subdomainCount = parentDomain.subdomainCount.plus(BIGINT_ONE); + parentDomain.lastUpdatedBlock = airBlock.id; } - - let tokenId = BigInt.fromUnsignedBytes(label).toString(); - domain.owner = getOrCreateAirAccount(chainId, newOwner).id; - domain.parent = parent.id; - domain.labelHash = label; + domain.name = name; + domain.labelName = labelName; + let ownerAccount = getOrCreateAirAccount(chainId, newOwner, airBlock); + ownerAccount.save(); + domain.owner = ownerAccount.id; + domain.parent = parentDomain.id; + domain.labelHash = labelHash; domain.tokenId = tokenId; - domain.lastBlock = block.id; - recurseSubdomainCountDecrement(domain, chainId, block, tokenAddress); + domain.lastUpdatedBlock = airBlock.id; + parentDomain.save(); domain.save(); + recurseSubdomainCountDecrement(domain, chainId, airBlock, tokenAddress); - // creating reverse registrar to get domainId when setting primary domain - if (domain.name) { - createReverseRegistrar(domain.name!, domain.id, block); - } - // creating is migrated mapping - getOrCreateIsMigratedMapping(domainId, block.id, isMigrated); - getOrCreateAirDomainOwnerChangedTransaction( - block, - logIndex, + let txn = getOrCreateAirDomainOwnerChangedTransaction( + airBlock, + logOrCallIndex, chainId, previousOwnerId, newOwner, @@ -119,56 +95,48 @@ export namespace domain { tokenId, domain, ); + txn.save(); } /** - * @dev This function tracks a domain transfer transaction - * @param node specifies the node of the domain - * @param chainId chain id - * @param newOwnerAddress specifies the new owner of the domain - * @param blockHeight block number in the chain - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex txn log index - * @param transactionHash transaction hash - * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry + * @dev This function tracks a domain transfer transaction + * @param block ethereum block + * @param transactionHash transaction hash + * @param logOrCallIndex txn log or call index + * @param domainId domain id + * @param newOwnerAddress specifies the new owner of the domain + * @param tokenAddress contract address of nft token */ export function trackDomainTransferTransaction( - node: string, - chainId: string, - newOwnerAddress: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, + block: ethereum.Block, transactionHash: string, + logOrCallIndex: BigInt, + domainId: string, + newOwnerAddress: string, tokenAddress: string, - fromOldRegistry: boolean, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domain.id, block.id); - if (fromOldRegistry && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); let previousOwnerId = domain.owner; if (previousOwnerId == null) { - previousOwnerId = getOrCreateAirAccount(chainId, ZERO_ADDRESS).id; + let previousOwnerAccount = getOrCreateAirAccount(chainId, ZERO_ADDRESS, airBlock); + previousOwnerAccount.save(); + previousOwnerId = previousOwnerAccount.id; } - let id = createEntityId(transactionHash, blockHeight, logIndex); + // update domain owner here + let newOwnerAccount = getOrCreateAirAccount(chainId, newOwnerAddress, airBlock); + newOwnerAccount.save(); + domain.owner = newOwnerAccount.id; + domain.lastUpdatedBlock = airBlock.id; + domain.save(); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirDomainTransferTransaction.load(id); if (entity == null) { entity = new AirDomainTransferTransaction(id); entity.from = previousOwnerId; - entity.to = getOrCreateAirAccount(chainId, newOwnerAddress).id; - let airBlock = getOrCreateAirBlock( - chainId, - blockHeight, - blockHash, - blockTimestamp, - ); + entity.to = newOwnerAccount.id; entity.block = airBlock.id; entity.transactionHash = transactionHash; entity.tokenId = domain.tokenId; @@ -180,42 +148,32 @@ export namespace domain { /** * @dev This function tracks a new resolver transaction - * @param resolver resolver contract address - * @param node domain node - * @param chainId chain id - * @param blockHeight block number in the chain - * @param blockHash block hash - * @param blockTimestamp block timestamp + * @param block ethereum block * @param transactionHash transaction hash - * @param logIndex event log index + * @param logOrCallIndex txn log or call index + * @param domainId air domain id + * @param resolver resolver contract address * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry */ export function trackDomainNewResolverTransaction( - resolver: string, - node: string, - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, + block: ethereum.Block, transactionHash: string, - logIndex: BigInt, + logOrCallIndex: BigInt, + domainId: string, + resolver: string, tokenAddress: string, - fromOldRegistry: boolean, ): void { + let chainId = getChainId(); // get block - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); // get domain - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domain.id, block.id); - if (fromOldRegistry && node != ROOT_NODE && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); // get previous resolver let previousResolverId = domain.resolver; // create new resolver - let resolverEntity = getOrCreateAirResolver(domain, chainId, resolver); + let resolverEntity = getOrCreateAirResolver(domain, chainId, airBlock, resolver); + resolverEntity.save(); // update domain resolver domain.resolver = resolverEntity.id; // update domain resolved address @@ -223,236 +181,229 @@ export namespace domain { domain.resolvedAddress = resolverEntity.resolvedAddress; } // do recursive subdomain count decrement - domain.lastBlock = block.id; - recurseSubdomainCountDecrement(domain, chainId, block, tokenAddress); + domain.lastUpdatedBlock = airBlock.id; domain.save(); + recurseSubdomainCountDecrement(domain, chainId, airBlock, tokenAddress); // create new resolver transaction - getOrCreateAirDomainNewResolverTransaction( + let tnx = getOrCreateAirDomainNewResolverTransaction( previousResolverId, resolverEntity.address, - block, + airBlock, transactionHash, - logIndex, + logOrCallIndex, domain, - ) + ); + tnx.save(); } /** * @dev This function tracks a new TTL transaction - * @param node domain node - * @param newTTL new TTL - * @param chainId chain id - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex event log index + * @param block ethereum block * @param transactionHash transaction hash + * @param logOrCallIndex txn log or call index + * @param domainId air domain id + * @param newTTL new TTL * @param tokenAddress contract address of nft token - * @param fromOldRegistry specifies if the event is from the old registry */ export function trackDomainNewTTLTransaction( - node: string, - newTTL: BigInt, - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, + block: ethereum.Block, transactionHash: string, + logOrCallIndex: BigInt, + domainId: string, + newTTL: BigInt, tokenAddress: string, - fromOldRegistry: boolean, ): void { + let chainId = getChainId(); // get block - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); // get domain - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let isMigratedMapping = getOrCreateIsMigratedMapping(domain.id, block.id); - if (fromOldRegistry && isMigratedMapping.isMigrated == true) { - // this domain was migrated from the old registry, so we don't need to hanlde old registry event now - return; - } + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); // get previous ttl let oldTTL: BigInt | null = null; - if (domain.ttl) { - oldTTL = domain.ttl; + // load extra entity for ttl + let extraId = domainId.concat("-").concat(AIR_EXTRA_TTL); + let extra = AirExtra.load(extraId); + if (extra != null) { + // if exists, assign oldTTL and update value with newTTL + oldTTL = BigInt.fromString(extra.value); + extra.value = newTTL.toString(); + } else { + // else create new extra entity for ttl + extra = createAirExtra(AIR_EXTRA_TTL, newTTL.toString(), extraId); } - // update domain ttl - domain.ttl = newTTL; - domain.lastBlock = block.id; + extra.save(); + // update domain extras + let extrasArray = new Array(); + if (domain.extras == null) { + extrasArray.push(extra.id); + } else { + extrasArray = domain.extras!; + if (extrasArray.indexOf(extra.id) == -1) { + extrasArray.push(extra.id); + } + } + domain.extras = extrasArray; + domain.lastUpdatedBlock = airBlock.id; domain.save(); // create AirDomainNewTTLTransaction - getOrCreateAirDomainNewTTLTransaction( + let txn = getOrCreateAirDomainNewTTLTransaction( transactionHash, block.number, - logIndex, + logOrCallIndex, oldTTL, newTTL, - block, + airBlock, domain, - ) + ); + txn.save(); } /** * @dev This function tracks a new name registered transaction + * @param block ethereum block * @param transactionHash transaction hash - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param logIndex event log index - * @param chainId chain id + * @param logOrCallIndex txn log or call index + * @param domainId air domain id * @param registrantAddress registrant address * @param expiryTimestamp domain expiry date * @param cost domain registration cost * @param paymentToken payment token address - * @param labelId label id - * @param rootNode root node byte array + * @param labelName domain label name * @param tokenAddress contract address of nft token */ export function trackNameRegisteredTransaction( + block: ethereum.Block, transactionHash: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - logIndex: BigInt, - chainId: string, + logOrCallIndex: BigInt, + domainId: string, registrantAddress: string, expiryTimestamp: BigInt, - cost: BigInt, + cost: BigInt | null, paymentToken: string, - labelId: BigInt, - rootNode: ByteArray, + labelName: string | null, tokenAddress: string, ): void { + let chainId = getChainId(); // prep mapping data - let label = uint256ToByteArray(labelId); - let labelName = ens.nameByHash(label.toHexString()); - let domainId = crypto.keccak256(rootNode.concat(label)).toHex(); - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); let domain = getOrCreateAirDomain(new Domain( domainId, chainId, - block, + airBlock, tokenAddress, )); - if (labelName != null) { domain.labelName = labelName } domain.expiryTimestamp = expiryTimestamp; - domain.lastBlock = block.id; - domain.registrationCost = cost; - domain.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; + domain.lastUpdatedBlock = airBlock.id; + if (cost) { + domain.registrationCost = cost; + } + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + domain.paymentToken = airToken.id; domain.save(); // create name registered transaction - getOrCreateAirNameRegisteredTransaction( + let txn = getOrCreateAirNameRegisteredTransaction( chainId, - blockHeight, - blockHash, - blockTimestamp, + block.number, + block.hash.toHexString(), + block.timestamp, transactionHash, - logIndex, + logOrCallIndex, domain, cost, paymentToken, registrantAddress, expiryTimestamp, ); + txn.save(); } /** * @dev This function tracks a name renewal transaction + * @param block ethereum block * @param transactionHash transaction hash - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param chainId chain id - * @param logIndex txn log index + * @param domainId air domain id * @param cost cost of renewal * @param paymentToken payment token address * @param renewer renewer address - * @param labelId label id - * @param rootNode root node byte array * @param expiryTimestamp expiry date * @param tokenAddress token address */ export function trackNameRenewedTransaction( + block: ethereum.Block, transactionHash: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - chainId: string, + domainId: string, cost: BigInt | null, paymentToken: string, renewer: string, - labelId: BigInt, - rootNode: ByteArray, expiryTimestamp: BigInt, tokenAddress: string, ): void { - let label = uint256ToByteArray(labelId); - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domainId = crypto.keccak256(rootNode.concat(label)).toHex(); + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); let domain = getOrCreateAirDomain(new Domain( domainId, chainId, - block, + airBlock, tokenAddress, )); domain.expiryTimestamp = expiryTimestamp; - domain.lastBlock = block.id; + domain.lastUpdatedBlock = airBlock.id; domain.save(); // create name renewed transaction - getOrCreateAirNameRenewedTransaction( + let txn = getOrCreateAirNameRenewedTransaction( transactionHash, chainId, - block, + airBlock, domain, cost, paymentToken, renewer, expiryTimestamp, ); + txn.save(); } /** - * @dev This function tracks set name preimage transaction + * @dev This function tracks trackNameRenewedOrRegistrationByController transaction + * @param block ethereum block + * @param transactionHash transaction hash + * @param domainId air domain id * @param name domain name - * @param label label hash + * @param labelHash label hash * @param cost cost - still needs to be recorded * @param paymentToken payment token address - * @param blockHeight block height - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param chainId chain id - * @param rootNode root node ByteArray - * @param tokenAddress contract address of nft token - * @param transactionHash transaction hash * @param renewer renewer address - can be null * @param expiryTimestamp expiry date - can be null * @param fromRegistrationEvent true if called from a registration event + * @param tokenAddress contract address of nft token */ - export function trackSetNamePreImage( + export function trackNameRenewedOrRegistrationByController( + block: ethereum.Block, + transactionHash: string, + domainId: string, name: string, - label: Bytes, + labelHash: Bytes, cost: BigInt, paymentToken: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - chainId: string, - rootNode: ByteArray, - tokenAddress: string, - transactionHash: string, renewer: string | null, expiryTimestamp: BigInt | null, fromRegistrationEvent: boolean, + tokenAddress: string, ): void { - const labelHash = crypto.keccak256(ByteArray.fromUTF8(name)); - if (!labelHash.equals(label)) { + let chainId = getChainId(); + const calculatedLabelHash = crypto.keccak256(ByteArray.fromUTF8(name)); + if (!calculatedLabelHash.equals(labelHash)) { log.warning( "Expected '{}' to hash to {}, but got {} instead. Skipping.", - [name, labelHash.toHex(), label.toHex()] + [name, calculatedLabelHash.toHex(), labelHash.toHex()] ); return; } @@ -461,189 +412,190 @@ export namespace domain { log.warning("Invalid label '{}'. Skipping.", [name]); return; } - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); let domain = getOrCreateAirDomain(new Domain( - crypto.keccak256(rootNode.concat(label)).toHex(), + domainId, chainId, - block, + airBlock, tokenAddress, )); // tracking registration cost in domain entity - renewal cost is not being tracked yet if (fromRegistrationEvent) { domain.registrationCost = cost; - domain.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; - domain.lastBlock = block.id; + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + domain.paymentToken = airToken.id; } else { // name renewal event // updating renewal cost in name renewed transaction entity - getOrCreateAirNameRenewedTransaction( + domain.expiryTimestamp = expiryTimestamp!; + let txn = getOrCreateAirNameRenewedTransaction( transactionHash, chainId, - block, + airBlock, domain, cost, paymentToken, renewer!, expiryTimestamp!, ); + txn.save(); } if (domain.labelName !== name) { domain.labelName = name domain.name = name + '.eth' - domain.lastBlock = block.id; // creating reverse registrar to get domainId when setting primary domain if (domain.name) { - createReverseRegistrar(domain.name!, domain.id, block); + let reverseRegistrar = createReverseRegistrar(domain.name!, domain.id, airBlock); + reverseRegistrar.save(); } } + domain.lastUpdatedBlock = airBlock.id; domain.save(); //new name registered event } /** - * @dev This function tracks a addr changed transaction - * @param chainId chain id - * @param logIndex event log index - * @param resolverAddress resolver contract address - * @param addr new addr - * @param node domain node - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp + * @dev This function tracks a resolved address changed transaction + * @param block ethereum block * @param transactionHash transaction hash + * @param logOrCallIndex txn log or call index + * @param domainId air domain id + * @param resolverAddress resolver contract address + * @param resolvedAddress resolved address of domain * @param tokenAddress contract address of nft token */ - export function trackAddrChangedTransaction( - chainId: string, - logIndex: BigInt, - resolverAddress: string, - addr: string, - node: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, + export function trackResolvedAddressChangedTransaction( + block: ethereum.Block, transactionHash: string, + logOrCallIndex: BigInt, + domainId: string, + resolverAddress: string, + resolvedAddress: string, tokenAddress: string, ): void { - let addrAccount = getOrCreateAirAccount(chainId, addr); - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let addrAccount = getOrCreateAirAccount(chainId, resolvedAddress, airBlock); + addrAccount.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); let previousResolvedAddressId = domain.resolvedAddress; - let resolver = getOrCreateAirResolver(domain, chainId, resolverAddress, addr); + let resolver = getOrCreateAirResolver(domain, chainId, airBlock, resolverAddress, resolvedAddress); resolver.domain = domain.id; resolver.save() if (domain.resolver == resolver.id) { domain.resolvedAddress = addrAccount.id; - domain.lastBlock = block.id; + domain.lastUpdatedBlock = airBlock.id; domain.save(); } - getOrCreateAirAddrChanged( + let txn = getOrCreateAirResolvedAddressChanged( chainId, - logIndex, + logOrCallIndex, resolver, - block, + airBlock, transactionHash, previousResolvedAddressId, - addr, + resolvedAddress, domain, ); + txn.save(); } /** * @dev This function tracks a resolver version change - * @param chainId chaind id - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp - * @param node domain node + * @param block ethereum block + * @param domainId air domain id * @param resolverAddress resolver contract address * @param tokenAddress contract address of nft token */ export function trackResolverVersionChange( - chainId: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, - node: string, + block: ethereum.Block, + domainId: string, resolverAddress: string, tokenAddress: string, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let domain = getOrCreateAirDomain(new Domain(node, chainId, block, tokenAddress)); - let resolver = getOrCreateAirResolver(domain, chainId, resolverAddress, null); - if (domain && domain.resolver === resolver.id) { + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let domain = getOrCreateAirDomain(new Domain(domainId, chainId, airBlock, tokenAddress)); + let resolver = getOrCreateAirResolver(domain, chainId, airBlock, resolverAddress, null); + resolver.save(); + if (domain && domain.resolver == resolver.id) { domain.resolvedAddress = null - domain.lastBlock = block.id; - domain.save(); + domain.lastUpdatedBlock = airBlock.id; } + domain.save(); } /** * @dev This function tracks a set primary domain transaction - * @param ensName ens name - * @param chainId chain id + * @param block ethereum block + * @param transactionHash transaction hash + * @param domainName domain name * @param from event.from address - * @param blockHeight block number - * @param blockHash block hash - * @param blockTimestamp block timestamp * @param tokenAddress contract address of nft token */ export function trackSetPrimaryDomainTransaction( - ensName: string, - chainId: string, - from: string, - blockHeight: BigInt, - blockHash: string, - blockTimestamp: BigInt, + block: ethereum.Block, transactionHash: string, + domainName: string, + from: string, tokenAddress: string, ): void { - let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let reverseRegistrar = getReverseRegistrar(ensName); + let chainId = getChainId(); + let airBlock = getOrCreateAirBlock(chainId, block.number, block.hash.toHexString(), block.timestamp); + airBlock.save(); + let reverseRegistrar = getReverseRegistrar(domainName); if (reverseRegistrar == null) { - log.warning("Reverse registrar not found for name {} txhash {}", [ensName, transactionHash]); + log.warning("Reverse registrar not found for name {} txhash {}", [domainName, transactionHash]); return; } - log.info("Reverse registrar found for name {} domainId {} txHash {}", [ensName, reverseRegistrar.domain, transactionHash]) - let domain = getOrCreateAirDomain(new Domain(reverseRegistrar.domain, chainId, block, tokenAddress)); - let fromAccount = getOrCreateAirAccount(chainId, from); + log.info("Reverse registrar found for name {} domainId {} txHash {}", [domainName, reverseRegistrar.domain, transactionHash]) + let domain = getOrCreateAirDomain(new Domain(reverseRegistrar.domain, chainId, airBlock, tokenAddress)); + let fromAccount = getOrCreateAirAccount(chainId, from, airBlock); + fromAccount.save(); // when domain's resolvedAddress is set as from address if (domain.resolvedAddress == fromAccount.id) { // get or create primary domain entity - let primaryDomainEntity = getOrCreatePrimaryDomain(domain, fromAccount, block); + let primaryDomainEntity = getOrCreatePrimaryDomain(domain, fromAccount, airBlock); // when primary domain already exists for a resolved address and is not same as new domain if (primaryDomainEntity.domain != domain.id) { log.info("Primary domain already exists for resolvedAddressId {} oldDomain {} newDomain {}", [fromAccount.id, primaryDomainEntity.domain, domain.id]) // unset isPrimary on old domain - let oldPrimaryDomain = getOrCreateAirDomain(new Domain(primaryDomainEntity.domain, chainId, block, tokenAddress)); + let oldPrimaryDomain = getOrCreateAirDomain(new Domain(primaryDomainEntity.domain, chainId, airBlock, tokenAddress)); oldPrimaryDomain.isPrimary = false; - oldPrimaryDomain.lastBlock = block.id; + oldPrimaryDomain.lastUpdatedBlock = airBlock.id; oldPrimaryDomain.save(); // set new primary domain for resolved address primaryDomainEntity.domain = domain.id; - primaryDomainEntity.lastUpdatedAt = block.id; + primaryDomainEntity.lastUpdatedAt = airBlock.id; primaryDomainEntity.save(); } // set isPrimary on new domain domain.isPrimary = true; - domain.lastBlock = block.id; + domain.lastUpdatedBlock = airBlock.id; domain.save(); } // record a set primary domain transaction with new domain - getOrCreateAirPrimaryDomainTransaction( - block, + let txn = getOrCreateAirPrimaryDomainTransaction( + airBlock, transactionHash, domain, from, chainId, - ) + ); + txn.save(); } // end of track functions and start of get or create and helper functions + /** + * @dev this function does not save the returned entity * @dev This function gets or creates a primary domain entity * @param domain air domain * @param fromAccount air account @@ -661,13 +613,13 @@ export namespace domain { entity = new PrimaryDomain(id); entity.domain = domain.id; entity.lastUpdatedAt = block.id; - entity.save(); log.info("Primary domain now for resolvedAddressId {} domain {}", [fromAccount.id, domain.id]) } return entity as PrimaryDomain; } /** + * @dev this function does not save the returned entity * @dev This function gets or creates a air primary domain transaction * @param block air block * @param transactionHash transaction hash @@ -692,16 +644,18 @@ export namespace domain { entity.tokenId = domain.tokenId; entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID, block); - entity.resolvedAddress = getOrCreateAirAccount(chainId, resolvedAddress).id; //make sure to remove the old primary ens if changed - entity.save(); + let resolvedAddressAccount = getOrCreateAirAccount(chainId, resolvedAddress, block); //make sure to remove the old primary ens if changed + resolvedAddressAccount.save(); + entity.resolvedAddress = resolvedAddressAccount.id; } return entity as AirPrimaryDomainTransaction; } /** + * @dev this function does not save the returned entity * @dev This function gets or creates a AirAddrChanged entity * @param chainId chain id - * @param logIndex event log index + * @param logOrCallIndex txn log or index * @param resolver resolver contract address * @param block air block * @param transactionHash transaction hash @@ -710,31 +664,32 @@ export namespace domain { * @param domain domain * @returns AirAddrChanged entity */ - function getOrCreateAirAddrChanged( + function getOrCreateAirResolvedAddressChanged( chainId: string, - logIndex: BigInt, + logOrCallIndex: BigInt, resolver: AirResolver, block: AirBlock, transactionHash: string, previousResolvedAddressId: string | null, newResolvedAddress: string, domain: AirDomain, - ): AirAddrChanged { - let id = createEntityId(transactionHash, block.number, logIndex); - let entity = AirAddrChanged.load(id); + ): AirResolvedAddressChanged { + let id = createEntityId(transactionHash, block.number, logOrCallIndex); + let entity = AirResolvedAddressChanged.load(id); if (entity == null) { - entity = new AirAddrChanged(id); + entity = new AirResolvedAddressChanged(id); entity.resolver = resolver.id; entity.block = block.id; entity.transactionHash = transactionHash; entity.previousResolvedAddress = previousResolvedAddressId; - entity.newResolvedAddress = getOrCreateAirAccount(chainId, newResolvedAddress).id; + let newResolvedAddressAccount = getOrCreateAirAccount(chainId, newResolvedAddress, block); + newResolvedAddressAccount.save(); + entity.newResolvedAddress = newResolvedAddressAccount.id; entity.domain = domain.id; entity.tokenId = domain.tokenId; entity.index = updateAirEntityCounter(AIR_ADDR_CHANGED_ENTITY_COUNTER_ID, block); - entity.save(); } - return entity as AirAddrChanged; + return entity as AirResolvedAddressChanged; } /** @@ -751,35 +706,15 @@ export namespace domain { * @dev this is a generic function to create ids for entities * @param transactionHash transaction hash * @param blockHeight block number in the chain - * @param logIndex txn log index + * @param logOrCallIndex txn log or call index * @returns entity id in string format */ - function createEntityId(transactionHash: string, blockHeight: BigInt, logIndex: BigInt): string { - return transactionHash.concat("-").concat(blockHeight.toString()).concat('-').concat(logIndex.toString()); - } - - /** - * @dev this function creates subnode of the node and returns it as air domain entity id - * @param node takes the node param from the event - * @param label takes the label param from the event - * @returns returns a air domain entity id - */ - function createAirDomainEntityId(node: Bytes, label: Bytes): string { - let subnode = makeSubnode(node, label); - return subnode; - } - - /** - * @dev this function creates subnode of the node and label - * @param node takes the node param from the event - * @param label takes the label param from the event - * @returns returns a subnode in hex string format - */ - function makeSubnode(node: Bytes, label: Bytes): string { - return crypto.keccak256(node.concat(label)).toHexString() + function createEntityId(transactionHash: string, blockHeight: BigInt, logOrCallIndex: BigInt): string { + return transactionHash.concat("-").concat(blockHeight.toString()).concat('-').concat(logOrCallIndex.toString()); } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new AirNameRenewedTransaction entity * @param transactionHash transaction hash * @param chainId chain id @@ -811,30 +746,31 @@ export namespace domain { entity.domain = domain.id; entity.cost = cost; entity.index = updateAirEntityCounter(AIR_NAME_RENEWED_ENTITY_COUNTER_ID, block); - if (paymentToken) { - entity.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; - } - entity.renewer = getOrCreateAirAccount(chainId, renewer).id; + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + entity.paymentToken = airToken.id; + let renewerAccount = getOrCreateAirAccount(chainId, renewer, block); + renewerAccount.save(); + entity.renewer = renewerAccount.id; entity.expiryTimestamp = expiryTimestamp; - entity.save(); } // getting renewal events from 2 contracts, old contract gives cost, new contract gives null, so if old contract event is processed first, then we update the cost // if new contract event is processed first, then we don't update the cost if (cost && !entity.cost) { entity.cost = cost; - entity.save(); } return entity as AirNameRenewedTransaction; } /** + * @dev this function does not save the returned entity * @dev this function gets or creates an AirNameRegisteredTransaction entity * @param chainId chain id * @param blockHeight block height * @param blockHash block hash * @param blockTimestamp block timestamp * @param transactionHash transaction hash - * @param logIndex log index + * @param logOrCallIndex txn log or call index * @param domain air domain * @param cost cost of the transaction * @param paymentToken payment token - can be null @@ -848,15 +784,16 @@ export namespace domain { blockHash: string, blockTimestamp: BigInt, transactionHash: string, - logIndex: BigInt, + logOrCallIndex: BigInt, domain: AirDomain, - cost: BigInt, + cost: BigInt | null, paymentToken: string, registrant: string, expiryTimestamp: BigInt, ): AirNameRegisteredTransaction { let block = getOrCreateAirBlock(chainId, blockHeight, blockHash, blockTimestamp); - let id = createEntityId(transactionHash, block.number, logIndex); + block.save(); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirNameRegisteredTransaction.load(id); if (entity == null) { entity = new AirNameRegisteredTransaction(id); @@ -866,27 +803,31 @@ export namespace domain { entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_NAME_REGISTERED_ENTITY_COUNTER_ID, block); entity.cost = cost; - if (paymentToken) { - entity.paymentToken = getOrCreateAirToken(chainId, paymentToken).id; - } - entity.registrant = getOrCreateAirAccount(chainId, registrant).id; + let airToken = getOrCreateAirToken(chainId, paymentToken); + airToken.save(); + entity.paymentToken = airToken.id; + let registrantAccount = getOrCreateAirAccount(chainId, registrant, block); + registrantAccount.save(); + entity.registrant = registrantAccount.id; entity.expiryTimestamp = expiryTimestamp; - entity.save(); } return entity as AirNameRegisteredTransaction; } /** + * @dev this function does not save the returned entity * @dev this function gets or creates an AirResolver entity * @param domain air domain entity * @param chainId chain id + * @param block air block * @param resolver resolver contract address - * @param addr address of addr record or null + * @param resolvedAddress address of resolved address or null * @returns AirResolver entity */ function getOrCreateAirResolver( domain: AirDomain, chainId: string, + block: AirBlock, resolver: string, resolvedAddress: string | null = EMPTY_STRING, ): AirResolver { @@ -894,23 +835,27 @@ export namespace domain { let entity = AirResolver.load(id); if (entity == null) { entity = new AirResolver(id); - entity.address = getOrCreateAirAccount(chainId, resolver).id; + let resolverAccount = getOrCreateAirAccount(chainId, resolver, block); + resolverAccount.save(); + entity.address = resolverAccount.id; entity.domain = domain.id; } if (resolvedAddress && resolvedAddress != EMPTY_STRING) { - entity.resolvedAddress = getOrCreateAirAccount(chainId, resolvedAddress).id; + let resolvedAddressAccount = getOrCreateAirAccount(chainId, resolvedAddress, block); + resolvedAddressAccount.save(); + entity.resolvedAddress = resolvedAddressAccount.id; } else if (resolvedAddress == null) { entity.resolvedAddress = null; } - entity.save(); return entity as AirResolver; } /** + * @dev this function does not save the returned entity * @dev This function gets or creates a new AirDomainNewTTLTransaction entity * @param transactionHash transaction hash * @param blockHeight block number in the chain - * @param logIndex txn log index + * @param logOrCallIndex txn log or call index * @param oldTTL old ttl value - can be null * @param newTTL new ttl value * @param block air block object @@ -920,13 +865,13 @@ export namespace domain { function getOrCreateAirDomainNewTTLTransaction( transactionHash: string, blockHeight: BigInt, - logIndex: BigInt, + logOrCallIndex: BigInt, oldTTL: BigInt | null, newTTL: BigInt, block: AirBlock, domain: AirDomain, ): AirDomainNewTTLTransaction { - let id = createEntityId(transactionHash, blockHeight, logIndex); + let id = createEntityId(transactionHash, blockHeight, logOrCallIndex); let entity = AirDomainNewTTLTransaction.load(id); if (entity == null) { entity = new AirDomainNewTTLTransaction(id); @@ -937,18 +882,18 @@ export namespace domain { entity.tokenId = domain.tokenId; entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER_ID, block); - entity.save(); } return entity as AirDomainNewTTLTransaction; } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new AirDomainNewResolverTransaction entity * @param previousResolverId previous resolver Id - can be null * @param newResolverId new resolver Id * @param block air block entity * @param transactionHash transaction hash - * @param logIndex log index + * @param logOrCallIndex txn log or call index * @param domain air domain entity * @returns AirDomainNewResolverTransaction entity */ @@ -957,10 +902,10 @@ export namespace domain { newResolverId: string, block: AirBlock, transactionHash: string, - logIndex: BigInt, + logOrCallIndex: BigInt, domain: AirDomain, ): AirDomainNewResolverTransaction { - let id = createEntityId(transactionHash, block.number, logIndex); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirDomainNewResolverTransaction.load(id); if (entity == null) { entity = new AirDomainNewResolverTransaction(id); @@ -971,30 +916,12 @@ export namespace domain { entity.tokenId = domain.tokenId; entity.domain = domain.id; entity.index = updateAirEntityCounter(AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID, block); - entity.save(); } return entity as AirDomainNewResolverTransaction; } /** - * @dev this function creates a new DomainVsIsMigratedMapping entity - * @param domaiId air domain entity id - * @param blockId air block entity id - * @param isMigrated is migrated flag - only required when creating a new entity - * @returns DomainVsIsMigratedMapping entity - */ - function getOrCreateIsMigratedMapping(domainId: string, blockId: string, isMigrated: boolean = false): DomainVsIsMigratedMapping { - let entity = DomainVsIsMigratedMapping.load(domainId); - if (entity == null) { - entity = new DomainVsIsMigratedMapping(domainId); - entity.isMigrated = isMigrated; - entity.lastUpdatedAt = blockId; - entity.save(); - } - return entity as DomainVsIsMigratedMapping; - } - - /** + * @dev this function does not save the returned entity * @dev this function creates a new reverse registrar entity if it does not exist * @param name ens name, ex: 'schiller.eth' * @param domainId air domain id @@ -1013,7 +940,6 @@ export namespace domain { entity.name = name; entity.domain = domainId; entity.createdAt = block.id; - entity.save(); } return entity as ReverseRegistrar; } @@ -1031,6 +957,7 @@ export namespace domain { } /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new air domain entity * @param domain Domain class object * @returns AirDomain entity @@ -1042,22 +969,36 @@ export namespace domain { if (entity == null) { entity = new AirDomain(domain.id); entity.subdomainCount = BIG_INT_ZERO; - entity.owner = getOrCreateAirAccount(domain.chainId, ZERO_ADDRESS).id; - entity.tokenAddress = getOrCreateAirToken(domain.chainId, domain.tokenAddress).id; + let ownerAccount = getOrCreateAirAccount(domain.chainId, ZERO_ADDRESS, domain.block); + ownerAccount.save(); + entity.owner = ownerAccount.id; + let airToken = getOrCreateAirToken(domain.chainId, domain.tokenAddress); + entity.tokenAddress = airToken.id; entity.isPrimary = false; entity.expiryTimestamp = BIG_INT_ZERO; entity.registrationCost = BIG_INT_ZERO; entity.createdAt = domain.block.id; - entity.lastBlock = domain.block.id; - entity.save(); + entity.lastUpdatedBlock = domain.block.id; } return entity as AirDomain; } /** + * @dev this function gets a air domain entity + * @param domainId air domain entity id + * @returns AirDomain entity - null if entity does not exist + */ + export function getAirDomain( + domainId: string, + ): AirDomain | null { + return AirDomain.load(domainId); + } + + /** + * @dev this function does not save the returned entity * @dev this function gets or creates a new air domain owner changed transaction entity * @param block air block entity - * @param logIndex log index + * @param logOrCallIndex log or call index * @param chainId chain id * @param previousOwnerId previous owner id * @param newOwner new owner address @@ -1068,7 +1009,7 @@ export namespace domain { */ function getOrCreateAirDomainOwnerChangedTransaction( block: AirBlock, - logIndex: BigInt, + logOrCallIndex: BigInt, chainId: string, previousOwnerId: string, newOwner: string, @@ -1076,18 +1017,19 @@ export namespace domain { tokenId: string, domain: AirDomain, ): AirDomainOwnerChangedTransaction { - let id = createEntityId(transactionHash, block.number, logIndex); + let id = createEntityId(transactionHash, block.number, logOrCallIndex); let entity = AirDomainOwnerChangedTransaction.load(id); if (entity == null) { entity = new AirDomainOwnerChangedTransaction(id); entity.previousOwner = previousOwnerId; - entity.newOwner = getOrCreateAirAccount(chainId, newOwner).id; + let newOwnerAccount = getOrCreateAirAccount(chainId, newOwner, block); + newOwnerAccount.save(); + entity.newOwner = newOwnerAccount.id; entity.transactionHash = transactionHash; entity.tokenId = tokenId; entity.domain = domain.id; entity.block = block.id; entity.index = updateAirEntityCounter(AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID, block); - entity.save(); } return entity as AirDomainOwnerChangedTransaction; } @@ -1098,58 +1040,20 @@ export namespace domain { * @param chainId chain id * @param block air block entity * @param tokenAddress contract address of nft token - * @returns air domain entity id */ - function recurseSubdomainCountDecrement(domain: AirDomain, chainId: string, block: AirBlock, tokenAddress: string): string | null { + function recurseSubdomainCountDecrement(domain: AirDomain, chainId: string, block: AirBlock, tokenAddress: string): void { if ((domain.resolver == null || domain.resolver!.split("-")[0] == ZERO_ADDRESS) && - domain.owner == getOrCreateAirAccount(chainId, ZERO_ADDRESS).id && domain.subdomainCount == BIG_INT_ZERO) { + domain.owner == getOrCreateAirAccount(chainId, ZERO_ADDRESS, block).id && domain.subdomainCount == BIG_INT_ZERO) { if (domain.parent) { const parentDomain = getOrCreateAirDomain(new Domain(domain.parent!, chainId, block, tokenAddress)); if (parentDomain) { parentDomain.subdomainCount = parentDomain.subdomainCount.minus(BIGINT_ONE) - parentDomain.lastBlock = block.id; + parentDomain.lastUpdatedBlock = block.id; parentDomain.save(); - return recurseSubdomainCountDecrement(parentDomain, chainId, block, tokenAddress) + recurseSubdomainCountDecrement(parentDomain, chainId, block, tokenAddress) } } - return null - } - return domain.id - } - - /** - * @dev this function gets or creates a new air token entity - * @param chainID chain id - * @param address token address - * @returns AirToken entity - */ - function getOrCreateAirToken(chainID: string, address: string): AirToken { - let entity = AirToken.load(chainID + "-" + address); - if (entity == null) { - entity = new AirToken(chainID + "-" + address); - entity.address = address; - entity.save(); - } - return entity as AirToken; - } - - /** - * @dev this function gets or creates a new air account entity - * @param chainId chain id - * @param address account address - * @returns AirAccount entity - */ - function getOrCreateAirAccount(chainId: string, address: string): AirAccount { - if (address == EMPTY_STRING) { - address = ZERO_ADDRESS; - } - let entity = AirAccount.load(chainId + "-" + address); - if (entity == null) { - entity = new AirAccount(chainId + "-" + address); - entity.address = address; - entity.save(); } - return entity as AirAccount; } /** diff --git a/ens/modules/airstack/domain-name/utils.ts b/ens/modules/airstack/domain-name/utils.ts index e2a311a8..e2afbe7a 100644 --- a/ens/modules/airstack/domain-name/utils.ts +++ b/ens/modules/airstack/domain-name/utils.ts @@ -1,8 +1,3 @@ -import { - BigInt, - ByteArray, -} from "@graphprotocol/graph-ts"; - export const AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER_ID = "AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER"; export const AIR_DOMAIN_TRANSFER_ENTITY_COUNTER_ID = "AIR_DOMAIN_TRANSFER_ENTITY_COUNTER"; export const AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER_ID = "AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER"; @@ -14,22 +9,7 @@ export const AIR_SET_PRIMARY_DOMAIN_ENTITY_COUNTER_ID = "AIR_SET_PRIMARY_DOMAIN_ export const AIR_META_ID = "AIR_META"; export const ETHEREUM_MAINNET_ID = "1"; +export const AIR_EXTRA_TTL = 'ttl'; export const ROOT_NODE = '0x0000000000000000000000000000000000000000000000000000000000000000' -export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; - -export function byteArrayFromHex(s: string): ByteArray { - if (s.length % 2 !== 0) { - throw new TypeError("Hex string must have an even number of characters") - } - let out = new Uint8Array(s.length / 2) - for (var i = 0; i < s.length; i += 2) { - out[i / 2] = parseInt(s.substring(i, i + 2), 16) as u32 - } - return changetype(out) -} - -export function uint256ToByteArray(i: BigInt): ByteArray { - let hex = i.toHex().slice(2).padStart(64, '0') - return byteArrayFromHex(hex) -} \ No newline at end of file +export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; \ No newline at end of file diff --git a/ens/package-lock.json b/ens/package-lock.json index 36b350c0..ceb4660f 100644 --- a/ens/package-lock.json +++ b/ens/package-lock.json @@ -19,7 +19,7 @@ "node_modules/@airstack/subgraph-generator": { "version": "1.0.0-alpha.3", "resolved": "file:../airstack-modules/airstack-subgraph-generator-1.0.0-alpha.3.tgz", - "integrity": "sha512-WKcm0wiNPIuTD5t55J8PpuQo6R82epE6SAw85mOq0ldUE/+T/dFTfPKwtRb4hN4NN1Jg0m6Yc+fbchQIF25UUA==", + "integrity": "sha512-ePXxSN3mJbd2COZuZv+0aDwIGX4nOqqH8Bot9St/wUkLVnhugQtsoC1nlOAVCqQRCN1hYf82WGg2JGdnAyIkpA==", "license": "ISC", "dependencies": { "@graphprotocol/graph-cli": "0.33.0", @@ -5544,7 +5544,7 @@ "dependencies": { "@airstack/subgraph-generator": { "version": "file:../airstack-modules/airstack-subgraph-generator-1.0.0-alpha.3.tgz", - "integrity": "sha512-WKcm0wiNPIuTD5t55J8PpuQo6R82epE6SAw85mOq0ldUE/+T/dFTfPKwtRb4hN4NN1Jg0m6Yc+fbchQIF25UUA==", + "integrity": "sha512-ePXxSN3mJbd2COZuZv+0aDwIGX4nOqqH8Bot9St/wUkLVnhugQtsoC1nlOAVCqQRCN1hYf82WGg2JGdnAyIkpA==", "requires": { "@graphprotocol/graph-cli": "0.33.0", "@graphprotocol/graph-ts": "0.27.0", diff --git a/ens/schema.graphql b/ens/schema.graphql index a74569fd..f48087b8 100644 --- a/ens/schema.graphql +++ b/ens/schema.graphql @@ -43,9 +43,16 @@ type AirEntityCounter @entity { lastUpdatedAt: AirBlock! } +type AirExtra @entity { + id: ID! # Concatenation of domainId and name + name: String! + value: String! +} + type AirAccount @entity { id: ID! address: String! + createdAt: AirBlock! } type AirToken @entity { @@ -57,7 +64,7 @@ type AirDomain @entity { id: ID! # The namehash of the name name: String # The human readable name, if known. Unknown portions replaced with hash in square brackets (eg, foo.[1234].eth) labelName: String # The human readable label name (imported from CSV), if known - labelHash: Bytes # keccak256(labelName) + labelHash: String # keccak256(labelName) tokenId: String # dec(labelHash) parent: AirDomain # The namehash (id) of the parent name subdomains: [AirDomain!]! @derivedFrom(field: "parent") # Can count domains from length of array @@ -65,14 +72,14 @@ type AirDomain @entity { resolvedAddress: AirAccount # Address logged from current resolver, if any owner: AirAccount! resolver: AirResolver - ttl: BigInt isPrimary: Boolean! # - NA # Is the primary domain for the resolved address expiryTimestamp: BigInt! registrationCost: BigInt! # Cost of domain registration in wei paymentToken: AirToken # Token used to pay for registration tokenAddress: AirToken! # Domain (eg: ens) token contract address createdAt: AirBlock! - lastBlock: AirBlock #- NA + lastUpdatedBlock: AirBlock #- NA + extras: [AirExtra!] } type AirDomainTransferTransaction implements AirDomainEvent @entity { @@ -123,14 +130,14 @@ type AirResolver @entity { id: ID! # Concatenation of resolver address and namehash domain: AirDomain address: AirAccount! # Address of resolver contract - resolvedAddress: AirAccount # Current value of addr record (per events) + resolvedAddress: AirAccount # Current value of resolved address record (per events) } -type AirAddrChanged implements AirDomainEvent @entity { +type AirResolvedAddressChanged implements AirDomainEvent @entity { id: ID! resolver: AirResolver! - previousResolvedAddress: AirAccount # previous addr record - newResolvedAddress: AirAccount! # new addr record + previousResolvedAddress: AirAccount # previous resolved address record + newResolvedAddress: AirAccount! # new resolved address record block: AirBlock! transactionHash: String! tokenId: String # dec(labelhash) - NA diff --git a/ens/src/ens-registry.ts b/ens/src/ens-registry.ts index 3aed13fc..81d177eb 100644 --- a/ens/src/ens-registry.ts +++ b/ens/src/ens-registry.ts @@ -7,29 +7,72 @@ import { import * as airstack from "../modules/airstack/domain-name"; import { log, + BigInt, + ens, } from "@graphprotocol/graph-ts"; -import { ETHEREUM_MAINNET_ID } from "../modules/airstack/domain-name/utils"; -import { TOKEN_ADDRESS_ENS } from "./utils"; +import { ETHEREUM_MAINNET_ID, ROOT_NODE } from "../modules/airstack/domain-name/utils"; +import { getChainId } from "../modules/airstack/common"; +import { + TOKEN_ADDRESS_ENS, + getOrCreateIsMigratedMapping, + createAirDomainEntityId, + createReverseRegistrar, +} from "./utils"; +import { AirDomain } from "../generated/schema"; /** * @dev this functions maps the NewOwner event to airstack trackDomainOwnerChangedTransaction * @param event NewOwnerEvent from ENS Registry */ export function handleNewOwner(event: NewOwnerEvent): void { log.info("handleNewOwner: owner {} node {} label {} txhash {}", [event.params.owner.toHexString(), event.params.node.toHexString(), event.params.label.toHexString(), event.transaction.hash.toHexString()]); + let domainId = createAirDomainEntityId(event.params.node, event.params.label); + let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); + let tokenId = BigInt.fromUnsignedBytes(event.params.label).toString(); + // marking the domain as migrated + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, + ETHEREUM_MAINNET_ID, + blockId, + true, + ); + isMigratedMapping.save(); + // creating labelName from label + let labelName = ens.nameByHash(event.params.label.toHexString()); + if (labelName === null) { + labelName = '[' + event.params.label.toHexString().slice(2) + ']'; + } + // creating name from labelName and parentName + let name: string | null; + let parentName: string | null; + if (event.params.node.toHexString() == ROOT_NODE) { + name = labelName; + } else { + let parent = AirDomain.load(event.params.node.toHexString()); + if (parent != null) { + parentName = parent.name; + } else { + parentName = ""; + } + name = labelName + "." + parentName!; + } + if (name) { + let reverseRegistrar = createReverseRegistrar(name, domainId, ETHEREUM_MAINNET_ID, event.block); + reverseRegistrar.save(); + } + // sending transaction to airstack airstack.domain.trackDomainOwnerChangedTransaction( - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, + event.block, + event.transaction.hash.toHexString(), event.logIndex, - ETHEREUM_MAINNET_ID, + domainId, + event.params.node.toHexString(), + tokenId, + event.params.label.toHexString(), + labelName, + name, event.params.owner.toHexString(), - event.transaction.hash.toHexString(), - true, - event.params.node, - event.params.label, TOKEN_ADDRESS_ENS, - false, - ); + ) } /** @@ -38,17 +81,24 @@ export function handleNewOwner(event: NewOwnerEvent): void { */ export function handleTransfer(event: TransferEvent): void { log.info("handleTransfer: owner {} node {} txhash {}", [event.params.owner.toHexString(), event.params.node.toHexString(), event.transaction.hash.toHexString()]); - airstack.domain.trackDomainTransferTransaction( - event.params.node.toHexString(), + // marking the domain as migrated + let domainId = event.params.node.toHexString(); + let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, ETHEREUM_MAINNET_ID, - event.params.owner.toHexString(), - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - event.logIndex, + blockId, + true, + ); + isMigratedMapping.save(); + // sending transaction to airstack + airstack.domain.trackDomainTransferTransaction( + event.block, event.transaction.hash.toHexString(), + event.logIndex, + domainId, + event.params.owner.toHexString(), TOKEN_ADDRESS_ENS, - false, ) } @@ -58,17 +108,23 @@ export function handleTransfer(event: TransferEvent): void { */ export function handleNewResolver(event: NewResolverEvent): void { log.info("handleNewResolver: resolver {} node {} txhash {}", [event.params.resolver.toHexString(), event.params.node.toHexString(), event.transaction.hash.toHexString()]); + let domainId = event.params.node.toHexString(); + let blockId = getChainId().concat("-").concat(event.block.number.toString()); + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, + getChainId(), + blockId, + true, + ); + isMigratedMapping.save(); + // sending transaction to airstack airstack.domain.trackDomainNewResolverTransaction( - event.params.resolver.toHexString(), - event.params.node.toHexString(), - ETHEREUM_MAINNET_ID, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, + event.block, event.transaction.hash.toHexString(), event.logIndex, + domainId, + event.params.resolver.toHexString(), TOKEN_ADDRESS_ENS, - false, ) } @@ -78,17 +134,23 @@ export function handleNewResolver(event: NewResolverEvent): void { */ export function handleNewTTL(event: NewTTLEvent): void { log.info("handleNewTTL: {} {} {} ", [event.params.ttl.toString(), event.params.node.toHexString(), event.transaction.hash.toHexString()]); + let domainId = event.params.node.toHexString(); + let blockId = getChainId().concat("-").concat(event.block.number.toString()); + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, + getChainId(), + blockId, + true, + ); + isMigratedMapping.save(); + // sending transaction to airstack airstack.domain.trackDomainNewTTLTransaction( - event.params.node.toHexString(), - event.params.ttl, - ETHEREUM_MAINNET_ID, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - event.logIndex, + event.block, event.transaction.hash.toHexString(), + event.logIndex, + domainId, + event.params.ttl, TOKEN_ADDRESS_ENS, - false, ) } @@ -98,20 +160,60 @@ export function handleNewTTL(event: NewTTLEvent): void { */ export function handleNewOwnerOldRegistry(event: NewOwnerEvent): void { log.info("handleNewOwnerOldRegistry: owner {} node {} label {} txhash {}", [event.params.owner.toHexString(), event.params.node.toHexString(), event.params.label.toHexString(), event.transaction.hash.toHexString()]); + let domainId = createAirDomainEntityId(event.params.node, event.params.label); + let blockId = getChainId().concat("-").concat(event.block.number.toString()); + let tokenId = BigInt.fromUnsignedBytes(event.params.label).toString(); + // getting is migrated mapping + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, + getChainId(), + blockId, + false, + ); + // this domain was migrated from the old registry, so we don't need to handle old registry event now + // this check needs to be done only in old registry event + if (isMigratedMapping.isMigrated == true) { + return; + } + // if the domain is not migrated yet, we save the above created mapping + isMigratedMapping.save(); + // creating labelName from label + let labelName = ens.nameByHash(event.params.label.toHexString()); + if (labelName === null) { + labelName = '[' + event.params.label.toHexString().slice(2) + ']'; + } + // creating name from labelName and parentName + let name: string | null; + let parentName: string | null; + if (event.params.node.toHexString() == ROOT_NODE) { + name = labelName; + } else { + let parent = AirDomain.load(event.params.node.toHexString()); + if (parent != null) { + parentName = parent.name; + } else { + parentName = ""; + } + name = labelName + "." + parentName!; + } + if (name) { + let reverseRegistrar = createReverseRegistrar(name, domainId, getChainId(), event.block); + reverseRegistrar.save(); + } + // sending transaction to airstack airstack.domain.trackDomainOwnerChangedTransaction( - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, + event.block, + event.transaction.hash.toHexString(), event.logIndex, - ETHEREUM_MAINNET_ID, + domainId, + event.params.node.toHexString(), + tokenId, + event.params.label.toHexString(), + labelName, + name, event.params.owner.toHexString(), - event.transaction.hash.toHexString(), - false, - event.params.node, - event.params.label, TOKEN_ADDRESS_ENS, - true, - ); + ) } /** @@ -120,17 +222,30 @@ export function handleNewOwnerOldRegistry(event: NewOwnerEvent): void { */ export function handleNewResolverOldRegistry(event: NewResolverEvent): void { log.info("handleNewResolverOldRegistry: resolver {} node {} txhash {}", [event.params.resolver.toHexString(), event.params.node.toHexString(), event.transaction.hash.toHexString()]); + // getting is migrated mapping + let domainId = event.params.node.toHexString(); + let blockId = getChainId().concat("-").concat(event.block.number.toString()); + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, + getChainId(), + blockId, + false, + ); + // this domain was migrated from the old registry, so we don't need to handle old registry event now + // this check needs to be done only in old registry event + if (domainId != ROOT_NODE && isMigratedMapping.isMigrated == true) { + return; + } + // if the domain is not migrated yet, we save the above created mapping + isMigratedMapping.save(); + // sending transaction to airstack airstack.domain.trackDomainNewResolverTransaction( - event.params.resolver.toHexString(), - event.params.node.toHexString(), - ETHEREUM_MAINNET_ID, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, + event.block, event.transaction.hash.toHexString(), event.logIndex, + domainId, + event.params.resolver.toHexString(), TOKEN_ADDRESS_ENS, - true, ) } @@ -140,17 +255,29 @@ export function handleNewResolverOldRegistry(event: NewResolverEvent): void { */ export function handleNewTTLOldRegistry(event: NewTTLEvent): void { log.info("handleNewTTLOldRegistry: {} {} {}", [event.params.ttl.toString(), event.params.node.toHexString(), event.transaction.hash.toHexString()]); - airstack.domain.trackDomainNewTTLTransaction( - event.params.node.toHexString(), - event.params.ttl, + // getting is migrated mapping + let domainId = event.params.node.toHexString(); + let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, ETHEREUM_MAINNET_ID, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - event.logIndex, + blockId, + false, + ); + // this domain was migrated from the old registry, so we don't need to handle old registry event now + // this check needs to be done only in old registry event + if (isMigratedMapping.isMigrated == true) { + return; + } + // if the domain is not migrated yet, we save the above created mapping + isMigratedMapping.save(); + airstack.domain.trackDomainNewTTLTransaction( + event.block, event.transaction.hash.toHexString(), + event.logIndex, + domainId, + event.params.ttl, TOKEN_ADDRESS_ENS, - true, ) } @@ -160,16 +287,29 @@ export function handleNewTTLOldRegistry(event: NewTTLEvent): void { */ export function handleTransferOldRegistry(event: TransferEvent): void { log.info("handleTransferOldRegistry: owner {} node {} txhash {}", [event.params.owner.toHexString(), event.params.node.toHexString(), event.transaction.hash.toHexString()]); - airstack.domain.trackDomainTransferTransaction( - event.params.node.toHexString(), + // getting is migrated mapping + let domainId = event.params.node.toHexString(); + let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); + let isMigratedMapping = getOrCreateIsMigratedMapping( + domainId, ETHEREUM_MAINNET_ID, - event.params.owner.toHexString(), - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - event.logIndex, + blockId, + false, + ); + // this domain was migrated from the old registry, so we don't need to handle old registry event now + // this check needs to be done only in old registry event + if (isMigratedMapping.isMigrated == true) { + return; + } + // if the domain is not migrated yet, we save the above created mapping + isMigratedMapping.save(); + // sending transaction to airstack + airstack.domain.trackDomainTransferTransaction( + event.block, event.transaction.hash.toHexString(), + event.logIndex, + domainId, + event.params.owner.toHexString(), TOKEN_ADDRESS_ENS, - true, ) } \ No newline at end of file diff --git a/ens/src/eth-registrar.ts b/ens/src/eth-registrar.ts index 939c67af..8efb8cbc 100644 --- a/ens/src/eth-registrar.ts +++ b/ens/src/eth-registrar.ts @@ -1,14 +1,13 @@ // Import types and APIs from graph-ts import { ByteArray, - log + log, + ens, + crypto, } from '@graphprotocol/graph-ts' - import { TOKEN_ADDRESS_ENS } from "./utils"; -import { byteArrayFromHex, ETHEREUM_MAINNET_ID, ZERO_ADDRESS } from '../modules/airstack/domain-name/utils'; -import { BIG_INT_ZERO } from '../modules/airstack/common'; +import { ZERO_ADDRESS } from '../modules/airstack/domain-name/utils'; import * as airstack from "../modules/airstack/domain-name"; - // Import event types from the registry contract ABI import { NameRegistered as NameRegisteredEvent, @@ -21,6 +20,7 @@ import { NameRegistered as ControllerNameRegisteredEvent, NameRenewed as ControllerNameRenewedEvent } from '../generated/EthRegistrarController/EthRegistrarController'; +import { uint256ToByteArray, byteArrayFromHex } from './utils'; const rootNode: ByteArray = byteArrayFromHex("93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"); @@ -30,20 +30,19 @@ const rootNode: ByteArray = byteArrayFromHex("93cdeb708b7545dc668eb9280176169d1c */ export function handleNameRegistered(event: NameRegisteredEvent): void { log.info("handleNameRegistered: registrant {} label {} expiry {} txhash {}", [event.params.owner.toHexString(), event.params.id.toHexString(), event.params.expires.toString(), event.transaction.hash.toHexString()]); - + let label = uint256ToByteArray(event.params.id); + let labelName = ens.nameByHash(label.toHexString()); + let domainId = crypto.keccak256(rootNode.concat(label)).toHex(); airstack.domain.trackNameRegisteredTransaction( + event.block, event.transaction.hash.toHexString(), - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, event.logIndex, - ETHEREUM_MAINNET_ID, + domainId, event.params.owner.toHexString(), event.params.expires, - event.transaction.value, + null, ZERO_ADDRESS, - event.params.id, - rootNode, + labelName, TOKEN_ADDRESS_ENS, ); } @@ -54,18 +53,15 @@ export function handleNameRegistered(event: NameRegisteredEvent): void { */ export function handleNameRenewed(event: NameRenewedEvent): void { log.info("handleNameRenewed: renewer {} label {} expiry {} txhash {}", [event.transaction.from.toHexString(), event.params.id.toHexString(), event.params.expires.toString(), event.transaction.hash.toHexString()]); - + let label = uint256ToByteArray(event.params.id); + let domainId = crypto.keccak256(rootNode.concat(label)).toHex(); airstack.domain.trackNameRenewedTransaction( + event.block, event.transaction.hash.toHexString(), - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - ETHEREUM_MAINNET_ID, + domainId, null, ZERO_ADDRESS, event.transaction.from.toHexString(), - event.params.id, - rootNode, event.params.expires, TOKEN_ADDRESS_ENS, ); @@ -77,21 +73,19 @@ export function handleNameRenewed(event: NameRenewedEvent): void { */ export function handleNameRegisteredByControllerOld(event: ControllerNameRegisteredEventOld): void { log.info("handleNameRegisteredByControllerOld: name {} label {} cost {} txhash {}", [event.params.name, event.params.label.toHexString(), event.params.cost.toString(), event.transaction.hash.toHexString()]); - airstack.domain.trackSetNamePreImage( + let domainId = crypto.keccak256(rootNode.concat(event.params.label)).toHex(); + airstack.domain.trackNameRenewedOrRegistrationByController( + event.block, + event.transaction.hash.toHexString(), + domainId, event.params.name, event.params.label, event.params.cost, ZERO_ADDRESS, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - ETHEREUM_MAINNET_ID, - rootNode, - TOKEN_ADDRESS_ENS, - event.transaction.hash.toHexString(), - null, - null, + event.params.owner.toHexString(), + event.params.expires, true, + TOKEN_ADDRESS_ENS, ) } @@ -101,22 +95,19 @@ export function handleNameRegisteredByControllerOld(event: ControllerNameRegiste */ export function handleNameRegisteredByController(event: ControllerNameRegisteredEvent): void { log.info("handleNameRegisteredByController: name {} label {} cost {} txhash {}", [event.params.name, event.params.label.toHexString(), event.params.cost.toString(), event.transaction.hash.toHexString()]); - - airstack.domain.trackSetNamePreImage( + let domainId = crypto.keccak256(rootNode.concat(event.params.label)).toHex(); + airstack.domain.trackNameRenewedOrRegistrationByController( + event.block, + event.transaction.hash.toHexString(), + domainId, event.params.name, event.params.label, event.params.cost, ZERO_ADDRESS, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - ETHEREUM_MAINNET_ID, - rootNode, - TOKEN_ADDRESS_ENS, - event.transaction.hash.toHexString(), - null, - null, + event.params.owner.toHexString(), + event.params.expires, true, + TOKEN_ADDRESS_ENS, ) } @@ -126,20 +117,18 @@ export function handleNameRegisteredByController(event: ControllerNameRegistered */ export function handleNameRenewedByController(event: ControllerNameRenewedEvent): void { log.info("handleNameRenewedByController: name {} label {} cost {} txhash {}", [event.params.name, event.params.label.toHexString(), event.params.cost.toString(), event.transaction.hash.toHexString()]); - airstack.domain.trackSetNamePreImage( + let domainId = crypto.keccak256(rootNode.concat(event.params.label)).toHex(); + airstack.domain.trackNameRenewedOrRegistrationByController( + event.block, + event.transaction.hash.toHexString(), + domainId, event.params.name, event.params.label, event.params.cost, ZERO_ADDRESS, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - ETHEREUM_MAINNET_ID, - rootNode, - TOKEN_ADDRESS_ENS, - event.transaction.hash.toHexString(), event.transaction.from.toHexString(), event.params.expires, false, + TOKEN_ADDRESS_ENS, ) } \ No newline at end of file diff --git a/ens/src/resolver.ts b/ens/src/resolver.ts index 963ed199..3adc136e 100644 --- a/ens/src/resolver.ts +++ b/ens/src/resolver.ts @@ -4,7 +4,6 @@ import { VersionChanged as VersionChangedEvent, } from "../generated/Resolver1/Resolver"; import { log } from "@graphprotocol/graph-ts"; -import { ETHEREUM_MAINNET_ID } from "../modules/airstack/domain-name/utils"; import { TOKEN_ADDRESS_ENS } from "./utils"; /** * @dev this function maps the AddrChanged event from the Resolver contract @@ -12,16 +11,13 @@ import { TOKEN_ADDRESS_ENS } from "./utils"; */ export function handleAddrChanged(event: AddrChangedEvent): void { log.info("handleAddrChanged: node {} addr {} resolver {} txhash {}", [event.params.node.toHexString(), event.params.a.toHexString(), event.address.toHexString(), event.transaction.hash.toHexString()]); - airstack.domain.trackAddrChangedTransaction( - ETHEREUM_MAINNET_ID, + airstack.domain.trackResolvedAddressChangedTransaction( + event.block, + event.transaction.hash.toHexString(), event.logIndex, + event.params.node.toHexString(), event.address.toHexString(), event.params.a.toHexString(), - event.params.node.toHexString(), - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, - event.transaction.hash.toHexString(), TOKEN_ADDRESS_ENS, ); } @@ -33,10 +29,7 @@ export function handleAddrChanged(event: AddrChangedEvent): void { export function handleVersionChanged(event: VersionChangedEvent): void { log.info("handleVersionChanged: node {} resolver {} txhash {}", [event.params.node.toHexString(), event.address.toHexString(), event.transaction.hash.toHexString()]); airstack.domain.trackResolverVersionChange( - ETHEREUM_MAINNET_ID, - event.block.number, - event.block.hash.toHexString(), - event.block.timestamp, + event.block, event.params.node.toHexString(), event.address.toHexString(), TOKEN_ADDRESS_ENS, diff --git a/ens/src/reverse-registrar.ts b/ens/src/reverse-registrar.ts index 25a2b538..b5ce806f 100644 --- a/ens/src/reverse-registrar.ts +++ b/ens/src/reverse-registrar.ts @@ -3,7 +3,6 @@ import { log } from "@graphprotocol/graph-ts"; import { SetNameCall, } from "../generated/ReverseRegistrar/ReverseRegistrar"; -import { ETHEREUM_MAINNET_ID } from "../modules/airstack/domain-name/utils"; import { TOKEN_ADDRESS_ENS } from "./utils"; /** * @dev this function maps the SetName call from the ReverseRegistrar contract @@ -12,13 +11,10 @@ import { TOKEN_ADDRESS_ENS } from "./utils"; export function handleSetName(call: SetNameCall): void { log.info("handleSetName: name {} txhash {}", [call.inputs.name, call.transaction.hash.toHexString()]); airstack.domain.trackSetPrimaryDomainTransaction( + call.block, + call.transaction.hash.toHexString(), call.inputs.name, - ETHEREUM_MAINNET_ID, call.from.toHexString(), - call.block.number, - call.block.hash.toHexString(), - call.block.timestamp, - call.transaction.hash.toHexString(), TOKEN_ADDRESS_ENS, ); } \ No newline at end of file diff --git a/ens/src/utils.ts b/ens/src/utils.ts index 05a03612..4cbd8e58 100644 --- a/ens/src/utils.ts +++ b/ens/src/utils.ts @@ -1 +1,84 @@ -export const TOKEN_ADDRESS_ENS = "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85"; \ No newline at end of file +import { + DomainVsIsMigratedMapping, + ReverseRegistrar, +} from "../generated/schema"; +import { + Bytes, + crypto, + ethereum, + ByteArray, + BigInt, +} from "@graphprotocol/graph-ts"; + +// ens constants +export const TOKEN_ADDRESS_ENS = "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85"; + +/** + * @dev this function creates a new DomainVsIsMigratedMapping entity + * @param domaiId air domain entity id + * @param chainId chain id + * @param blockId air block id + * @param isMigrated is migrated flag - only required when creating a new entity + * @returns DomainVsIsMigratedMapping entity +*/ +export function getOrCreateIsMigratedMapping(domainId: string, chainId: string, blockId: string, isMigrated: boolean = false): DomainVsIsMigratedMapping { + let entity = DomainVsIsMigratedMapping.load(domainId); + if (entity == null) { + entity = new DomainVsIsMigratedMapping(domainId); + entity.isMigrated = isMigrated; + entity.lastUpdatedAt = blockId; + } + return entity as DomainVsIsMigratedMapping; +} + +/** + * @dev this function creates subnode of the node and returns it as air domain entity id + * @param node takes the node param from the event + * @param label takes the label param from the event + * @returns returns a air domain entity id + */ +export function createAirDomainEntityId(node: Bytes, label: Bytes): string { + return crypto.keccak256(node.concat(label)).toHexString() +} + +/** + * @dev this function creates a new reverse registrar entity if it does not exist + * @param name ens name, ex: 'schiller.eth' + * @param domainId air domain id + * @param block air block entity + * @returns ReverseRegistrar entity + */ +export function createReverseRegistrar( + name: string, + domainId: string, + chainId: string, + block: ethereum.Block, +): ReverseRegistrar { + let id = crypto.keccak256(Bytes.fromUTF8(name)).toHexString(); + let entity = ReverseRegistrar.load(id); + if (entity == null) { + entity = new ReverseRegistrar(id); + entity.name = name; + entity.domain = domainId; + entity.createdAt = chainId.concat("-").concat(block.number.toString()); + entity.save(); + } + return entity as ReverseRegistrar; +} + +// specific to ens +export function byteArrayFromHex(s: string): ByteArray { + if (s.length % 2 !== 0) { + throw new TypeError("Hex string must have an even number of characters") + } + let out = new Uint8Array(s.length / 2) + for (var i = 0; i < s.length; i += 2) { + out[i / 2] = parseInt(s.substring(i, i + 2), 16) as u32 + } + return changetype(out) +} + +export function uint256ToByteArray(i: BigInt): ByteArray { + let hex = i.toHex().slice(2).padStart(64, '0') + return byteArrayFromHex(hex) +} \ No newline at end of file diff --git a/ens/subgraph.yaml b/ens/subgraph.yaml index 21313b79..bd896a3c 100644 --- a/ens/subgraph.yaml +++ b/ens/subgraph.yaml @@ -119,119 +119,10 @@ dataSources: - event: NameRenewed(indexed uint256,uint256) handler: handleNameRenewed - kind: ethereum/contract - name: Resolver2 + name: Resolver network: mainnet source: abi: Resolver - address: '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41' - startBlock: 9412610 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: Resolver1 - network: mainnet - source: - abi: Resolver - address: '0xDaaF96c344f63131acadD0Ea35170E7892d3dfBA' - startBlock: 9380387 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: OldResolver2 - network: mainnet - source: - abi: Resolver - address: '0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8' - startBlock: 8659893 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: OldResolver1 - network: mainnet - source: - abi: Resolver - address: '0x1da022710dF5002339274AaDEe8D58218e9D6AB5' startBlock: 3648359 mapping: kind: ethereum/events diff --git a/ens/subgraph.yaml.bck b/ens/subgraph.yaml.bck deleted file mode 100644 index 21313b79..00000000 --- a/ens/subgraph.yaml.bck +++ /dev/null @@ -1,370 +0,0 @@ -specVersion: 0.0.5 -schema: - file: ./schema.graphql -dataSources: - - kind: ethereum - name: EnsRegistry - network: mainnet - source: - address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e' - abi: EnsRegistry - startBlock: 9380380 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: EnsRegistry - file: ./abis/EnsRegistry.json - eventHandlers: - - event: NewOwner(indexed bytes32,indexed bytes32,address) - handler: handleNewOwner - - event: Transfer(indexed bytes32,address) - handler: handleTransfer - - event: NewResolver(indexed bytes32,address) - handler: handleNewResolver - - event: NewTTL(indexed bytes32,uint64) - handler: handleNewTTL - file: ./src/ens-registry.ts - - kind: ethereum/contract - name: ENSRegistryOld - network: mainnet - source: - address: '0x314159265dd8dbb310642f98f50c066173c1259b' - abi: EnsRegistry - startBlock: 3327417 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: EnsRegistry - file: ./abis/EnsRegistry.json - eventHandlers: - - event: NewOwner(indexed bytes32,indexed bytes32,address) - handler: handleNewOwnerOldRegistry - - event: Transfer(indexed bytes32,address) - handler: handleTransferOldRegistry - - event: NewResolver(indexed bytes32,address) - handler: handleNewResolverOldRegistry - - event: NewTTL(indexed bytes32,uint64) - handler: handleNewTTLOldRegistry - file: ./src/ens-registry.ts - - kind: ethereum/contract - name: BaseRegistrar - network: mainnet - source: - address: '0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85' - abi: BaseRegistrar - startBlock: 9380410 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/eth-registrar.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: BaseRegistrar - file: ./abis/BaseRegistrar.json - eventHandlers: - - event: NameRegistered(indexed uint256,indexed address,uint256) - handler: handleNameRegistered - - event: NameRenewed(indexed uint256,uint256) - handler: handleNameRenewed - - kind: ethereum/contract - name: Resolver2 - network: mainnet - source: - abi: Resolver - address: '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41' - startBlock: 9412610 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: Resolver1 - network: mainnet - source: - abi: Resolver - address: '0xDaaF96c344f63131acadD0Ea35170E7892d3dfBA' - startBlock: 9380387 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: OldResolver2 - network: mainnet - source: - abi: Resolver - address: '0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8' - startBlock: 8659893 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: OldResolver1 - network: mainnet - source: - abi: Resolver - address: '0x1da022710dF5002339274AaDEe8D58218e9D6AB5' - startBlock: 3648359 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/resolver.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: Resolver - file: ./abis/PublicResolver.json - eventHandlers: - - event: AddrChanged(indexed bytes32,address) - handler: handleAddrChanged - - event: VersionChanged(indexed bytes32,uint64) - handler: handleVersionChanged - - kind: ethereum/contract - name: ReverseRegistrar - network: mainnet - source: - abi: ReverseRegistrar - address: '0x084b1c3C81545d370f3634392De611CaaBFf8148' - startBlock: 9380506 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/reverse-registrar.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: ReverseRegistrar - file: ./abis/ReverseRegistrar.json - callHandlers: - - function: setName(string) - handler: handleSetName - - kind: ethereum/contract - name: EthRegistrarController - network: mainnet - source: - address: '0x82994379B1Ec951C8E001DFceC2A7Ce8f4f39b97' - abi: EthRegistrarController - startBlock: 11787529 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/eth-registrar.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: EthRegistrarController - file: ./abis/EthRegistrarController.json - eventHandlers: - - event: NameRegistered(string,indexed bytes32,indexed address,uint256,uint256) - handler: handleNameRegisteredByController - - event: NameRenewed(string,indexed bytes32,uint256,uint256) - handler: handleNameRenewedByController - - kind: ethereum/contract - name: EthRegistrarControllerOld - network: mainnet - source: - address: '0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5' - abi: EthRegistrarControllerOld - startBlock: 9380471 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - file: ./src/eth-registrar.ts - entities: - - AirAccount - - AirBlock - - AirMeta - - AirEntityCounter - - AirToken - - AirDomain - - AirDomainTransferTransaction - - AirDomainOwnerChangedTransaction - - AirDomainNewResolverTransaction - - AirDomainNewTTLTransaction - - AirResolver - - AirAddrChanged - - AirNameRegisteredTransaction - - AirNameRenewedTransaction - - AirPrimaryDomainTransaction - abis: - - name: EthRegistrarControllerOld - file: ./abis/EthRegistrarControllerOld.json - eventHandlers: - - event: NameRegistered(string,indexed bytes32,indexed address,uint256,uint256) - handler: handleNameRegisteredByControllerOld - - event: NameRenewed(string,indexed bytes32,uint256,uint256) - handler: handleNameRenewedByController diff --git a/ens/tests/ens-registry-utils.ts b/ens/tests/ens-registry-utils.ts index d087e296..5f56223f 100644 --- a/ens/tests/ens-registry-utils.ts +++ b/ens/tests/ens-registry-utils.ts @@ -1,12 +1,14 @@ import { newMockEvent } from "matchstick-as" -import { ethereum, Address, Bytes, BigInt } from "@graphprotocol/graph-ts" +import { ethereum, Address, Bytes, BigInt, ens } from "@graphprotocol/graph-ts" import { getTransactionHash } from "./common-utils" +import { BIG_INT_ZERO } from "../modules/airstack/common/index" import { NewOwner as NewOwnerEvent, NewResolver as NewResolverEvent, NewTTL as NewTTLEvent, Transfer as TransferEvent } from "../generated/EnsRegistry/EnsRegistry" +import { AirDomain } from "../generated/schema" export function getHandleNewOwnerEvent(): NewOwnerEvent { return createHandleNewOwnerEvent() @@ -24,6 +26,24 @@ export function getHandleNewTTLEvent(): NewTTLEvent { return createHandleNewTTLEvent() } +export function getHandleNewTTLEvent1(): NewTTLEvent { + let event = changetype(newMockEvent()) + event.block.number = BigInt.fromI32(10098239); + event.block.timestamp = BigInt.fromI32(2879823); + event.block.hash = Bytes.fromHexString("0x701633854b23364112e8528a85254a039abf8d1d81d629f88426196819e0b0b5") + event.transaction.hash = getTransactionHash() + event.logIndex = BigInt.fromI32(77) + + event.parameters = new Array() + event.parameters.push( + new ethereum.EventParam("node", ethereum.Value.fromFixedBytes(Bytes.fromHexString("0xad3988d642ba25a8ca9d8889e0cfd6c550060e35455c55c936be87f9cfb97407") as Bytes)) + ) + event.parameters.push( + new ethereum.EventParam("ttl", ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(99))) + ) + return event +} + function createHandleNewOwnerEvent(): NewOwnerEvent { let event = changetype(newMockEvent()) event.block.number = BigInt.fromI32(10098239); @@ -37,7 +57,7 @@ function createHandleNewOwnerEvent(): NewOwnerEvent { new ethereum.EventParam("node", ethereum.Value.fromFixedBytes(Bytes.fromHexString("0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2") as Bytes)) ) event.parameters.push( - new ethereum.EventParam("label", ethereum.Value.fromFixedBytes(Bytes.fromHexString("0xa4757f81c024f155983881ff8228a21c098ecc3708b3b0ba64b8d605d5e9849b") as Bytes)) + new ethereum.EventParam("label", ethereum.Value.fromFixedBytes(Bytes.fromHexString("0x99726e0d8b407cf2176c79d70375d2c906063193e0a0951bf2aa26e62bfadaab") as Bytes)) ) event.parameters.push( new ethereum.EventParam("owner", ethereum.Value.fromAddress(Address.fromString("0x084b1c3c81545d370f3634392de611caabff8148") as Address)) @@ -97,4 +117,42 @@ function createHandleNewTTLEvent(): NewTTLEvent { new ethereum.EventParam("ttl", ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(100))) ) return event +} + +const ROOT_NODE = '0x0000000000000000000000000000000000000000000000000000000000000000' + +export function getNameByLabelHashAndNode(labelHash: Bytes, node: Bytes): string { + let labelName = ens.nameByHash(labelHash.toHexString()); + if (labelName === null) { + labelName = '[' + labelHash.toHexString().slice(2) + ']'; + } + // creating name from labelName and parentName + let name: string | null; + let parentName: string | null; + if (node.toHexString() == ROOT_NODE) { + name = labelName; + } else { + let parent = AirDomain.load(node.toHexString()); + if (parent != null) { + parentName = parent.name; + } else { + parentName = ""; + } + name = labelName + "." + parentName!; + } + return name; +} + +export function createParentDomain(parentDomainId: string): void { + let entity = new AirDomain(parentDomainId); + entity.subdomainCount = BIG_INT_ZERO; + entity.name = "eth"; + entity.owner = "1-472668903"; + entity.tokenAddress = "1-472668903"; + entity.isPrimary = false; + entity.expiryTimestamp = BIG_INT_ZERO; + entity.registrationCost = BIG_INT_ZERO; + entity.createdAt = "1-472668903"; + entity.lastUpdatedBlock = "1-472668903"; + entity.save(); } \ No newline at end of file diff --git a/ens/tests/ens-registry.test.ts b/ens/tests/ens-registry.test.ts index f8102535..f10caa9c 100644 --- a/ens/tests/ens-registry.test.ts +++ b/ens/tests/ens-registry.test.ts @@ -4,10 +4,11 @@ import { test, clearStore, afterEach, + logStore, } from "matchstick-as/assembly/index" -import { crypto, ens, BigInt } from "@graphprotocol/graph-ts" -import { getHandleNewTTLEvent, getHandleNewResolverEvent, getHandleTransferEvent, getHandleNewOwnerEvent } from "./ens-registry-utils" -import { handleNewResolver, handleTransferOldRegistry, handleTransfer, handleNewOwnerOldRegistry, handleNewOwner, handleNewTTL, handleNewTTLOldRegistry } from "../src/ens-registry" +import { crypto, ens, BigInt, Bytes, log } from "@graphprotocol/graph-ts" +import { getHandleNewTTLEvent1, createParentDomain, getNameByLabelHashAndNode, getHandleNewTTLEvent, getHandleNewResolverEvent, getHandleTransferEvent, getHandleNewOwnerEvent } from "./ens-registry-utils" +import { handleNewResolver, handleTransferOldRegistry, handleTransfer, handleNewOwnerOldRegistry, handleNewOwner, handleNewTTL, handleNewTTLOldRegistry, handleNewResolverOldRegistry } from "../src/ens-registry" import { ETHEREUM_MAINNET_ID, ZERO_ADDRESS } from "../modules/airstack/domain-name/utils" import { TOKEN_ADDRESS_ENS } from "../src/utils"; import { BIGINT_ONE, BIG_INT_ZERO } from "../modules/airstack/common" @@ -18,12 +19,15 @@ describe("Unit tests for ens registry handlers", () => { }) test("Test handleNewOwner", () => { + // prep + let parentDomainId = "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2"; + createParentDomain(parentDomainId); + // call event handler let event = getHandleNewOwnerEvent(); handleNewOwner(event) // assert here let domainId = crypto.keccak256(event.params.node.concat(event.params.label)).toHex(); let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); - let parentDomainId = event.params.node.toHexString(); // assert here // AirMeta assert.fieldEquals("AirMeta", "AIR_META", "name", "ens") @@ -31,16 +35,43 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") - // AirDomain - assert.fieldEquals("AirDomain", parentDomainId, "subdomainCount", BIG_INT_ZERO.toString()); + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "true"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // ReverseRegistrar let labelName = ens.nameByHash(event.params.label.toHexString()); + let name = getNameByLabelHashAndNode(event.params.label, event.params.node); + let reverseRegistrarId = crypto.keccak256(Bytes.fromUTF8(name)).toHexString(); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "id", reverseRegistrarId); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "name", name); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "domain", domainId); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "createdAt", blockId); + // AirAccount + let ownerAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "id", ownerAccountId); + assert.fieldEquals("AirAccount", ownerAccountId, "address", event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirDomain + assert.fieldEquals("AirDomain", parentDomainId, "subdomainCount", BIGINT_ONE.toString()); assert.fieldEquals("AirDomain", domainId, "labelName", labelName!); assert.fieldEquals("AirDomain", domainId, "owner", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString())); assert.fieldEquals("AirDomain", domainId, "parent", parentDomainId); assert.fieldEquals("AirDomain", domainId, "labelHash", event.params.label.toHexString()); assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "true"); assert.fieldEquals("AirDomain", domainId, "tokenId", BigInt.fromUnsignedBytes(event.params.label).toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); assert.fieldEquals("AirDomain", domainId, "createdAt", blockId); assert.fieldEquals("AirDomain", domainId, "registrationCost", BIG_INT_ZERO.toString()); assert.fieldEquals("AirDomain", domainId, "expiryTimestamp", BIG_INT_ZERO.toString()); @@ -58,12 +89,15 @@ describe("Unit tests for ens registry handlers", () => { }) test("Test handleNewOwnerOldRegistry", () => { + // prep + let parentDomainId = "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2"; + createParentDomain(parentDomainId); + // call event handler let event = getHandleNewOwnerEvent(); handleNewOwnerOldRegistry(event) // assert here let domainId = crypto.keccak256(event.params.node.concat(event.params.label)).toHex(); let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); - let parentDomainId = event.params.node.toHexString(); // assert here // AirMeta assert.fieldEquals("AirMeta", "AIR_META", "name", "ens") @@ -71,16 +105,43 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") - // AirDomain - assert.fieldEquals("AirDomain", parentDomainId, "subdomainCount", BIG_INT_ZERO.toString()); + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "false"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // ReverseRegistrar let labelName = ens.nameByHash(event.params.label.toHexString()); + let name = getNameByLabelHashAndNode(event.params.label, event.params.node); + let reverseRegistrarId = crypto.keccak256(Bytes.fromUTF8(name)).toHexString(); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "id", reverseRegistrarId); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "name", name); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "domain", domainId); + assert.fieldEquals("ReverseRegistrar", reverseRegistrarId, "createdAt", blockId); + // AirAccount + let ownerAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "id", ownerAccountId); + assert.fieldEquals("AirAccount", ownerAccountId, "address", event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_OWNER_CHANGED_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirDomain + assert.fieldEquals("AirDomain", parentDomainId, "subdomainCount", BIGINT_ONE.toString()); assert.fieldEquals("AirDomain", domainId, "labelName", labelName!); assert.fieldEquals("AirDomain", domainId, "owner", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString())); assert.fieldEquals("AirDomain", domainId, "parent", parentDomainId); assert.fieldEquals("AirDomain", domainId, "labelHash", event.params.label.toHexString()); assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "false"); assert.fieldEquals("AirDomain", domainId, "tokenId", BigInt.fromUnsignedBytes(event.params.label).toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); assert.fieldEquals("AirDomain", domainId, "createdAt", blockId); assert.fieldEquals("AirDomain", domainId, "registrationCost", BIG_INT_ZERO.toString()); assert.fieldEquals("AirDomain", domainId, "expiryTimestamp", BIG_INT_ZERO.toString()); @@ -110,6 +171,32 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "true"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirAccount + let zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + let newOwnerAddress = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "id", newOwnerAddress); + assert.fieldEquals("AirAccount", newOwnerAddress, "address", event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_TRANSFER_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_TRANSFER_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirDomain + assert.fieldEquals("AirDomain", domainId, "owner", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString())); // AirDomainTransferTransaction let domainOwnerChangedEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); assert.fieldEquals("AirDomainTransferTransaction", domainOwnerChangedEntityId, "from", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); @@ -121,7 +208,6 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirDomainTransferTransaction", domainOwnerChangedEntityId, "index", BIGINT_ONE.toString()); }) - test("Test handleTransferOldRegistry", () => { let event = getHandleTransferEvent(); handleTransferOldRegistry(event) @@ -135,6 +221,32 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "false"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirAccount + let zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + let newOwnerAddress = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "id", newOwnerAddress); + assert.fieldEquals("AirAccount", newOwnerAddress, "address", event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_TRANSFER_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_TRANSFER_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirDomain + assert.fieldEquals("AirDomain", domainId, "owner", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString())); // AirDomainTransferTransaction let domainOwnerChangedEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); assert.fieldEquals("AirDomainTransferTransaction", domainOwnerChangedEntityId, "from", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); @@ -160,10 +272,38 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "true"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirResolver + assert.fieldEquals("AirResolver", resolverId, "id", resolverId); + assert.fieldEquals("AirResolver", resolverId, "address", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.resolver.toHexString())); + assert.fieldEquals("AirResolver", resolverId, "domain", domainId); + // AirAccount + let zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + let newOwnerAddress = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.resolver.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "id", newOwnerAddress); + assert.fieldEquals("AirAccount", newOwnerAddress, "address", event.params.resolver.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); // AirDomain assert.fieldEquals("AirDomain", domainId, "resolver", resolverId); assert.fieldEquals("AirDomain", domainId, "subdomainCount", BIG_INT_ZERO.toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); // AirDomainNewResolverTransaction let domainNewResolverEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); assert.fieldEquals("AirDomainNewResolverTransaction", domainNewResolverEntityId, "previousResolver", "null"); @@ -177,7 +317,7 @@ describe("Unit tests for ens registry handlers", () => { test("Test handleNewResolverOldRegistry", () => { let event = getHandleNewResolverEvent(); - handleNewResolver(event) + handleNewResolverOldRegistry(event) // assert here let domainId = event.params.node.toHexString(); let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); @@ -189,10 +329,38 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "false"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirResolver + assert.fieldEquals("AirResolver", resolverId, "id", resolverId); + assert.fieldEquals("AirResolver", resolverId, "address", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.resolver.toHexString())); + assert.fieldEquals("AirResolver", resolverId, "domain", domainId); + // AirAccount + let zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + let newOwnerAddress = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.resolver.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "id", newOwnerAddress); + assert.fieldEquals("AirAccount", newOwnerAddress, "address", event.params.resolver.toHexString()); + assert.fieldEquals("AirAccount", newOwnerAddress, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_NEW_RESOLVER_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); // AirDomain assert.fieldEquals("AirDomain", domainId, "resolver", resolverId); assert.fieldEquals("AirDomain", domainId, "subdomainCount", BIG_INT_ZERO.toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); // AirDomainNewResolverTransaction let domainNewResolverEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); assert.fieldEquals("AirDomainNewResolverTransaction", domainNewResolverEntityId, "previousResolver", "null"); @@ -217,18 +385,88 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "true"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirAccount + let zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); // AirDomain - assert.fieldEquals("AirDomain", domainId, "ttl", event.params.ttl.toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "extras", "[0xad3988d642ba25a8ca9d8889e0cfd6c550060e35455c55c936be87f9cfb97407-ttl]"); + // AirExtra + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "id", domainId.concat("-").concat('ttl')); + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "name", "ttl"); + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "value", event.params.ttl.toString()); // AirDomainNewTTLTransaction - let domainNewResolverEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "oldTTL", "null"); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "newTTL", event.params.ttl.toString()); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "transactionHash", event.transaction.hash.toHexString()); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "block", blockId); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "tokenId", "null"); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "domain", domainId); - assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "index", BIGINT_ONE.toString()); + let domainNewTTLEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "oldTTL", "null"); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "newTTL", event.params.ttl.toString()); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "transactionHash", event.transaction.hash.toHexString()); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "block", blockId); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "tokenId", "null"); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "domain", domainId); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "index", BIGINT_ONE.toString()); + // testing multiple extra events in one test + let event1 = getHandleNewTTLEvent1(); + handleNewTTL(event1) + // assert here + // AirMeta + assert.fieldEquals("AirMeta", "AIR_META", "name", "ens") + assert.fieldEquals("AirMeta", "AIR_META", "slug", "ens-v1") + assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") + assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") + assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event1.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event1.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event1.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "true"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirAccount + zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + // AirEntityCounter + airEntityCounterId = "AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "2"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirDomain + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "extras", "[0xad3988d642ba25a8ca9d8889e0cfd6c550060e35455c55c936be87f9cfb97407-ttl]"); + // AirExtra + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "id", domainId.concat("-").concat('ttl')); + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "name", "ttl"); + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "value", event1.params.ttl.toString()); + // AirDomainNewTTLTransaction + domainNewTTLEntityId = event1.transaction.hash.toHexString().concat("-").concat(event1.block.number.toString()).concat("-").concat(event1.logIndex.toString()); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "oldTTL", "100"); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "newTTL", event1.params.ttl.toString()); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "transactionHash", event1.transaction.hash.toHexString()); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "block", blockId); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "tokenId", "null"); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "domain", domainId); + assert.fieldEquals("AirDomainNewTTLTransaction", domainNewTTLEntityId, "index", BIGINT_ONE.plus(BIGINT_ONE).toString()); }) test("Test handleNewTTLOldRegistry", () => { @@ -244,9 +482,33 @@ describe("Unit tests for ens registry handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // IsMigratedMapping + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "id", domainId); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "isMigrated", "false"); + assert.fieldEquals("DomainVsIsMigratedMapping", domainId, "lastUpdatedAt", blockId); + // AirAccount + let zeroAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "id", zeroAccountId); + assert.fieldEquals("AirAccount", zeroAccountId, "address", ZERO_ADDRESS); + assert.fieldEquals("AirAccount", zeroAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_DOMAIN_NEW_TTL_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); // AirDomain - assert.fieldEquals("AirDomain", domainId, "ttl", event.params.ttl.toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "extras", "[0xad3988d642ba25a8ca9d8889e0cfd6c550060e35455c55c936be87f9cfb97407-ttl]"); + // AirExtra + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "id", domainId.concat("-").concat('ttl')); + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "name", "ttl"); + assert.fieldEquals("AirExtra", domainId.concat("-").concat('ttl'), "value", event.params.ttl.toString()); // AirDomainNewTTLTransaction let domainNewResolverEntityId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); assert.fieldEquals("AirDomainNewTTLTransaction", domainNewResolverEntityId, "oldTTL", "null"); diff --git a/ens/tests/eth-registrar.test.ts b/ens/tests/eth-registrar.test.ts index 377d7256..6d031f1a 100644 --- a/ens/tests/eth-registrar.test.ts +++ b/ens/tests/eth-registrar.test.ts @@ -8,9 +8,10 @@ import { import { ByteArray, crypto, Bytes } from "@graphprotocol/graph-ts" import { handleNameRenewedByController, handleNameRegistered, handleNameRenewed, handleNameRegisteredByControllerOld, handleNameRegisteredByController } from "../src/eth-registrar" import { getHandleNameRenewedByControllerEvent, getHandleNameRegisteredEvent, getHandleNameRenewedEvent, getHandleNameRegisteredByControllerOldEvent, getHandleNameRegisteredByControllerEvent } from "./eth-registrar-utils" -import { ETHEREUM_MAINNET_ID, ZERO_ADDRESS, byteArrayFromHex, uint256ToByteArray } from "../modules/airstack/domain-name/utils" +import { ETHEREUM_MAINNET_ID, ZERO_ADDRESS } from "../modules/airstack/domain-name/utils" +import { uint256ToByteArray, byteArrayFromHex } from "../src/utils" import { BIGINT_ONE } from "../modules/airstack/common" -import { AirDomain, ReverseRegistrar } from "../generated/schema" +import { AirDomain } from "../generated/schema" const rootNode: ByteArray = byteArrayFromHex("93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"); @@ -32,17 +33,39 @@ describe("Unit tests for eth registrar handlers", () => { assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // AirAccount + let ownerAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "id", ownerAccountId); + assert.fieldEquals("AirAccount", ownerAccountId, "address", event.params.owner.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_NAME_REGISTERED_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_NAME_REGISTERED_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirToken + let airTokenId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirToken", airTokenId, "id", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); + assert.fieldEquals("AirToken", airTokenId, "address", ZERO_ADDRESS); // AirDomain assert.fieldEquals("AirDomain", domainId, "expiryTimestamp", event.params.expires.toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "paymentToken", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); // AirNameRegisteredTransaction let nameRegisteredId = event.transaction.hash.toHexString().concat("-").concat(event.block.number.toString()).concat("-").concat(event.logIndex.toString()); + assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "paymentToken", airTokenId); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "block", blockId); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "transactionHash", event.transaction.hash.toHexString()); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "tokenId", "null"); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "domain", domainId); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "index", BIGINT_ONE.toString()); - assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "cost", event.transaction.value.toString()); + assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "cost", "null"); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "registrant", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.owner.toHexString())); assert.fieldEquals("AirNameRegisteredTransaction", nameRegisteredId, "expiryTimestamp", event.params.expires.toString()); }) @@ -54,11 +77,38 @@ describe("Unit tests for eth registrar handlers", () => { let domainId = crypto.keccak256(rootNode.concat(uint256ToByteArray(event.params.id))).toHex(); let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); // assert here + // AirMeta + assert.fieldEquals("AirMeta", "AIR_META", "name", "ens") + assert.fieldEquals("AirMeta", "AIR_META", "slug", "ens-v1") + assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") + assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") + assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // AirAccount + let ownerAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.transaction.from.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "id", ownerAccountId); + assert.fieldEquals("AirAccount", ownerAccountId, "address", event.transaction.from.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_NAME_RENEWED_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_NAME_RENEWED_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirToken + let airTokenId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirToken", airTokenId, "id", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); + assert.fieldEquals("AirToken", airTokenId, "address", ZERO_ADDRESS); // AirDomain assert.fieldEquals("AirDomain", domainId, "expiryTimestamp", event.params.expires.toString()); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); // AirNameRenewedTransaction let nameRenewedId = event.transaction.hash.toHexString().concat("-").concat(domainId); + assert.fieldEquals("AirNameRenewedTransaction", nameRenewedId, "paymentToken", airTokenId); assert.fieldEquals("AirNameRenewedTransaction", nameRenewedId, "block", blockId); assert.fieldEquals("AirNameRenewedTransaction", nameRenewedId, "transactionHash", event.transaction.hash.toHexString()); assert.fieldEquals("AirNameRenewedTransaction", nameRenewedId, "tokenId", "null"); @@ -77,10 +127,15 @@ describe("Unit tests for eth registrar handlers", () => { let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); let reverseRegistrarId = crypto.keccak256(Bytes.fromUTF8(event.params.name.concat(".eth"))).toHexString(); // assert here + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); // AirDomain assert.fieldEquals("AirDomain", domainId, "registrationCost", event.params.cost.toString()); assert.fieldEquals("AirDomain", domainId, "paymentToken", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); assert.fieldEquals("AirDomain", domainId, "labelName", event.params.name); assert.fieldEquals("AirDomain", domainId, "name", event.params.name.concat(".eth")); // ReverseRegistrar @@ -99,10 +154,15 @@ describe("Unit tests for eth registrar handlers", () => { let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); let reverseRegistrarId = crypto.keccak256(Bytes.fromUTF8(event.params.name.concat(".eth"))).toHexString(); // assert here + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); // AirDomain assert.fieldEquals("AirDomain", domainId, "registrationCost", event.params.cost.toString()); assert.fieldEquals("AirDomain", domainId, "paymentToken", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); assert.fieldEquals("AirDomain", domainId, "labelName", event.params.name); assert.fieldEquals("AirDomain", domainId, "name", event.params.name.concat(".eth")); // ReverseRegistrar @@ -121,9 +181,30 @@ describe("Unit tests for eth registrar handlers", () => { let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); let reverseRegistrarId = crypto.keccak256(Bytes.fromUTF8(event.params.name.concat(".eth"))).toHexString(); // assert here + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // AirAccount + let ownerAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.transaction.from.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "id", ownerAccountId); + assert.fieldEquals("AirAccount", ownerAccountId, "address", event.transaction.from.toHexString()); + assert.fieldEquals("AirAccount", ownerAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_NAME_RENEWED_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_NAME_RENEWED_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); + // AirToken + let airTokenId = ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS); + assert.fieldEquals("AirToken", airTokenId, "id", ETHEREUM_MAINNET_ID.concat("-").concat(ZERO_ADDRESS)); + assert.fieldEquals("AirToken", airTokenId, "address", ZERO_ADDRESS); // AirDomain assert.fieldEquals("AirDomain", domainId, "registrationCost", "0"); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId); + assert.fieldEquals("AirDomain", domainId, "expiryTimestamp", event.params.expires.toString()); + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId); assert.fieldEquals("AirDomain", domainId, "labelName", event.params.name); assert.fieldEquals("AirDomain", domainId, "name", event.params.name.concat(".eth")); // AirNameRenewedTransaction diff --git a/ens/tests/resolver-utils.ts b/ens/tests/resolver-utils.ts index 8e8404cd..b40fafce 100644 --- a/ens/tests/resolver-utils.ts +++ b/ens/tests/resolver-utils.ts @@ -2,6 +2,8 @@ import { newMockEvent } from "matchstick-as" import { ethereum, Address, Bytes, BigInt } from "@graphprotocol/graph-ts" import { AddrChanged, VersionChanged } from "../generated/Resolver1/Resolver" import { getTransactionHash } from "./common-utils" +import { AirDomain } from "../generated/schema" +import { BIG_INT_ZERO } from "../modules/airstack/common/index" export function getHandleAddrChangedEvent(): AddrChanged { return createHandleAddrChangedEvent( @@ -57,3 +59,17 @@ export function createHandleVersionChangedEvent( return event } +export function createAirDomain(domainId: string): AirDomain { + let entity = new AirDomain(domainId); + entity.subdomainCount = BIG_INT_ZERO; + entity.name = "eth"; + entity.owner = "1-472668903"; + entity.tokenAddress = "1-472668903"; + entity.isPrimary = false; + entity.expiryTimestamp = BIG_INT_ZERO; + entity.registrationCost = BIG_INT_ZERO; + entity.createdAt = "1-472668903"; + entity.lastUpdatedBlock = "1-472668903"; + entity.save(); + return entity as AirDomain; +} \ No newline at end of file diff --git a/ens/tests/resolver.test.ts b/ens/tests/resolver.test.ts index 6d544b6b..007ebd3d 100644 --- a/ens/tests/resolver.test.ts +++ b/ens/tests/resolver.test.ts @@ -6,8 +6,9 @@ import { afterEach, } from "matchstick-as/assembly/index" import { handleAddrChanged, handleVersionChanged } from "../src/resolver" -import { getHandleAddrChangedEvent, getHandleVersionChangedEvent } from "./resolver-utils" +import { createAirDomain, getHandleAddrChangedEvent, getHandleVersionChangedEvent } from "./resolver-utils" import { ETHEREUM_MAINNET_ID } from "../modules/airstack/domain-name/utils" +import { log } from "@graphprotocol/graph-ts" describe("Unit tests for resolver handlers", () => { afterEach(() => { @@ -15,6 +16,9 @@ describe("Unit tests for resolver handlers", () => { }) test("Test handleAddrChanged", () => { + let domain = createAirDomain("0xea6cc843bbe16a18e678f7050e9183f09ccf900a3b4b74de12dae9ce1f95dff4"); + domain.resolver = "0x314159265dd8dbb310642f98f50c066173c1259b-0xea6cc843bbe16a18e678f7050e9183f09ccf900a3b4b74de12dae9ce1f95dff4"; + domain.save(); let event = getHandleAddrChangedEvent(); handleAddrChanged(event) // assert here @@ -22,45 +26,74 @@ describe("Unit tests for resolver handlers", () => { let resolverId = event.address.toHexString().concat("-").concat(event.params.node.toHexString()) let domainId = event.params.node.toHexString(); let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); - // AirMeta assert.fieldEquals("AirMeta", "AIR_META", "name", "ens") assert.fieldEquals("AirMeta", "AIR_META", "slug", "ens-v1") assert.fieldEquals("AirMeta", "AIR_META", "version", "v1") assert.fieldEquals("AirMeta", "AIR_META", "schemaVersion", "1.0.0") assert.fieldEquals("AirMeta", "AIR_META", "network", "MAINNET") - // AirResolver + assert.fieldEquals("AirResolver", resolverId, "id", resolverId) assert.fieldEquals("AirResolver", resolverId, "domain", domainId) - + assert.fieldEquals("AirResolver", resolverId, "address", ETHEREUM_MAINNET_ID.concat("-").concat(event.address.toHexString())) + assert.fieldEquals("AirResolver", resolverId, "resolvedAddress", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.a.toHexString())) + // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId); + assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()); + assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()); + assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()); + // AirAccount + let resolverAddressAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.params.a.toHexString()); + assert.fieldEquals("AirAccount", resolverAddressAccountId, "id", resolverAddressAccountId); + assert.fieldEquals("AirAccount", resolverAddressAccountId, "address", event.params.a.toHexString()); + assert.fieldEquals("AirAccount", resolverAddressAccountId, "createdAt", blockId); + // AirEntityCounter + let airEntityCounterId = "AIR_ADDR_CHANGED_ENTITY_COUNTER"; + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "id", "AIR_ADDR_CHANGED_ENTITY_COUNTER"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "count", "1"); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "createdAt", blockId); + assert.fieldEquals("AirEntityCounter", airEntityCounterId, "lastUpdatedAt", blockId); // AirDomain - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId) - - // getOrCreateAirAddrChanged - assert.fieldEquals("AirAddrChanged", addrChangedId, "resolver", resolverId) - assert.fieldEquals("AirAddrChanged", addrChangedId, "block", blockId) - assert.fieldEquals("AirAddrChanged", addrChangedId, "transactionHash", event.transaction.hash.toHexString()) - assert.fieldEquals("AirAddrChanged", addrChangedId, "previousResolvedAddress", "null") - assert.fieldEquals("AirAddrChanged", addrChangedId, "newResolvedAddress", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.a.toHexString())) - assert.fieldEquals("AirAddrChanged", addrChangedId, "domain", domainId) - assert.fieldEquals("AirAddrChanged", addrChangedId, "tokenId", "null",) - assert.fieldEquals("AirAddrChanged", addrChangedId, "index", "1") + assert.fieldEquals("AirDomain", domainId, "id", domainId) + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId) + assert.fieldEquals("AirDomain", domainId, "resolvedAddress", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.a.toHexString())) + // AirResolvedAddressChanged + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "resolver", resolverId) + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "block", blockId) + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "transactionHash", event.transaction.hash.toHexString()) + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "previousResolvedAddress", "null") + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "newResolvedAddress", ETHEREUM_MAINNET_ID.concat("-").concat(event.params.a.toHexString())) + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "domain", domainId) + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "tokenId", "null",) + assert.fieldEquals("AirResolvedAddressChanged", addrChangedId, "index", "1") }) test("test handleVersionChanged", () => { + let domain = createAirDomain("0xea6cc843bbe16a18e678f7050e9183f09ccf900a3b4b74de12dae9ce1f95dff4"); + domain.resolver = "0x314159265dd8dbb310642f98f50c066173c1259b-0xea6cc843bbe16a18e678f7050e9183f09ccf900a3b4b74de12dae9ce1f95dff4"; + domain.save(); let event = getHandleVersionChangedEvent(); handleVersionChanged(event) // assert here let blockId = ETHEREUM_MAINNET_ID.concat("-").concat(event.block.number.toString()); // AirBlock + assert.fieldEquals("AirBlock", blockId, "id", blockId) assert.fieldEquals("AirBlock", blockId, "number", event.block.number.toString()) assert.fieldEquals("AirBlock", blockId, "hash", event.block.hash.toHexString()) assert.fieldEquals("AirBlock", blockId, "timestamp", event.block.timestamp.toString()) + // AirAccount + let resolverAddressAccountId = ETHEREUM_MAINNET_ID.concat("-").concat(event.address.toHexString()); + assert.fieldEquals("AirAccount", resolverAddressAccountId, "id", resolverAddressAccountId) + assert.fieldEquals("AirAccount", resolverAddressAccountId, "address", event.address.toHexString()) + assert.fieldEquals("AirAccount", resolverAddressAccountId, "createdAt", blockId) // AirDomain let domainId = event.params.node.toHexString(); - assert.fieldEquals("AirDomain", domainId, "lastBlock", blockId) + assert.fieldEquals("AirDomain", domainId, "id", domainId) + assert.fieldEquals("AirDomain", domainId, "resolvedAddress", "null") + assert.fieldEquals("AirDomain", domainId, "lastUpdatedBlock", blockId) // AirResolver let resolverId = event.address.toHexString().concat("-").concat(event.params.node.toHexString()) + assert.fieldEquals("AirResolver", resolverId, "id", resolverId) assert.fieldEquals("AirResolver", resolverId, "domain", domainId) assert.fieldEquals("AirResolver", resolverId, "address", ETHEREUM_MAINNET_ID.concat("-").concat(event.address.toHexString())) })