Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save Reveal Info #801

Closed
wants to merge 2 commits into from
Closed
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
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ typescript/
system-tests/
monitoring/
cross-chain/
infrastructure/
9 changes: 9 additions & 0 deletions infrastructure/tbtc-deposit-reveals/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
/node_modules
*-lock.*
*.lock
*.log
.wrangler/
/external

/dist
2 changes: 2 additions & 0 deletions infrastructure/tbtc-deposit-reveals/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
external/
.wrangler/
3 changes: 3 additions & 0 deletions infrastructure/tbtc-deposit-reveals/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
...require("@keep-network/prettier-config-keep"),
}
44 changes: 44 additions & 0 deletions infrastructure/tbtc-deposit-reveals/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Deposit Reveals API

A backend to store TBTC reveal and recovery information so that a
user does not have to.

We're using [cloudflare workers](https://workers.cloudflare.com/) with typescript,
and a D1 database for persistence.

[itty-router](https://github.com/kwhitley/itty-router) is used for routing.

## Architecture

We have a `routes.ts` file that hands off http requests to various functions within
the `controllers` folder. The controllers read from D1, giving us the
[model-view-controller pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
pattern (the view is the front end).

## Development

- local development: `yarn run dev`
- query remote D1: `yarn run query:<env> <query>`
- - example: `yarn run query:local 'select * from reveals;'`
- view pending remote migrations: `yarn run migrations:<env>:list`
- apply pending remote migrations: `yarn run migrations:<env>:apply`
- create a new migration: `yarn run migrations:create`
- reset to a bootstrapped local database: `yarn run reload_db:local`
- factory reset the local database: `yarn run reset_db:local`

## Deployment

We have two different environments: `staging` and `production`.
To deploy to an environment:

```
$ yarn run deploy --env <environment>
```

Make sure to select the "Thesis" account when prompted.
If deployment does not prompt you, log out and then back in:

```
$ npx wrangler logout
$ npx wrangler login
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Migration number: 0000 2024-03-19T14:35:39.927Z

CREATE TABLE IF NOT EXISTS reveals (
address TEXT,
reveal_info JSON,
metadata JSON,
application TEXT,
inserted_at TIMESTAMP NOT NULL DEFAULT current_timestamp
);
31 changes: 31 additions & 0 deletions infrastructure/tbtc-deposit-reveals/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "template-worker-typescript",
"version": "0.0.0",
"private": true,
"scripts": {
"deploy": "wrangler deploy src/index.ts",
"dev": "wrangler dev --local-upstream 'localhost:3000'",
"query:production": "wrangler d1 execute tbtc-deposit-reveals-production --env production",
"query:staging": "wrangler d1 execute tbtc-deposit-reveals-staging --env staging",
"query:local": "wrangler d1 execute tbtc-deposit-reveals-staging --local",
"migrations:create": "wrangler d1 migrations create tbtc-deposit-reveals-production",
"migrations:production:list": "wrangler d1 migrations list tbtc-deposit-reveals-production --env production",
"migrations:production:apply": "wrangler d1 migrations apply tbtc-deposit-reveals-production --env production",
"migrations:staging:list": "wrangler d1 migrations list tbtc-deposit-reveals-staging --env staging",
"migrations:staging:apply": "wrangler d1 migrations apply tbtc-deposit-reveals-staging --env staging",
"migrations:local:list": "wrangler d1 migrations list tbtc-deposit-reveals-staging --local",
"migrations:local:apply": "wrangler d1 migrations apply tbtc-deposit-reveals-staging --local",
"reload_db:local": "sh scripts/rebuild_db.sh",
"reset_db:local": "wrangler d1 execute tbtc-deposit-reveals-staging --local --file ./scripts/reset_db.sql"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20231016.0",
"@keep-network/prettier-config-keep": "github:keep-network/prettier-config-keep",
"typescript": "^5.0.4",
"wrangler": "^3.0.0"
},
"dependencies": {
"@keep-network/tbtc-v2.ts": "^2.3.0",
"itty-router": "^4.2.2"
}
}
8 changes: 8 additions & 0 deletions infrastructure/tbtc-deposit-reveals/scripts/local_data.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
INSERT INTO reveals (address, reveal_info, metadata, application)
VALUES
(
'0xalice',
'{"depositor":{"identifierHex":"27343e0410acd8cf711d079c57811fe8c0666df2"},"blindingFactor":"32cd0d8907411467","walletPublicKeyHash":"03b74d6893ad46dfdd01b9e0e3b3385f4fce2d1e","refundPublicKeyHash":"be94fbd152b1c9f396a5e2dce4f536de0cddac1e","refundLocktime":"6ebe3b65","btcRecoveryAddress":"2NAcvrJF3oDpjC5nuqhJvLrsvEtXwQ1W65n"}',
'{}',
"mezo"
);
5 changes: 5 additions & 0 deletions infrastructure/tbtc-deposit-reveals/scripts/rebuild_db.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

yarn run query:local --file ./scripts/reset_db.sql
yes | yarn run migrations:local:apply
yarn run query:local --file ./scripts/local_data.sql
3 changes: 3 additions & 0 deletions infrastructure/tbtc-deposit-reveals/scripts/reset_db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
drop table if exists reveals;

drop table if exists d1_migrations;
90 changes: 90 additions & 0 deletions infrastructure/tbtc-deposit-reveals/src/controllers/deposits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { IRequest, StatusError } from "itty-router"
import { Env } from "#/types"
import { DepositReceipt } from "@keep-network/tbtc-v2.ts/src/lib/contracts/bridge"

type DepositQueryResult = {
address: string
reveal_info: string
metadata: string
application: string
inserted_at: number
}

type Deposit = {
address: string
revealInfo: DepositReceipt
metadata: Object
application: string
insertedAt: number
}

export async function getDepositsForAddress(
request: IRequest,
env: Env,
): Promise<Deposit[]> {
const {
params: { address },
} = request
if (address === undefined) {
throw new StatusError(
500,
"Unable to extract the address from the request.",
)
}
const { results: reveals } = await env.DB.prepare(
`
SELECT
address,
reveal_info,
metadata,
application,
CAST(strftime('%s', inserted_at) as INT) as inserted_at
FROM reveals
WHERE address = ?1
`,
)
.bind(address)
.all<DepositQueryResult>()

return reveals.map((reveal) => {
return {
address: reveal.address,
revealInfo: JSON.parse(reveal.reveal_info),
metadata: JSON.parse(reveal.metadata),
application: reveal.application,
insertedAt: reveal.inserted_at,
}
})
}

export type SaveDepositRequest = {
address: string
revealInfo: DepositReceipt
metadata: Object
application: string
}

export async function saveDeposit(
request: SaveDepositRequest & IRequest,
env: Env,
): Promise<{ success: boolean }> {
const saveDepositInfo: SaveDepositRequest = request.content
const { address, revealInfo, metadata, application } = saveDepositInfo
const result = await env.DB.prepare(
`
INSERT INTO reveals
(address, reveal_info, metadata, application)
VALUES
(?1, ?2, ?3, ?4);
`,
)
.bind(
address,
JSON.stringify(revealInfo),
JSON.stringify(metadata),
application,
)
.run()

return { success: result.success }
}
29 changes: 29 additions & 0 deletions infrastructure/tbtc-deposit-reveals/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { error, json } from "itty-router"
import router, { RouterRequest, corsify } from "#/routes"
import { Env } from "#/types"

export default {
async fetch(request: Request, env: Env, context: ExecutionContext) {
return router
.handle(request, env, context)
.then((response) => {
const jsonResponse = json(response)
// Reflect the changes made by the router to the request object.
const routerRequest = request as unknown as RouterRequest

routerRequest.responseHeaders?.forEach(
(headerValue: string, headerName: string) => {
jsonResponse.headers.append(headerName, headerValue)
},
)

return jsonResponse
})
.catch((err) => {
console.error(err)

return error(err)
})
.then(corsify)
},
}
66 changes: 66 additions & 0 deletions infrastructure/tbtc-deposit-reveals/src/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
Router,
IRequest,
createCors,
error,
withContent,
withCookies,
RouterType,
RouteHandler,
} from "itty-router"
import { Env } from "#/types"
import {
getDepositsForAddress,
saveDeposit,
SaveDepositRequest,
} from "./controllers/deposits"

export const { preflight, corsify } = createCors({
origins: (_: string) => true,
methods: ["GET", "POST", "DELETE"],
headers: {
"Access-Control-Allow-Credentials": true,
},
})

const router = Router()

/**
* Adds a property, `responseHeaders`, that can be used to modify the eventual
* response headers without returning a response. This allows middleware to set
* response headers.
*/
function withResponseHeaders(request: IRequest): void {
request.responseHeaders = new Headers()
}

type TypedRoute<
RequestType = IRequest,
// This is a direct pull from itty router for easier typing on our end.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Args extends unknown[] = [env: Env, context: ExecutionContext],
RT = RouterType,
> = (path: string, ...handlers: RouteHandler<RequestType, Args>[]) => RT

export type RouterRequest = IRequest & {
cookies: Record<string, string>
responseHeaders: Headers
content?: Record<string, unknown>
sessionId?: string
}
// Capture the added properties created by our middlewares.
export type MiddlewaredRouter = RouterType<TypedRoute<RouterRequest>, []>

router
.all<IRequest, [], MiddlewaredRouter>(
"*",
preflight,
withResponseHeaders,
withCookies,
withContent,
)
.get("/deposits/:address", getDepositsForAddress)
.post<SaveDepositRequest & IRequest>("/deposits", saveDeposit)
.all("*", () => error(404, "No home route."))

export default router
3 changes: 3 additions & 0 deletions infrastructure/tbtc-deposit-reveals/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Env = {
DB: D1Database
}
12 changes: 12 additions & 0 deletions infrastructure/tbtc-deposit-reveals/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../typescript/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"types": ["@cloudflare/workers-types"],
"paths": {
"#/*": ["./src/*"]
}
},
"include": ["src/**/*", "test/**/*"],
"exclude": ["node_modules"]
}
20 changes: 20 additions & 0 deletions infrastructure/tbtc-deposit-reveals/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name = "tbtc-deposit-reveals"
main = "./src/index.ts"
compatibility_date = "2022-10-10"

[[d1_databases]]
binding = "DB"
database_name = "tbtc-deposit-reveals-staging"
database_id = "144880b2-3392-4e24-afa2-453d6940b9f7"

# Staging
[[env.staging.d1_databases]]
binding = "DB"
database_name = "tbtc-deposit-reveals-staging"
database_id = "144880b2-3392-4e24-afa2-453d6940b9f7"

# Production
[[env.production.d1_databases]]
binding = "DB"
database_name = "tbtc-deposit-reveals-production"
database_id = "a859f79c-2a13-4e71-8602-c0a1098a3303"
Loading