From 7fde94f855f24c44dea28f07726536d88c593cd1 Mon Sep 17 00:00:00 2001 From: Eric Lin <40213852eric@gmail.com> Date: Sun, 2 Jul 2023 12:56:51 +0800 Subject: [PATCH] Initial commit --- abis/ERC6551RegistryAndReadCall.json | 245 ++++++++++++++++++ networks.json | 8 + package.json | 18 ++ schema.graphql | 20 ++ src/erc-6551-registry-and-read-call.ts | 36 +++ subgraph.yaml | 27 ++ .../erc-6551-registry-and-read-call-utils.ts | 67 +++++ tests/erc-6551-registry-and-read-call.test.ts | 94 +++++++ tsconfig.json | 4 + 9 files changed, 519 insertions(+) create mode 100644 abis/ERC6551RegistryAndReadCall.json create mode 100644 networks.json create mode 100644 package.json create mode 100644 schema.graphql create mode 100644 src/erc-6551-registry-and-read-call.ts create mode 100644 subgraph.yaml create mode 100644 tests/erc-6551-registry-and-read-call-utils.ts create mode 100644 tests/erc-6551-registry-and-read-call.test.ts create mode 100644 tsconfig.json diff --git a/abis/ERC6551RegistryAndReadCall.json b/abis/ERC6551RegistryAndReadCall.json new file mode 100644 index 0000000..06a0c8c --- /dev/null +++ b/abis/ERC6551RegistryAndReadCall.json @@ -0,0 +1,245 @@ +[ + { + "inputs": [ + { + "internalType": "address payable", + "name": "gatewayAddress", + "type": "address" + }, + { "internalType": "string", "name": "feePayerAddress", "type": "string" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "InitializationFailed", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "implementation", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "salt", + "type": "uint256" + } + ], + "name": "AccountCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "requestAddress", + "type": "address" + } + ], + "name": "ReceivedData", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + }, + { "internalType": "uint256", "name": "chainId", "type": "uint256" }, + { "internalType": "address", "name": "tokenContract", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "bytes", "name": "initData", "type": "bytes" } + ], + "name": "abiPacketAccount", + "outputs": [{ "internalType": "bytes", "name": "packet", "type": "bytes" }], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + }, + { "internalType": "uint256", "name": "chainId", "type": "uint256" }, + { "internalType": "address", "name": "tokenContract", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "uint256", "name": "salt", "type": "uint256" } + ], + "name": "account", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "nftContract", "type": "address" }, + { "internalType": "uint256", "name": "nftId", "type": "uint256" }, + { "internalType": "uint256", "name": "chain_id", "type": "uint256" }, + { "internalType": "address", "name": "tba", "type": "address" } + ], + "name": "addTbaAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + }, + { "internalType": "uint256", "name": "chainId", "type": "uint256" }, + { "internalType": "address", "name": "tokenContract", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "bytes", "name": "initData", "type": "bytes" } + ], + "name": "createAccount", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "gatewayContract", + "outputs": [ + { "internalType": "contract IGateway", "name": "", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint64", "name": "destGasLimit", "type": "uint64" }, + { "internalType": "uint64", "name": "destGasPrice", "type": "uint64" }, + { "internalType": "uint64", "name": "ackGasLimit", "type": "uint64" }, + { "internalType": "uint64", "name": "ackGasPrice", "type": "uint64" }, + { "internalType": "uint128", "name": "relayerFees", "type": "uint128" }, + { "internalType": "uint8", "name": "ackType", "type": "uint8" }, + { "internalType": "bool", "name": "isReadCall", "type": "bool" }, + { "internalType": "bytes", "name": "asmAddress", "type": "bytes" } + ], + "name": "getRequestMetadata", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "nftContract", "type": "address" }, + { "internalType": "uint256", "name": "nftId", "type": "uint256" } + ], + "name": "getTbas", + "outputs": [ + { "internalType": "address[]", "name": "", "type": "address[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "bool", "name": "", "type": "bool" }, + { "internalType": "bytes", "name": "execData", "type": "bytes" } + ], + "name": "iAck", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "name": "nfts", + "outputs": [ + { "internalType": "uint256", "name": "chainId", "type": "uint256" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "requestAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "destChainId", "type": "string" }, + { + "internalType": "string", + "name": "destinationContractAddress", + "type": "string" + }, + { "internalType": "bytes", "name": "requestMetadata", "type": "bytes" }, + { "internalType": "bytes", "name": "packet", "type": "bytes" } + ], + "name": "sendReadRequest", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "feePayerAddress", "type": "string" } + ], + "name": "setDappMetadata", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "gateway", "type": "address" } + ], + "name": "setGateway", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/networks.json b/networks.json new file mode 100644 index 0000000..bdddc3e --- /dev/null +++ b/networks.json @@ -0,0 +1,8 @@ +{ + "goerli": { + "ERC6551RegistryAndReadCall": { + "address": "0x77813af45BC74aB209236b92CE2B6F2A51e58ee8", + "startBlock": 9248181 + } + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..98d388d --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "horcross", + "license": "UNLICENSED", + "scripts": { + "codegen": "graph codegen", + "build": "graph build", + "deploy": "graph deploy --node https://api.studio.thegraph.com/deploy/ horcross", + "create-local": "graph create --node http://localhost:8020/ horcross", + "remove-local": "graph remove --node http://localhost:8020/ horcross", + "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 horcross", + "test": "graph test" + }, + "dependencies": { + "@graphprotocol/graph-cli": "0.51.2", + "@graphprotocol/graph-ts": "0.30.0" + }, + "devDependencies": { "matchstick-as": "0.5.0" } +} diff --git a/schema.graphql b/schema.graphql new file mode 100644 index 0000000..8366cd1 --- /dev/null +++ b/schema.graphql @@ -0,0 +1,20 @@ +type AccountCreated @entity(immutable: true) { + id: Bytes! + account: Bytes! # address + implementation: Bytes! # address + chainId: BigInt! # uint256 + tokenContract: Bytes! # address + tokenId: BigInt! # uint256 + salt: BigInt! # uint256 + blockNumber: BigInt! + blockTimestamp: BigInt! + transactionHash: Bytes! +} + +type ReceivedData @entity(immutable: true) { + id: Bytes! + requestAddress: Bytes! # address + blockNumber: BigInt! + blockTimestamp: BigInt! + transactionHash: Bytes! +} diff --git a/src/erc-6551-registry-and-read-call.ts b/src/erc-6551-registry-and-read-call.ts new file mode 100644 index 0000000..90b9ca9 --- /dev/null +++ b/src/erc-6551-registry-and-read-call.ts @@ -0,0 +1,36 @@ +import { + AccountCreated as AccountCreatedEvent, + ReceivedData as ReceivedDataEvent +} from "../generated/ERC6551RegistryAndReadCall/ERC6551RegistryAndReadCall" +import { AccountCreated, ReceivedData } from "../generated/schema" + +export function handleAccountCreated(event: AccountCreatedEvent): void { + let entity = new AccountCreated( + event.transaction.hash.concatI32(event.logIndex.toI32()) + ) + entity.account = event.params.account + entity.implementation = event.params.implementation + entity.chainId = event.params.chainId + entity.tokenContract = event.params.tokenContract + entity.tokenId = event.params.tokenId + entity.salt = event.params.salt + + entity.blockNumber = event.block.number + entity.blockTimestamp = event.block.timestamp + entity.transactionHash = event.transaction.hash + + entity.save() +} + +export function handleReceivedData(event: ReceivedDataEvent): void { + let entity = new ReceivedData( + event.transaction.hash.concatI32(event.logIndex.toI32()) + ) + entity.requestAddress = event.params.requestAddress + + entity.blockNumber = event.block.number + entity.blockTimestamp = event.block.timestamp + entity.transactionHash = event.transaction.hash + + entity.save() +} diff --git a/subgraph.yaml b/subgraph.yaml new file mode 100644 index 0000000..6f9b9bf --- /dev/null +++ b/subgraph.yaml @@ -0,0 +1,27 @@ +specVersion: 0.0.5 +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum + name: ERC6551RegistryAndReadCall + network: goerli + source: + address: "0x77813af45BC74aB209236b92CE2B6F2A51e58ee8" + abi: ERC6551RegistryAndReadCall + startBlock: 9248181 + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - AccountCreated + - ReceivedData + abis: + - name: ERC6551RegistryAndReadCall + file: ./abis/ERC6551RegistryAndReadCall.json + eventHandlers: + - event: AccountCreated(address,address,uint256,address,uint256,uint256) + handler: handleAccountCreated + - event: ReceivedData(address) + handler: handleReceivedData + file: ./src/erc-6551-registry-and-read-call.ts diff --git a/tests/erc-6551-registry-and-read-call-utils.ts b/tests/erc-6551-registry-and-read-call-utils.ts new file mode 100644 index 0000000..f6c606f --- /dev/null +++ b/tests/erc-6551-registry-and-read-call-utils.ts @@ -0,0 +1,67 @@ +import { newMockEvent } from "matchstick-as" +import { ethereum, Address, BigInt } from "@graphprotocol/graph-ts" +import { + AccountCreated, + ReceivedData +} from "../generated/ERC6551RegistryAndReadCall/ERC6551RegistryAndReadCall" + +export function createAccountCreatedEvent( + account: Address, + implementation: Address, + chainId: BigInt, + tokenContract: Address, + tokenId: BigInt, + salt: BigInt +): AccountCreated { + let accountCreatedEvent = changetype(newMockEvent()) + + accountCreatedEvent.parameters = new Array() + + accountCreatedEvent.parameters.push( + new ethereum.EventParam("account", ethereum.Value.fromAddress(account)) + ) + accountCreatedEvent.parameters.push( + new ethereum.EventParam( + "implementation", + ethereum.Value.fromAddress(implementation) + ) + ) + accountCreatedEvent.parameters.push( + new ethereum.EventParam( + "chainId", + ethereum.Value.fromUnsignedBigInt(chainId) + ) + ) + accountCreatedEvent.parameters.push( + new ethereum.EventParam( + "tokenContract", + ethereum.Value.fromAddress(tokenContract) + ) + ) + accountCreatedEvent.parameters.push( + new ethereum.EventParam( + "tokenId", + ethereum.Value.fromUnsignedBigInt(tokenId) + ) + ) + accountCreatedEvent.parameters.push( + new ethereum.EventParam("salt", ethereum.Value.fromUnsignedBigInt(salt)) + ) + + return accountCreatedEvent +} + +export function createReceivedDataEvent(requestAddress: Address): ReceivedData { + let receivedDataEvent = changetype(newMockEvent()) + + receivedDataEvent.parameters = new Array() + + receivedDataEvent.parameters.push( + new ethereum.EventParam( + "requestAddress", + ethereum.Value.fromAddress(requestAddress) + ) + ) + + return receivedDataEvent +} diff --git a/tests/erc-6551-registry-and-read-call.test.ts b/tests/erc-6551-registry-and-read-call.test.ts new file mode 100644 index 0000000..1562bff --- /dev/null +++ b/tests/erc-6551-registry-and-read-call.test.ts @@ -0,0 +1,94 @@ +import { + assert, + describe, + test, + clearStore, + beforeAll, + afterAll +} from "matchstick-as/assembly/index" +import { Address, BigInt } from "@graphprotocol/graph-ts" +import { AccountCreated } from "../generated/schema" +import { AccountCreated as AccountCreatedEvent } from "../generated/ERC6551RegistryAndReadCall/ERC6551RegistryAndReadCall" +import { handleAccountCreated } from "../src/erc-6551-registry-and-read-call" +import { createAccountCreatedEvent } from "./erc-6551-registry-and-read-call-utils" + +// Tests structure (matchstick-as >=0.5.0) +// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 + +describe("Describe entity assertions", () => { + beforeAll(() => { + let account = Address.fromString( + "0x0000000000000000000000000000000000000001" + ) + let implementation = Address.fromString( + "0x0000000000000000000000000000000000000001" + ) + let chainId = BigInt.fromI32(234) + let tokenContract = Address.fromString( + "0x0000000000000000000000000000000000000001" + ) + let tokenId = BigInt.fromI32(234) + let salt = BigInt.fromI32(234) + let newAccountCreatedEvent = createAccountCreatedEvent( + account, + implementation, + chainId, + tokenContract, + tokenId, + salt + ) + handleAccountCreated(newAccountCreatedEvent) + }) + + afterAll(() => { + clearStore() + }) + + // For more test scenarios, see: + // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test + + test("AccountCreated created and stored", () => { + assert.entityCount("AccountCreated", 1) + + // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function + assert.fieldEquals( + "AccountCreated", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "account", + "0x0000000000000000000000000000000000000001" + ) + assert.fieldEquals( + "AccountCreated", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "implementation", + "0x0000000000000000000000000000000000000001" + ) + assert.fieldEquals( + "AccountCreated", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "chainId", + "234" + ) + assert.fieldEquals( + "AccountCreated", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "tokenContract", + "0x0000000000000000000000000000000000000001" + ) + assert.fieldEquals( + "AccountCreated", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "tokenId", + "234" + ) + assert.fieldEquals( + "AccountCreated", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "salt", + "234" + ) + + // More assert options: + // https://thegraph.com/docs/en/developer/matchstick/#asserts + }) +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4e86672 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json", + "include": ["src", "tests"] +}