Skip to content

Commit

Permalink
chore: update to ORM (#7)
Browse files Browse the repository at this point in the history
* chore: update to ORM

* fix: remove test from GitHub action

* chore: remove year
  • Loading branch information
bonustrack authored Dec 27, 2023
1 parent 671fba7 commit 067135d
Show file tree
Hide file tree
Showing 17 changed files with 470 additions and 3,276 deletions.
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
DATABASE_URL=mysql://root:default_password@localhost:3306/checkpoint

DATABASE_URL=mysql://user:password@host:port/database
23 changes: 0 additions & 23 deletions .eslintrc

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Build and Run Tests
name: Lint and build
on: [push]
jobs:
build-test:
lint-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
Expand All @@ -16,6 +16,5 @@ jobs:
- run: yarn install
- run: yarn lint
- run: yarn build
- run: yarn test
env:
DATABASE_URL: 'mysql://root:[email protected]:3306/checkpoint'
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ coverage
.idea
.vscode
*.log

# Checkpoint
.checkpoint
8 changes: 0 additions & 8 deletions .prettierrc

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Snapshot Labs
Copyright (c) Snapshot Labs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Checkpoint starter template

This is a template to quickly get started to use [Checkpoint](https://docs.checkpoint.fyi)
to expose a GraphQL API to query data from your StarkNet contracts.
to expose a GraphQL API to query data from your Starknet contracts.

## Getting started

This starter project contains logic to index events from a StarkNet Poster contract that is defined in the
This starter project contains logic to index events from a Starknet Poster contract that is defined in the
[starknet-poster](https://github.com/snapshot-labs/starknet-poster/blob/master/contracts/Poster.cairo) repository.

Create a copy of this repository by clicking **'Use this template'** button or clicking [this
Expand All @@ -17,7 +17,7 @@ link](https://github.com/snapshot-labs/checkpoint-template/generate).
- Docker with `docker-compose`
- Yarn

> You can also use npm, just make sure to replace the subsequent 'yarn' commands with their npm equivalent.
> You can also use NPM, just make sure to replace the subsequent 'yarn' commands with their NPM equivalent.
After cloning this project, run the following command to install dependencies:

Expand All @@ -40,7 +40,7 @@ Next, start up the server:
yarn dev # for local development or else `yarn start` for production build.
```

This will expose a GraphQL API endpoint locally at http://localhost:3000. You can easily interact with this endpoint using the graphiql interface by visiting http://localhost:3000 in your browser.
This will expose a GraphQL API endpoint locally at http://localhost:3000. You can easily interact with this endpoint using the GraphiQL interface by visiting http://localhost:3000 in your browser.

To fetch a list of Post's try the following query:

Expand Down
51 changes: 21 additions & 30 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,44 +1,35 @@
{
"name": "@snapshot-labs/checkpoint-template",
"version": "1.0.0",
"version": "0.1.0",
"license": "MIT",
"description": "Checkpoint starter template",
"main": "dist/src/index.js",
"repository": "[email protected]:snapshot-labs/checkpoint-template.git",
"scripts": {
"lint": "eslint src/ test/ --ext .ts --fix",
"build": "tsc -p tsconfig.build.json",
"codegen": "checkpoint generate",
"lint": "eslint src/ --ext .ts --fix",
"prebuild": "yarn codegen",
"build": "tsc",
"dev": "nodemon src/index.ts",
"start": "node dist/src/index.js",
"test": "jest"
"start": "node dist/src/index.js"
},
"author": "Snapshot Labs",
"license": "MIT",
"eslintConfig": {
"extends": "@snapshot-labs"
},
"prettier": "@snapshot-labs/prettier-config",
"dependencies": {
"@ethersproject/address": "^5.6.0",
"@ethersproject/bignumber": "^5.6.1",
"@snapshot-labs/checkpoint": "^0.1.0-beta.25",
"@snapshot-labs/sx": "^0.1.0-beta.44",
"@snapshot-labs/checkpoint": "^0.1.0-beta.26",
"@types/node": "^18.11.6",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"starknet": "^5.19.3"
"nodemon": "^2.0.19",
"starknet": "^5.19.3",
"ts-node": "^10.8.1",
"typescript": "^4.9.3"
},
"devDependencies": {
"@types/bn.js": "^5.1.0",
"@types/express": "^4.17.13",
"@types/jest": "^27.5.1",
"@types/mysql": "^2.15.21",
"@types/node": "^20.8.10",
"@typescript-eslint/eslint-plugin": "^5.25.0",
"@typescript-eslint/parser": "^5.25.0",
"eslint": "^8.15.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^28.1.0",
"jest-mock-extended": "^2.0.6",
"nodemon": "^2.0.16",
"prettier": "^2.6.2",
"ts-jest": "^28.0.2",
"ts-node": "^10.7.0",
"typescript": "^4.9.3"
"@snapshot-labs/eslint-config": "^0.1.0-beta.7",
"@snapshot-labs/prettier-config": "^0.1.0-beta.7",
"eslint": "^8.28.0",
"prettier": "^2.8.0"
}
}
52 changes: 52 additions & 0 deletions src/abis/Poster.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"data": [
{
"name": "address",
"type": "felt"
},
{
"name": "content_len",
"type": "felt"
},
{
"name": "content",
"type": "felt*"
},
{
"name": "tag_len",
"type": "felt"
},
{
"name": "tag",
"type": "felt*"
}
],
"keys": [],
"name": "new_post",
"type": "event"
},
{
"name": "post",
"type": "function",
"inputs": [
{
"name": "content_len",
"type": "felt"
},
{
"name": "content",
"type": "felt*"
},
{
"name": "tag_len",
"type": "felt"
},
{
"name": "tag",
"type": "felt*"
}
],
"outputs": []
}
]
3 changes: 2 additions & 1 deletion src/config.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"network_node_url": "https://starknet-goerli.infura.io/v3/46a5dd9727bf48d4a132672d3f376146",
"optimistic_indexing": true,
"sources": [
{
"contract": "0x04d10712e72b971262f5df09506bbdbdd7f729724030fa909e8c8e7ac2fd0012",
"start": 185778,
"deploy_fn": "handleDeploy",
"abi": "Poster",
"events": [
{
"name": "new_post",
Expand Down
33 changes: 15 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,33 @@ import Checkpoint, { LogLevel } from '@snapshot-labs/checkpoint';
import config from './config.json';
import * as writers from './writers';
import checkpointBlocks from './checkpoints.json';
import Poster from './abis/Poster.json';

const dir = __dirname.endsWith('dist/src') ? '../' : '';
const schemaFile = path.join(__dirname, `${dir}../src/schema.gql`);
const schema = fs.readFileSync(schemaFile, 'utf8');

const checkpointOptions = {
logLevel: LogLevel.Info
// prettifyLogs: true, // uncomment in local dev
};
const checkpoint = new Checkpoint(config, writers, schema, {
logLevel: LogLevel.Info,
prettifyLogs: true,
abis: {
Poster
}
});

// Initialize checkpoint
// @ts-ignore
const checkpoint = new Checkpoint(config, writers, schema, checkpointOptions);
async function run() {
await checkpoint.reset();
await checkpoint.resetMetadata();
await checkpoint.seedCheckpoints(checkpointBlocks);
await checkpoint.start();
}

// resets the entities already created in the database
// ensures data is always fresh on each re-run
checkpoint
.reset()
.then(() => checkpoint.seedCheckpoints(checkpointBlocks))
.then(() => {
// start the indexer
checkpoint.start();
});
run();

const app = express();
app.use(express.json({ limit: '4mb' }));
app.use(express.urlencoded({ limit: '4mb', extended: false }));
app.use(cors({ maxAge: 86400 }));

// mount Checkpoint's GraphQL API on path /
app.use('/', checkpoint.graphql);

const PORT = process.env.PORT || 3000;
Expand Down
19 changes: 4 additions & 15 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import { getAddress } from '@ethersproject/address';
import { BigNumber } from '@ethersproject/bignumber';
import { shortStringArrToStr } from '@snapshot-labs/sx/dist/utils/strings';
import { shortString } from 'starknet';

export const toAddress = bn => {
try {
return getAddress(BigNumber.from(bn).toHexString());
} catch (e) {
return bn;
}
};

export const hexStrArrToStr = (data, start: number, length: number | bigint): string => {
const dataSlice = data.slice(start, start + Number(length));
return shortStringArrToStr(dataSlice.map(m => BigInt(m)));
};
export function longStringToText(array: string[]): string {
return array.reduce((acc, slice) => acc + shortString.decodeShortString(slice), '');
}
67 changes: 18 additions & 49 deletions src/writers.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,22 @@
import { hexStrArrToStr, toAddress } from './utils';
import type { CheckpointWriter } from '@snapshot-labs/checkpoint';
import { validateAndParseAddress } from 'starknet';
import { CheckpointWriter } from '@snapshot-labs/checkpoint';
import { Post } from '../.checkpoint/models';
import { longStringToText } from './utils';

export async function handleDeploy() {
// Run logic as at the time Contract was deployed.
}
export const handleNewPost: CheckpointWriter = async ({ block, tx, rawEvent, event }) => {
if (!block || !event || !rawEvent) return;

// This decodes the new_post events data and stores successfully
// decoded information in the `posts` table.
//
// See here for the original logic used to create post transactions:
// https://gist.github.com/perfectmak/417a4dab69243c517654195edf100ef9#file-index-ts
export async function handleNewPost({ block, tx, event, mysql }: Parameters<CheckpointWriter>[0]) {
if (!block || !event) return;
const author = validateAndParseAddress(rawEvent.from_address);
const content = longStringToText(event.content);
const tag = longStringToText(event.tag);

const author = toAddress(event.data[0]);
let content = '';
let tag = '';
const contentLength = BigInt(event.data[1]);
const tagLength = BigInt(event.data[2 + Number(contentLength)]);
const timestamp = block.timestamp;
const blockNumber = block.block_number;
const post = new Post(`${author}/${tx.transaction_hash}`);
post.author = author;
post.content = content;
post.tag = tag;
post.tx_hash = tx.transaction_hash;
post.created_at = block.timestamp;
post.created_at_block = block.block_number;

// parse content bytes
try {
content = hexStrArrToStr(event.data, 2, contentLength);
} catch (e) {
console.error(`failed to decode content on block [${blockNumber}]: ${e}`);
return;
}

// parse tag bytes
try {
tag = hexStrArrToStr(event.data, 3 + Number(contentLength), tagLength);
} catch (e) {
console.error(`failed to decode tag on block [${blockNumber}]: ${e}`);
return;
}

// post object matches fields of Post type in schema.gql
const post = {
id: `${author}/${tx.transaction_hash}`,
author,
content,
tag,
tx_hash: tx.transaction_hash,
created_at: timestamp,
created_at_block: blockNumber
};

// table names are `lowercase(TypeName)s` and can be interacted with sql
await mysql.queryAsync('INSERT IGNORE INTO posts SET ?', [post]);
}
await post.save();
};
20 changes: 0 additions & 20 deletions test/__snapshots__/writers.test.ts.snap

This file was deleted.

Loading

0 comments on commit 067135d

Please sign in to comment.