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

Cardano template PoC #67

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
76 changes: 76 additions & 0 deletions cardano-connection/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
## CHAIN DATA
# Example: "https://rpc-devnet-cardano-evm.c1.milkomeda.com"
CHAIN_URI="http://localhost:8545"
# Example: "https://explorer-devnet-cardano-evm.c1.milkomeda.com"
CHAIN_EXPLORER_URI=""
# Example: "Milkomeda C1 Testnet"
CHAIN_NAME="Hardhat"
# Example: "200101"
CHAIN_ID="31337"
# Example: "Milkomeda Test Ada"
CHAIN_CURRENCY_NAME="Test Hardhat Tokens"
# Note: The shorthand currency name/sybol shown in the user's wallet
# Example: "mtADA"
CHAIN_CURRENCY_SYMBOL="TEST"
# Note: The number of decimals of the native/gas asset of the chain
# Example: "18"
CHAIN_CURRENCY_DECIMALS="18"
# Note: This is in seconds as a float
# Example: "2.0"
BLOCK_TIME="2"

## CONTRACT DEPLOYMENT
# Example: "0xA02F7744868945A346Ee6994068F54D039683445"
CONTRACT_ADDRESS="0x5FbDB2315678afecb367f032d93F642f64180aa3" # fill with result of npm run chain:deploy
# Note: This is the block height to start syncing from; usually the contract deployment block height
# Example: "9000000"
START_BLOCKHEIGHT="0"


## Middleware
# Note: This is the URL which your middleware will use to interact with your game node webserver
# Example: "http://localhost:3333"
BACKEND_URI="http://localhost:3333"


## MISC
# Note: This is the port your game node webserver will use
# Example: "3333"
WEBSERVER_PORT="3333"
# Note: This enables running your game node with just the webserver running, meaning no new blocks will be synced.
# This is primarily useful for development, devops, or testing other edge cases where you want to interact with
# the game node but not have the game state progress forward.
SERVER_ONLY_MODE="false"

## DATABASE
DB_NAME="postgres"
DB_USER="postgres"
DB_PW="postgres"
DB_HOST="localhost"
DB_PORT="5432"

## Batcher setup
# BATCHER DB connection:
BATCHER_DB_HOST="paima-batcher-db"
BATCHER_DB_USER="postgres"
BATCHER_DB_PW="postgres"
BATCHER_DB_NAME="postgres"
BATCHER_DB_PORT="5532"

# Batcher Contract:
DEFAULT_FEE="10000000000000000"

# Batcher Webserver:
BATCHER_PORT="3340"

# Batcher Validation parameters:
GAME_NODE_URI="http://localhost:3333"
DEFAULT_VALIDATION_ACTIVE="false"
GAME_INPUT_VALIDATOR_PERIOD="1000"
BATCHED_TRANSACTION_POSTER_PERIOD="3000"
BATCHED_MESSAGE_SIZE_LIMIT="100000"
MAX_USER_INPUTS_PER_MINUTE="10"
MAX_USER_INPUTS_PER_DAY="500"

# Batcher wallet
BATCHER_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" # hardhat local node key
34 changes: 34 additions & 0 deletions cardano-connection/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module.exports = {
parser: '@typescript-eslint/parser',
extends: ['prettier', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
parserOptions: {
ecmaVersion: 2019,
sourceType: 'module',
},
rules: {
'@typescript-eslint/explicit-member-accessibility': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/no-parameter-properties': 0,
'@typescript-eslint/interface-name-prefix': 0,
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'default',
format: null,
leadingUnderscore: 'allow',
},
{
selector: 'typeLike',
format: ['PascalCase'],
leadingUnderscore: 'allow',
},
],
'@typescript-eslint/consistent-type-imports': 'error',
'spaced-comment': 'warn',
},
};
44 changes: 44 additions & 0 deletions cardano-connection/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
jestSetup.d.ts
jestSetup.js
db/src/pgPool.js

node_modules
*.tsbuildinfo

build
lib
dist
dist-ssr

# Editor directories and files
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
snapshots

*.local

.env
.env.testnet
.env.mainnet

# Frontend
build.zip
WebGL
frontend/paimaMiddleware.js

