Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@

Contrak helps teams track track their smart contract deployments.

[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/qc4V0T?referralCode=kMU60t)
## 🚀 Deployment

### Railway

## 🚀 Getting Started
#### Option 1: SQLite

[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/qc4V0T?referralCode=kMU60t)

### Deploying Contrak
Follow the steps below to deploy Contrak to Railway with a persistent volume to store the SQLite database:

1. Click the "Deploy on Railway" button above
2. Fill in the environment variables:
2. Click "Deploy Now"
3. (Optional) Add a custom domain and update the `SITE_URL` environment variable

| Variable | Description |
| -------------- | ---------------------------------------------------- |
| `SITE_URL` | Set this to `https://${{RAILWAY_PUBLIC_DOMAIN}}/` |
| `DATABASE_URL` | Set this to `${{RAILWAY_VOLUME_MOUNT_PATH}}/data.db` |
#### Option 2: Postgres

4. Click "Deploy"
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/AEqvSh?referralCode=kMU60t)

Follow the steps below to deploy Contrak to Railway with a Postgres database:

1. Click the "Deploy on Railway" button above
2. Click "Deploy Now"
3. (Optional) Add a custom domain and update the `SITE_URL` environment variable

## 👷 Contributing

Expand All @@ -39,4 +47,3 @@ Contrak helps teams track track their smart contract deployments.
- `packages/sdk`: Contains the TypeScript SDK for Contrak
- `packages/utils`: Contains utility functions used across the project
- `web`: Contains the Next.js web app for Contrak
- `web3inbox`: Contains an example deployment of [Web3Inbox](https://web3inbox.com/) with Contrak notifications
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
"scripts": {
"dev:web": "yarn workspace web dev",
"build:web": "yarn && yarn workspace @contrak/utils build && yarn workspace @contrak/db build && yarn workspace @contrak/rest build && yarn workspace @contrak/sdk build && yarn workspace web build",
"build:packages": "yarn workspace @contrak/utils build && yarn workspace @contrak/db build && yarn workspace @contrak/rest build && yarn workspace @contrak/sdk build",
"start:web": "yarn workspace web start",
"db:push": "yarn workspace @contrak/db push",
"db:push": "DATABASE_TYPE=sqlite yarn workspace @contrak/db push:sqlite",
"hardhat:node": "yarn workspace hardhat-project hardhat node",
"hardhat:deploy": "yarn workspace hardhat-project hardhat run --network localhost scripts/deploy.ts"
},
Expand Down
50 changes: 38 additions & 12 deletions packages/db/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,39 @@
import "dotenv/config";

import type { Config } from "drizzle-kit";
import * as dotenv from "dotenv";
dotenv.config();

console.log(process.env.DATABASE_URL);

export default {
schema: "./src/schema.ts",
driver: "better-sqlite",
dbCredentials: {
url: process.env.DATABASE_URL ?? "../../data.db",
},
} satisfies Config;
import { raise, iife } from "@contrak/utils";

const config = iife(() => {
switch (process.env.DATABASE_TYPE) {
case "sqlite": {
const sqliteConfig = {
schema: "./src/sqlite/schema.ts",
driver: "better-sqlite",
dbCredentials: {
url: process.env.DATABASE_URL ?? raise("DATABASE_URL is not set"),
},
} satisfies Config;

return sqliteConfig;
}

case "postgres": {
const pgConfig = {
schema: "./src/postgres/schema.ts",
driver: "pg",
dbCredentials: {
connectionString:
process.env.DATABASE_URL ?? raise("DATABASE_URL is not set"),
},
} satisfies Config;

return pgConfig;
}

default: {
raise("DATABASE_TYPE is not set");
}
}
});

export default config;
25 changes: 19 additions & 6 deletions packages/db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@
"name": "@contrak/db",
"version": "0.0.1",
"description": "Interact with the Contrak database",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
"./postgres": {
"require": "./dist/postgres/index.js",
"types": "./dist/postgres/index.d.ts"
},
"./sqlite": {
"require": "./dist/sqlite/index.js",
"types": "./dist/sqlite/index.d.ts"
}
},
"scripts": {
"build": "tsc",
"push": "drizzle-kit push:sqlite"
"build": "tsup",
"push:sqlite": "DATABASE_URL=../../data.db drizzle-kit push:sqlite",
"push:postgres": "drizzle-kit push:pg"
},
"files": [
"/dist"
Expand All @@ -15,14 +24,18 @@
"zod": "^3.22.2"
},
"dependencies": {
"@contrak/utils": "workspace:*",
"better-sqlite3": "^8.6.0",
"dotenv": "^16.3.1",
"drizzle-orm": "^0.28.6",
"drizzle-zod": "^0.5.1"
"drizzle-zod": "^0.5.1",
"postgres": "^3.4.0"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.5",
"@types/node": "^20.7.1",
"drizzle-kit": "^0.19.13"
"drizzle-kit": "^0.19.13",
"tsup": "^7.2.0",
"typescript": "^5.2.2"
}
}
12 changes: 0 additions & 12 deletions packages/db/src/db.ts

This file was deleted.

3 changes: 0 additions & 3 deletions packages/db/src/index.ts

This file was deleted.

53 changes: 0 additions & 53 deletions packages/db/src/model.ts

This file was deleted.

59 changes: 59 additions & 0 deletions packages/db/src/postgres/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { drizzle, PostgresJsDatabase } from "drizzle-orm/postgres-js";
import { desc, eq } from "drizzle-orm";
import postgres from "postgres";
import { raise } from "@contrak/utils";

import * as schema from "./schema";

export class Database {
private static db: PostgresJsDatabase<typeof schema>;

private constructor(databasePath: string) {
if (!Database.db) {
const pg = postgres(databasePath);
Database.db = drizzle(pg, { schema });
}
}

async getAllContracts() {
return Database.db
.select()
.from(schema.contracts)
.orderBy(desc(schema.contracts.createdAt));
}

async getContractsByHistory(historyId: string) {
return Database.db
.select()
.from(schema.contracts)
.where(eq(schema.contracts.contractHistoryId, historyId))
.orderBy(desc(schema.contracts.createdAt));
}

async getContractById(id: number) {
const [first] = await Database.db
.select()
.from(schema.contracts)
.where(eq(schema.contracts.id, id));
return first;
}

async createContract(
contract: Omit<typeof schema.contracts.$inferInsert, "id" | "createdAt">
) {
const [row] = await Database.db
.insert(schema.contracts)
.values({
...contract,
createdAt: new Date(),
})
.returning();
return row;
}

static fromEnv() {
const databasePath =
process.env.DATABASE_URL ?? raise("DATABASE_URL not set");
return new Database(databasePath);
}
}
2 changes: 2 additions & 0 deletions packages/db/src/postgres/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Database } from "./db";
export * as schema from "./schema";
18 changes: 18 additions & 0 deletions packages/db/src/postgres/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { text, serial, pgTable, timestamp } from "drizzle-orm/pg-core";

export const contracts = pgTable("contracts", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
contractHistoryId: text("contract_history_id").notNull(),
chainId: text("chain_id").notNull(),
contractAddress: text("contract_address").notNull(),
deployerAddress: text("deployer_address"),
deploymentTransactionHash: text("deployment_transaction_hash"),
orgPublicKey: text("org_public_key"),
message: text("message"),
deployerSignature: text("deployer_signature"),
orgSignature: text("org_signature"),
createdAt: timestamp("created_at").notNull(),
githubUrl: text("github_url"),
gitUsername: text("git_username"),
});
58 changes: 58 additions & 0 deletions packages/db/src/sqlite/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { BetterSQLite3Database, drizzle } from "drizzle-orm/better-sqlite3";
import { desc, eq } from "drizzle-orm";
import SQLiteDatabase from "better-sqlite3";
import { raise } from "@contrak/utils";

import * as schema from "./schema";
export class Database {
private static db: BetterSQLite3Database<typeof schema>;

private constructor(databasePath: string) {
if (!Database.db) {
const sqlite = new SQLiteDatabase(databasePath);
Database.db = drizzle(sqlite, { schema });
}
}

async getAllContracts() {
return Database.db
.select()
.from(schema.contracts)
.orderBy(desc(schema.contracts.createdAt));
}

async getContractsByHistory(historyId: string) {
return Database.db
.select()
.from(schema.contracts)
.where(eq(schema.contracts.contractHistoryId, historyId))
.orderBy(desc(schema.contracts.createdAt));
}

async getContractById(id: number) {
const [first] = await Database.db
.select()
.from(schema.contracts)
.where(eq(schema.contracts.id, id));
return first;
}

async createContract(
contract: Omit<typeof schema.contracts.$inferInsert, "id" | "createdAt">
) {
const [row] = await Database.db
.insert(schema.contracts)
.values({
...contract,
createdAt: new Date(),
})
.returning();
return row;
}

static fromEnv() {
const databasePath =
process.env.DATABASE_URL ?? raise("DATABASE_URL not set");
return new Database(databasePath);
}
}
2 changes: 2 additions & 0 deletions packages/db/src/sqlite/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Database } from "./db";
export * as schema from "./schema";
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
sqliteTable,
text,
integer,
uniqueIndex,
} from "drizzle-orm/sqlite-core";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

export const contracts = sqliteTable("contracts", {
id: integer("id").primaryKey({ autoIncrement: true }),
Expand Down
7 changes: 0 additions & 7 deletions packages/db/src/zod.ts

This file was deleted.

Loading