# recompiled code for standalone purposes
packaged/*
1 change: 1 addition & 0 deletions cardano-connection/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
1 change: 1 addition & 0 deletions cardano-connection/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lts/iron
4 changes: 4 additions & 0 deletions cardano-connection/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
db/src/*.queries.ts
api/src/tsoa/routes.ts
build
middleware/packaged/*
15 changes: 15 additions & 0 deletions cardano-connection/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"overrides": [
{
"files": ["*.js", "*.ts", "*.jsx", "*.tsx", "*.css", "*.json"],
"options": {
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 100,
"arrowParens": "avoid"
}
}
]
}
15 changes: 15 additions & 0 deletions cardano-connection/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"files.associations": {
".env.*": "properties"
},
"[sql]": {
"editor.formatOnSave": false
},
"[json][jsonc][json5]": {
"editor.formatOnSave": true
}
}
119 changes: 119 additions & 0 deletions cardano-connection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Cardano Game Template

This documentation provides a basic overview of the template. Each module has its own `README` file with more detailed information.

## Installation

Install [Yaci Devkit](https://github.com/bloxbean/yaci-devkit) and start a Cardano node locally

To install dependencies and perform initial setup, run the following command:

```
npm run initialize
```

This does the following:

- install dependencies of this template
- copies `.env.example` as `.env.localhost` to the parent folder

### MacOS specific

If you're using Mac and run into installation issues you can add `--target=esbuild-darwin-arm64` as a workaround to `npm install`. This installs the correct version of a problematic package. For example:

```
npm install --save-dev esbuild@latest --target=esbuild-darwin-arm64
```

## Building

To compile the Game Node into `endpoints` and `gameCode` entrypoints used by Paima Engine, use the following command:

```
npm run pack
```

To compile the JavaScript Bundle of the middleware for the game frontend, run the command:

```
npm run pack:middleware
```

## Prerequisites

Ensure that the `paima-engine-{linux|mac}` executable is located in the parent directory of this project. The directory structure should be as follows:

```
this-template
../paima-engine-linux
../.env
```

## Environment Setup

Config file `.env.localhost` is created during `npm run initialize` in the parent folder, based on `.env.example` in this project. This is an empty file that you need to fill in with your specific values, before running Paima Engine.

Feel free to use examples written in the file for initial testing.

## Contracts

1. Start a local network using `npm run chain:start`
2. `npm run chain:deploy`

## Development

To reflect changes in the `API`, use the following command to regenerate all `tsoa` routes:

```
npm run compile:api
```

If there are any changes to the DB schema or queries, start the `pgtyped` watcher process using the following command. It will regenerate all the DB types used in the project:

```
npm run compile:db
```

To speed up the development cycle you can at any time completely reset the database and start syncing from the latest blockheight. Run this command, that will modify your `.env.localhost` and `docker-compose.yml` files:

```
npm run database:reset
```

## Production

To start the database, run the command:

```
npm run database:up
```

To run the Game Node, follow these steps:

1. Change to the parent directory where the packaged folder was generated:

```
cd ..
```

2. Execute the following command:

```
./paima-engine-linux run
```

You can set the `NETWORK` variable if you want to load a custom config for your Game Node. For example to load `.env.localhost` use:

```
NETWORK=localhost ./paima-engine-linux run
```

## Documentation

If you've got this far you're probably already familiar with our documentation. But if you need to refresh your knowledge you can copy the documentation files to your file system by using the standalone CLI command:

```
./paima-engine-linux docs
```

Or you can visit our [Paima Documentation Website](docs.paimastudios.com) at any time.
10 changes: 10 additions & 0 deletions cardano-connection/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Webserver

This package implements the REST API that serves data from the game node database to the middleware (which is then used by the game frontend).

## How to run

This package uses [tsoa](https://github.com/lukeautry/tsoa) to generate type safe API endpoints.
`tsoa` requires a configuration file, `tsoa.json`. Every endpoint (called "controller" in `tsoa` convention) needs to be a single TypeScript file. To generate the endpoints, you must run the `tsoa` CLI. You can do that by running `npm run compile`.

The CLI will generate a `routes.ts` file, which exports a function called `RegisterRoutes`. The function takes an Express server as its sole argument. This package exports that function, to be imported by the game backend and passed to Paima Engine to run the server.
27 changes: 27 additions & 0 deletions cardano-connection/api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@game/api",
"version": "1.0.0",
"description": "Webserver REST API for the middleware to interact with game node.",
"main": "build/index.js",
"type": "module",
"scripts": {
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1",
"compile": "npx tsoa spec-and-routes"
},
"author": "",
"license": "ISC",
"dependencies": {
"@game/utils": "1.0.0",
"@game/db": "1.0.0",
"cors": "^2.8.5",
"express": "^4.18.2",
"fp-ts": "^2.16.2",
"io-ts": "^2.2.21",
"tsoa": "^6.0.1"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21"
}
}
18 changes: 18 additions & 0 deletions cardano-connection/api/src/controllers/userStats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Body, Controller, Get, Path, Post, Query, Route, SuccessResponse } from 'tsoa';
import { requirePool, getUserStats } from '@game/db';
import type { UserStats } from '@game/utils';

interface GetUserStatsResponse {
stats: UserStats;
}

@Route('user_stats')
export class UserStatsController extends Controller {
@Get()
public async get(@Query() wallet: string): Promise<GetUserStatsResponse> {
const pool = requirePool();
wallet = wallet.toLowerCase();
const [stats] = await getUserStats.run({ wallet }, pool);
return { stats };
}
}
17 changes: 17 additions & 0 deletions cardano-connection/api/src/controllers/worldState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Controller, Get, Route } from 'tsoa';
import { requirePool, getWorldStats } from '@game/db';
import type { WorldStats } from '@game/utils';

interface GetWorldStateResponse {
stats: WorldStats[];
}

@Route('world_state')
export class WorldStateController extends Controller {
@Get()
public async get(): Promise<GetWorldStateResponse> {
const pool = requirePool();
const stats = await getWorldStats.run(undefined, pool);
return { stats };
}
}
2 changes: 2 additions & 0 deletions cardano-connection/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { RegisterRoutes } from './tsoa/routes.js';
export default RegisterRoutes;
Loading