fix/podman-postgres-integration (#37)

resolves #25

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: johba <johba@harb.eth>
Reviewed-on: https://codeberg.org/johba/harb/pulls/37
This commit is contained in:
johba 2025-10-01 20:26:49 +02:00
parent 8947ec11ca
commit b4c829e4d6
25 changed files with 187 additions and 144 deletions

1
.gitignore vendored
View file

@ -26,3 +26,4 @@ ponder-repo
tmp tmp
foundry.lock foundry.lock
services/ponder/.env.local services/ponder/.env.local
node_modules

View file

@ -33,6 +33,8 @@
- Fund the LiquidityManager with Base WETH (`0x4200...0006`) before expecting `recenter()` to succeed. - Fund the LiquidityManager with Base WETH (`0x4200...0006`) before expecting `recenter()` to succeed.
- Ponder stores data in `.ponder/`; drop the directory if schema changes break migrations. - Ponder stores data in `.ponder/`; drop the directory if schema changes break migrations.
- Keep git clean before committing; never leave commented-out code or untested changes. - Keep git clean before committing; never leave commented-out code or untested changes.
- **ES Modules**: The entire stack uses ES modules. kraiken-lib, txnBot, Ponder, and web-app all require `"type": "module"` in package.json and use `import` syntax.
- **Podman Named Volumes**: `kraiken-lib/dist/` is mounted as a named volume (`harb_kraiken-dist`). After changing module format or build configuration, delete the volume with `podman volume rm harb_kraiken-dist` and restart to force a clean rebuild.
## Handy Commands ## Handy Commands
- `foundryup` - update Foundry toolchain. - `foundryup` - update Foundry toolchain.

View file

@ -2,7 +2,7 @@
set -euo pipefail set -euo pipefail
MNEMONIC_FILE=/workspace/onchain/.secret.local MNEMONIC_FILE=/workspace/onchain/.secret.local
ANVIL_CMD=(anvil --fork-url "${FORK_URL:-https://sepolia.base.org}" --chain-id 31337 --block-time 1 --host 0.0.0.0 --port 8545) ANVIL_CMD=(anvil --fork-url "${FORK_URL:-https://sepolia.base.org}" --chain-id 31337 --block-time 1 --host 0.0.0.0 --port 8545 --threads 4 --timeout 2000 --retries 2 --fork-retry-backoff 100)
if [[ -f "$MNEMONIC_FILE" ]]; then if [[ -f "$MNEMONIC_FILE" ]]; then
MNEMONIC="$(tr -d '\n\r' <"$MNEMONIC_FILE")" MNEMONIC="$(tr -d '\n\r' <"$MNEMONIC_FILE")"

View file

@ -1,6 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Install jq if not available
if ! command -v jq >/dev/null 2>&1; then
apk add --no-cache jq >/dev/null 2>&1 || apt-get update && apt-get install -y jq >/dev/null 2>&1 || true
fi
ROOT_DIR=/workspace ROOT_DIR=/workspace
STATE_DIR=$ROOT_DIR/tmp/podman STATE_DIR=$ROOT_DIR/tmp/podman
LOG_DIR=$STATE_DIR/logs LOG_DIR=$STATE_DIR/logs
@ -35,9 +40,7 @@ log() {
wait_for_rpc() { wait_for_rpc() {
for _ in {1..120}; do for _ in {1..120}; do
if curl -s -o /dev/null -X POST "$ANVIL_RPC" \ if cast chain-id --rpc-url "$ANVIL_RPC" >/dev/null 2>&1; then
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'; then
return 0 return 0
fi fi
sleep 1 sleep 1
@ -141,7 +144,7 @@ seed_application_state() {
prime_chain() { prime_chain() {
log "Pre-mining blocks" log "Pre-mining blocks"
for _ in {1..1200}; do for _ in {1..2000}; do
cast rpc --rpc-url "$ANVIL_RPC" evm_mine >/dev/null 2>&1 || true cast rpc --rpc-url "$ANVIL_RPC" evm_mine >/dev/null 2>&1 || true
done done
} }
@ -153,6 +156,8 @@ KRAIKEN_ADDRESS=$KRAIKEN
STAKE_ADDRESS=$STAKE STAKE_ADDRESS=$STAKE
START_BLOCK=$DEPLOY_BLOCK START_BLOCK=$DEPLOY_BLOCK
PONDER_RPC_URL_BASE_SEPOLIA_LOCAL_FORK=$ANVIL_RPC PONDER_RPC_URL_BASE_SEPOLIA_LOCAL_FORK=$ANVIL_RPC
DATABASE_URL=postgresql://ponder:ponder_local@postgres:5432/ponder_local
DATABASE_SCHEMA=ponder_local_${DEPLOY_BLOCK}
EOPONDER EOPONDER
} }

View file

@ -11,12 +11,21 @@ while [[ ! -f "$CONTRACT_ENV" ]]; do
done done
cd "$PONDER_WORKDIR" cd "$PONDER_WORKDIR"
echo "[ponder-entrypoint] Installing dependencies..." echo "[ponder-entrypoint] Installing dependencies..."
npm install --no-save --loglevel error 2>&1 || { npm install --no-save --loglevel error 2>&1 || {
echo "[ponder-entrypoint] npm install failed, trying with --force" echo "[ponder-entrypoint] npm install failed, trying with --force"
npm install --force --no-save --loglevel error npm install --force --no-save --loglevel error
} }
# Load and export all environment variables from .env.local
if [[ -f .env.local ]]; then
echo "[ponder-entrypoint] Loading environment from .env.local"
set -a
source .env.local
set +a
fi
export CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING:-1} export CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING:-1}
export HOST=0.0.0.0 export HOST=0.0.0.0
export PORT=${PORT:-42069} export PORT=${PORT:-42069}

View file

@ -31,16 +31,7 @@ fi
echo "[txn-bot-entrypoint] Compiling TypeScript..." echo "[txn-bot-entrypoint] Compiling TypeScript..."
if [[ ! -f dist/index.js ]]; then if [[ ! -f dist/index.js ]]; then
echo "[txn-bot-entrypoint] Running tsc to compile kraiken-lib..." echo "[txn-bot-entrypoint] Running tsc to compile kraiken-lib..."
./node_modules/.bin/tsc \ ./node_modules/.bin/tsc 2>&1 | head -20 || {
--outDir dist \
--declaration \
--module commonjs \
--target es2020 \
--skipLibCheck \
--esModuleInterop \
--allowSyntheticDefaultImports \
--resolveJsonModule \
src/index.ts src/helpers.ts src/subgraph.ts src/__generated__/graphql.ts 2>&1 | head -20 || {
echo "[txn-bot-entrypoint] TypeScript compilation had some issues, checking if files were created..." echo "[txn-bot-entrypoint] TypeScript compilation had some issues, checking if files were created..."
} }

View file

@ -13,6 +13,7 @@ Shared TypeScript helpers used by the landing app, txnBot, and other services to
- `src/chains.ts` - Chain constants and deployment metadata. - `src/chains.ts` - Chain constants and deployment metadata.
- `src/queries/` - GraphQL operations that target the Ponder schema. - `src/queries/` - GraphQL operations that target the Ponder schema.
- `src/__generated__/graphql.ts` - Codegen output consumed throughout the stack. - `src/__generated__/graphql.ts` - Codegen output consumed throughout the stack.
- `src/abis.ts` - Contract ABIs imported directly from `onchain/out/` forge artifacts. Single source of truth for all ABI consumers.
## GraphQL Code Generation ## GraphQL Code Generation
- Schema source points to the Ponder GraphQL endpoint for the active environment. - Schema source points to the Ponder GraphQL endpoint for the active environment.
@ -30,6 +31,17 @@ Shared TypeScript helpers used by the landing app, txnBot, and other services to
- txnBot relies on the same helpers to evaluate profitability and tax windows. - txnBot relies on the same helpers to evaluate profitability and tax windows.
- When the Ponder schema changes, rerun `npm run compile` and commit regenerated types to prevent drift. - When the Ponder schema changes, rerun `npm run compile` and commit regenerated types to prevent drift.
## ES Module Architecture
- **Module Type**: This package is built as ES modules (`"type": "module"` in package.json). All consumers must support ES modules.
- **Import Extensions**: All relative imports in TypeScript source files MUST include `.js` extensions (e.g., `from "./helpers.js"`). This is required for ES module resolution even though the source files are `.ts`.
- **JSON Imports**: JSON files (like ABI artifacts) must use import assertions: `import Foo from './path.json' assert { type: 'json' }`.
- **TypeScript Config**: `tsconfig.json` must specify:
- `"module": "esnext"` - Generate ES module syntax
- `"moduleResolution": "node"` - Enable proper module resolution
- `"rootDir": "./src"` - Ensure flat output structure in `dist/`
- **Build Output**: Running `npx tsc` produces ES module `.js` files in `dist/` that can be consumed by both browser (Vite) and Node.js (≥14 with `"type": "module"`).
- **Container Volumes**: In Podman/Docker setups, `dist/` is often a named volume. After changing module format or imports, delete the volume (`podman volume rm harb_kraiken-dist`) before restarting to force a clean rebuild.
## Quality Guidelines ## Quality Guidelines
- Keep helpers pure and side-effect free; they should accept explicit dependencies. - Keep helpers pure and side-effect free; they should accept explicit dependencies.
- Prefer narrow exports so downstream consumers can tree-shake bundles. - Prefer narrow exports so downstream consumers can tree-shake bundles.

View file

@ -213,6 +213,7 @@
"integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.2", "@babel/code-frame": "^7.24.2",
@ -2893,6 +2894,7 @@
"integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==", "integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.13.0" "undici-types": "~7.13.0"
} }
@ -3402,6 +3404,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001587", "caniuse-lite": "^1.0.30001587",
"electron-to-chromium": "^1.4.668", "electron-to-chromium": "^1.4.668",
@ -4617,6 +4620,7 @@
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
"integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
} }
@ -4701,6 +4705,7 @@
"integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"workspaces": [ "workspaces": [
"website" "website"
], ],
@ -5344,6 +5349,7 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "^29.7.0", "@jest/core": "^29.7.0",
"@jest/types": "^29.6.3", "@jest/types": "^29.6.3",
@ -7862,6 +7868,7 @@
"integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -8154,6 +8161,7 @@
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },

View file

@ -2,8 +2,15 @@
"name": "kraiken-lib", "name": "kraiken-lib",
"version": "0.2.0", "version": "0.2.0",
"description": "helper functions and snatch selection", "description": "helper functions and snatch selection",
"type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"files": [ "files": [
"/dist" "/dist"
], ],

View file

@ -5,8 +5,8 @@
* To update: run `forge build` in onchain/ directory * To update: run `forge build` in onchain/ directory
*/ */
const KraikenForgeOutput = require('../../onchain/out/Kraiken.sol/Kraiken.json'); import KraikenForgeOutput from '../../onchain/out/Kraiken.sol/Kraiken.json' assert { type: 'json' };
const StakeForgeOutput = require('../../onchain/out/Stake.sol/Stake.json'); import StakeForgeOutput from '../../onchain/out/Stake.sol/Stake.json' assert { type: 'json' };
/** /**
* Kraiken ERC20 token contract ABI * Kraiken ERC20 token contract ABI

View file

@ -1,4 +1,4 @@
export * from "./staking"; export * from "./staking.js";
export * from "./snatch"; export * from "./snatch.js";
export * from "./ids"; export * from "./ids.js";
export * from "./taxRates"; export * from "./taxRates.js";

View file

@ -1,4 +1,4 @@
import { bytesToUint256LittleEndian } from "./subgraph"; import { bytesToUint256LittleEndian } from "./subgraph.js";
export function toBigIntId(id: string | Uint8Array | number | bigint): bigint { export function toBigIntId(id: string | Uint8Array | number | bigint): bigint {
if (typeof id === "bigint") return id; if (typeof id === "bigint") return id;

View file

@ -1,20 +1,20 @@
export { export {
bytesToUint256LittleEndian, bytesToUint256LittleEndian,
uint256ToBytesLittleEndian, uint256ToBytesLittleEndian,
} from "./subgraph"; } from "./subgraph.js";
// Backward compatible aliases // Backward compatible aliases
export { export {
bytesToUint256LittleEndian as bytesToUint256, bytesToUint256LittleEndian as bytesToUint256,
uint256ToBytesLittleEndian as uint256ToBytes, uint256ToBytesLittleEndian as uint256ToBytes,
} from "./subgraph"; } from "./subgraph.js";
export { TAX_RATE_OPTIONS, type TaxRateOption } from "./taxRates"; export { TAX_RATE_OPTIONS, type TaxRateOption } from "./taxRates.js";
export { export {
calculateSnatchShortfall, calculateSnatchShortfall,
isPositionDelinquent, isPositionDelinquent,
} from "./staking"; } from "./staking.js";
export { export {
minimumTaxRate, minimumTaxRate,
@ -23,8 +23,8 @@ export {
type SnatchablePosition, type SnatchablePosition,
type SnatchSelectionOptions, type SnatchSelectionOptions,
type SnatchSelectionResult, type SnatchSelectionResult,
} from "./snatch"; } from "./snatch.js";
export { decodePositionId } from "./ids"; export { decodePositionId } from "./ids.js";
export { KraikenAbi, StakeAbi, ABIS } from "./abis"; export { KraikenAbi, StakeAbi, ABIS } from "./abis.js";

View file

@ -1,5 +1,5 @@
import type { Position } from "./__generated__/graphql"; import type { Position } from "./__generated__/graphql.js";
import { toBigIntId } from "./ids"; import { toBigIntId } from "./ids.js";
export interface SnatchablePosition { export interface SnatchablePosition {
id: bigint; id: bigint;

View file

@ -1,12 +1,14 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "esnext",
"target": "es2020", "target": "es2020",
"declaration": true, "declaration": true,
"outDir": "./dist", "outDir": "./dist",
"rootDir": "./src",
"skipLibCheck": true, "skipLibCheck": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "node",
"types": ["node"] "types": ["node"]
}, },
"include": [ "include": [

View file

@ -10,9 +10,16 @@
## Development Workflow ## Development Workflow
- Tooling: Foundry (`forge build`, `forge test`, `forge fmt`, `forge snapshot`), Anvil for local chain, Base Sepolia deployment script (`forge script ...BaseSepoliaDeploy`). - Tooling: Foundry (`forge build`, `forge test`, `forge fmt`, `forge snapshot`), Anvil for local chain, Base Sepolia deployment script (`forge script ...BaseSepoliaDeploy`).
- Repo structure highlights: `src/` (core contracts), `test/helpers/` (Uniswap/Kraiken bases), `lib/uni-v3-lib` (math + JS setup), `script/` (deploy), `out/` (artifacts), config via `foundry.toml` & `remappings.txt`. - Repo structure highlights: `src/` (core contracts), `test/helpers/` (Uniswap/Kraiken bases), `lib/uni-v3-lib` (math + JS setup), `script/` (deploy), `out/` (artifacts), config via `foundry.toml` & `remappings.txt`.
- Setup steps: clone repo, init/update submodules, install `lib/uni-v3-lib` dependencies (yarn), ensure Foundry installed. - Setup steps: clone repo, init/update submodules (`git submodule update --init --recursive`), install `lib/uni-v3-lib` dependencies (`npm install` in `lib/uni-v3-lib/`), ensure Foundry installed.
- **ABI Architecture**: Contract ABIs are exported via `kraiken-lib/src/abis.ts`, which imports directly from `onchain/out/` (forge build artifacts). All consumers (ponder, web-app) import from kraiken-lib for type-safe, single-source-of-truth ABIs. Run `forge build` in `onchain/` to update ABIs across the stack. - **ABI Architecture**: Contract ABIs are exported via `kraiken-lib/src/abis.ts`, which imports directly from `onchain/out/` (forge build artifacts). All consumers (ponder, web-app) import from kraiken-lib for type-safe, single-source-of-truth ABIs. Run `forge build` in `onchain/` to update ABIs across the stack.
## Containerized Builds (Podman/Docker)
- **Git Submodules**: Must be initialized before building (`git submodule update --init --recursive`). Empty `lib/` directories cause compilation failures.
- **uni-v3-lib Dependencies**: Requires `npm install` in `lib/uni-v3-lib/` to populate `node_modules/` with Uniswap interfaces (IUniswapV3Pool, IUniswapV3Factory) and solady dependencies.
- **Foundry Image**: Use `ghcr.io/foundry-rs/foundry:latest` for containers. The image includes `forge`, `cast`, `anvil` but NOT `jq` or `curl`.
- **Root Access**: Bootstrap scripts that create deployment artifacts may need to run as root (user: "0:0") to write to mounted volumes.
- **Volume Permissions**: Use `:z` (shared SELinux label) instead of `:Z` (private) for multi-container access to the same mount.
## Strategy & Mechanics ## Strategy & Mechanics
- Outstanding supply excludes liquidity position balances; enforce 20% staking cap (~20k positions). - Outstanding supply excludes liquidity position balances; enforce 20% staking cap (~20k positions).
- Anchor width and discovery depth adjusted dynamically; anchorShare tunes ETH allocation, discoveryDepth controls liquidity density multiples (≈2x-10x), capitalInefficiency shifts VWAP floor valuation (70%-170%). - Anchor width and discovery depth adjusted dynamically; anchorShare tunes ETH allocation, discoveryDepth controls liquidity density multiples (≈2x-10x), capitalInefficiency shifts VWAP floor valuation (70%-170%).

115
package-lock.json generated
View file

@ -22,7 +22,6 @@
"os": [ "os": [
"aix" "aix"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -40,7 +39,6 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -58,7 +56,6 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -76,7 +73,6 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -94,7 +90,6 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -112,7 +107,6 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -130,7 +124,6 @@
"os": [ "os": [
"freebsd" "freebsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -148,7 +141,6 @@
"os": [ "os": [
"freebsd" "freebsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -166,7 +158,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -184,7 +175,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -202,7 +192,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -220,7 +209,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -238,7 +226,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -256,7 +243,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -274,7 +260,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -292,7 +277,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -310,7 +294,6 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -328,7 +311,6 @@
"os": [ "os": [
"netbsd" "netbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -346,7 +328,6 @@
"os": [ "os": [
"netbsd" "netbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -364,7 +345,6 @@
"os": [ "os": [
"openbsd" "openbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -382,7 +362,6 @@
"os": [ "os": [
"openbsd" "openbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -400,7 +379,6 @@
"os": [ "os": [
"openharmony" "openharmony"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -418,7 +396,6 @@
"os": [ "os": [
"sunos" "sunos"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -436,7 +413,6 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -454,7 +430,6 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -472,7 +447,6 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -1263,8 +1237,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.52.2", "version": "4.52.2",
@ -1278,8 +1251,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.52.2", "version": "4.52.2",
@ -1293,8 +1265,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.52.2", "version": "4.52.2",
@ -1308,8 +1279,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.52.2", "version": "4.52.2",
@ -1323,8 +1293,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"freebsd" "freebsd"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.52.2", "version": "4.52.2",
@ -1338,8 +1307,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"freebsd" "freebsd"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.52.2", "version": "4.52.2",
@ -1353,8 +1321,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.52.2", "version": "4.52.2",
@ -1368,8 +1335,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1383,8 +1349,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.52.2", "version": "4.52.2",
@ -1398,8 +1363,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-loong64-gnu": { "node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1413,8 +1377,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-ppc64-gnu": { "node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1428,8 +1391,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1443,8 +1405,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-riscv64-musl": { "node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.52.2", "version": "4.52.2",
@ -1458,8 +1419,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1473,8 +1433,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1488,8 +1447,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.52.2", "version": "4.52.2",
@ -1503,8 +1461,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-openharmony-arm64": { "node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.52.2", "version": "4.52.2",
@ -1518,8 +1475,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"openharmony" "openharmony"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.52.2", "version": "4.52.2",
@ -1533,8 +1489,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.52.2", "version": "4.52.2",
@ -1548,8 +1503,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-win32-x64-gnu": { "node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.52.2", "version": "4.52.2",
@ -1563,8 +1517,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ]
"peer": true
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.52.2", "version": "4.52.2",
@ -1578,8 +1531,7 @@
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ]
"peer": true
}, },
"node_modules/@skorotkiewicz/snowflake-id": { "node_modules/@skorotkiewicz/snowflake-id": {
"version": "1.0.1", "version": "1.0.1",
@ -1874,8 +1826,7 @@
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/accepts": { "node_modules/accepts": {
"version": "2.0.0", "version": "2.0.0",
@ -2219,7 +2170,6 @@
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"esbuild": "bin/esbuild" "esbuild": "bin/esbuild"
}, },
@ -2301,6 +2251,7 @@
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"accepts": "^2.0.0", "accepts": "^2.0.0",
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
@ -2374,7 +2325,6 @@
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"
}, },
@ -2636,6 +2586,7 @@
"integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==", "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"jiti": "lib/jiti-cli.mjs" "jiti": "lib/jiti-cli.mjs"
} }
@ -2660,6 +2611,7 @@
"integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
"dev": true, "dev": true,
"license": "MPL-2.0", "license": "MPL-2.0",
"peer": true,
"dependencies": { "dependencies": {
"detect-libc": "^2.0.3" "detect-libc": "^2.0.3"
}, },
@ -3031,7 +2983,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
@ -3131,8 +3082,7 @@
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC"
"peer": true
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "4.0.3", "version": "4.0.3",
@ -3244,7 +3194,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@ -3365,6 +3314,7 @@
"integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -3389,6 +3339,7 @@
"integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.26.0" "scheduler": "^0.26.0"
}, },
@ -3502,7 +3453,6 @@
"integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==", "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/estree": "1.0.8" "@types/estree": "1.0.8"
}, },
@ -3772,7 +3722,8 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==", "integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/tailwindcss-animate": { "node_modules/tailwindcss-animate": {
"version": "1.0.7", "version": "1.0.7",
@ -3821,7 +3772,6 @@
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fdir": "^6.5.0", "fdir": "^6.5.0",
"picomatch": "^4.0.3" "picomatch": "^4.0.3"
@ -3946,7 +3896,6 @@
"integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
@ -4027,7 +3976,6 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
@ -4091,6 +4039,7 @@
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }

View file

@ -2,28 +2,44 @@ version: "3.8"
services: services:
anvil: anvil:
build: image: ghcr.io/foundry-rs/foundry:latest
context: .
dockerfile: containers/foundry.Containerfile
command: ["/workspace/containers/anvil-entrypoint.sh"] command: ["/workspace/containers/anvil-entrypoint.sh"]
volumes: volumes:
- .:/workspace:Z - .:/workspace:z
expose: expose:
- "8545" - "8545"
restart: unless-stopped restart: unless-stopped
postgres:
image: docker.io/library/postgres:16-alpine
environment:
- POSTGRES_USER=ponder
- POSTGRES_PASSWORD=ponder_local
- POSTGRES_DB=ponder_local
volumes:
- postgres-data:/var/lib/postgresql/data
expose:
- "5432"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ponder"]
interval: 5s
timeout: 5s
retries: 5
bootstrap: bootstrap:
build: image: ghcr.io/foundry-rs/foundry:latest
context: . user: "0:0"
dockerfile: containers/foundry.Containerfile
command: ["/workspace/containers/bootstrap.sh"] command: ["/workspace/containers/bootstrap.sh"]
volumes: volumes:
- .:/workspace:Z - .:/workspace:z
environment: environment:
- ANVIL_RPC=http://anvil:8545 - ANVIL_RPC=http://anvil:8545
depends_on: depends_on:
anvil: anvil:
condition: service_started condition: service_started
postgres:
condition: service_healthy
restart: "no" restart: "no"
ponder: ponder:
@ -38,7 +54,10 @@ services:
environment: environment:
- CHOKIDAR_USEPOLLING=1 - CHOKIDAR_USEPOLLING=1
depends_on: depends_on:
- anvil anvil:
condition: service_started
postgres:
condition: service_healthy
expose: expose:
- "42069" - "42069"
restart: unless-stopped restart: unless-stopped
@ -98,7 +117,7 @@ services:
caddy: caddy:
image: docker.io/library/caddy:2.8 image: docker.io/library/caddy:2.8
volumes: volumes:
- ./containers/Caddyfile:/etc/caddy/Caddyfile:Z - ./containers/Caddyfile:/etc/caddy/Caddyfile:z
ports: ports:
- "0.0.0.0:8081:80" - "0.0.0.0:8081:80"
depends_on: depends_on:
@ -115,6 +134,7 @@ services:
restart: unless-stopped restart: unless-stopped
volumes: volumes:
postgres-data:
webapp-node-modules: webapp-node-modules:
landing-node-modules: landing-node-modules:
ponder-node-modules: ponder-node-modules:

View file

@ -15,6 +15,7 @@ Ponder-based indexer that records Kraiken protocol activity and exposes the Grap
## Development Workflow ## Development Workflow
- Primary path: `nohup ./scripts/local_env.sh start &` boots Anvil, deploys contracts, and launches Ponder in watch mode. - Primary path: `nohup ./scripts/local_env.sh start &` boots Anvil, deploys contracts, and launches Ponder in watch mode.
- Podman stack: `podman-compose up -d` starts all services including PostgreSQL; bootstrap creates `.env.local` automatically.
- Focused debugging: within `services/ponder/`, run `npm install` then `PONDER_NETWORK=BASE_SEPOLIA_LOCAL_FORK npm run dev` once the stack is already online. - Focused debugging: within `services/ponder/`, run `npm install` then `PONDER_NETWORK=BASE_SEPOLIA_LOCAL_FORK npm run dev` once the stack is already online.
- For production-style runs, use `npm run build` followed by `PONDER_NETWORK=BASE npm run start` and point `DATABASE_URL` to PostgreSQL if persistence is required. - For production-style runs, use `npm run build` followed by `PONDER_NETWORK=BASE npm run start` and point `DATABASE_URL` to PostgreSQL if persistence is required.
@ -23,6 +24,18 @@ Ponder-based indexer that records Kraiken protocol activity and exposes the Grap
- Regenerate typings after schema edits by restarting Ponder; generated artifacts live in `generated/`. - Regenerate typings after schema edits by restarting Ponder; generated artifacts live in `generated/`.
- If the stack script fails during boot, check `.ponder/logs` and RPC quota usage before rerunning. - If the stack script fails during boot, check `.ponder/logs` and RPC quota usage before rerunning.
## Containerized Environment (Podman/Docker)
- **Environment Loading**: `.env.local` must be explicitly sourced in the entrypoint script before `npm run dev`. Ponder's built-in env loader may not find it in containerized environments.
- **Virtual Module Errors**: If you see `Failed to load url ponder:registry/ponder:schema/ponder:api`, check:
1. `DATABASE_URL` is properly set and accessible
2. kraiken-lib ABIs exist (`onchain/out/Kraiken.sol/Kraiken.json`)
3. kraiken-lib TypeScript is built (`kraiken-lib/dist/index.js`)
4. `ponder-env.d.ts` is writable by the container user (chmod 666 or pre-create it)
5. Ponder version is 0.13.8+ (earlier versions had virtual module generation bugs)
- **PostgreSQL Connection**: Requires `DATABASE_URL` env var; Ponder falls back to PGlite if not set. The entrypoint must export this before Ponder starts.
- **File Permissions**: Container runs as `node` user; ensure `ponder-env.d.ts` is writable (created with 666 permissions on host).
- **API Endpoint Requirement**: Ponder 0.13.8+ requires `src/api/index.ts` to exist, even if you only use GraphQL. Missing it causes "API endpoint file not found" errors.
## Quality Checks ## Quality Checks
- Avoid reintroducing legacy subgraph assumptions; rely solely on Ponder schema helpers. - Avoid reintroducing legacy subgraph assumptions; rely solely on Ponder schema helpers.
- Keep handler logic deterministic and idempotent; reorgs trigger replays. - Keep handler logic deterministic and idempotent; reorgs trigger replays.

View file

@ -11,7 +11,7 @@
"@ponder/core": "^0.7.17", "@ponder/core": "^0.7.17",
"hono": "^4.5.0", "hono": "^4.5.0",
"kraiken-lib": "file:../../kraiken-lib", "kraiken-lib": "file:../../kraiken-lib",
"ponder": "^0.13.6", "ponder": "^0.13.8",
"viem": "^2.21.0" "viem": "^2.21.0"
}, },
"devDependencies": { "devDependencies": {
@ -37,6 +37,7 @@
"@graphql-codegen/typescript-operations": "^4.2.0", "@graphql-codegen/typescript-operations": "^4.2.0",
"@graphql-typed-document-node/core": "^3.2.0", "@graphql-typed-document-node/core": "^3.2.0",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/node": "^24.6.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"typescript": "^5.4.3" "typescript": "^5.4.3"
@ -109,7 +110,8 @@
"version": "0.2.13", "version": "0.2.13",
"resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.2.13.tgz", "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.2.13.tgz",
"integrity": "sha512-YRY806NnScVqa21/1L1vaysSQ+0/cAva50z7vlwzaGiBOTS9JhdzIRHN0KfgMhobFAphbznZJ7urMso4RtMBIQ==", "integrity": "sha512-YRY806NnScVqa21/1L1vaysSQ+0/cAva50z7vlwzaGiBOTS9JhdzIRHN0KfgMhobFAphbznZJ7urMso4RtMBIQ==",
"license": "Apache-2.0" "license": "Apache-2.0",
"peer": true
}, },
"node_modules/@envelop/core": { "node_modules/@envelop/core": {
"version": "5.3.2", "version": "5.3.2",
@ -1011,6 +1013,7 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"engines": { "engines": {
"node": ">=8.0.0" "node": ">=8.0.0"
} }
@ -1226,6 +1229,7 @@
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.26.3.tgz", "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.26.3.tgz",
"integrity": "sha512-yWSgGi9bY13b/W06DD2OCDDHQmq1kwTGYlQ4wpZkMOJqMGCstVCFIvxCCVG4KfY1/3G0MhDAcZsip/Lw8/vJWw==", "integrity": "sha512-yWSgGi9bY13b/W06DD2OCDDHQmq1kwTGYlQ4wpZkMOJqMGCstVCFIvxCCVG4KfY1/3G0MhDAcZsip/Lw8/vJWw==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
} }
@ -1609,6 +1613,7 @@
"integrity": "sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==", "integrity": "sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
} }
@ -2139,6 +2144,7 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@ -2971,6 +2977,7 @@
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz",
"integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
} }
@ -3028,6 +3035,7 @@
"resolved": "https://registry.npmjs.org/hono/-/hono-4.9.8.tgz", "resolved": "https://registry.npmjs.org/hono/-/hono-4.9.8.tgz",
"integrity": "sha512-JW8Bb4RFWD9iOKxg5PbUarBYGM99IcxFl2FPBo2gSJO11jjUDqlP1Bmfyqt8Z/dGhIQ63PMA9LdcLefXyIasyg==", "integrity": "sha512-JW8Bb4RFWD9iOKxg5PbUarBYGM99IcxFl2FPBo2gSJO11jjUDqlP1Bmfyqt8Z/dGhIQ63PMA9LdcLefXyIasyg==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.9.0"
} }
@ -3967,6 +3975,7 @@
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"pg-connection-string": "^2.9.1", "pg-connection-string": "^2.9.1",
"pg-pool": "^3.10.1", "pg-pool": "^3.10.1",
@ -4123,9 +4132,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/ponder": { "node_modules/ponder": {
"version": "0.13.6", "version": "0.13.8",
"resolved": "https://registry.npmjs.org/ponder/-/ponder-0.13.6.tgz", "resolved": "https://registry.npmjs.org/ponder/-/ponder-0.13.8.tgz",
"integrity": "sha512-/LtSCfso7yshF7t7irNJyfQWvLfGI65quJiG4zaE902+coGm6YX9dqoVM+CxRtnOudSADTLsC3U3HAOJFfQXWQ==", "integrity": "sha512-Eqj4ZBpft6/WOZdbW1XIVoUsrdMtfZMEtfX7P4wBgqc1YCSHCOFtQmLUB2QxAe/Qw+sO+eiCCk+BDCCMEXlOYA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.23.4", "@babel/code-frame": "^7.23.4",
@ -4326,6 +4335,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
}, },
@ -5017,6 +5027,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -5080,6 +5091,7 @@
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -5145,6 +5157,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@noble/curves": "1.9.1", "@noble/curves": "1.9.1",
"@noble/hashes": "1.8.0", "@noble/hashes": "1.8.0",
@ -5429,6 +5442,7 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },

View file

@ -13,7 +13,7 @@
"@ponder/core": "^0.7.17", "@ponder/core": "^0.7.17",
"hono": "^4.5.0", "hono": "^4.5.0",
"kraiken-lib": "file:../../kraiken-lib", "kraiken-lib": "file:../../kraiken-lib",
"ponder": "^0.13.6", "ponder": "^0.13.8",
"viem": "^2.21.0" "viem": "^2.21.0"
}, },
"devDependencies": { "devDependencies": {

View file

@ -9,12 +9,6 @@ declare module "ponder:schema" {
export * from "./ponder.schema.ts"; export * from "./ponder.schema.ts";
} }
declare module "*.json" {
import type { Abi } from 'viem'
const value: { abi: Abi }
export default value
}
// This file enables type checking and editor autocomplete for this Ponder project. // This file enables type checking and editor autocomplete for this Ponder project.
// After upgrading, you may find that changes have been made to this file. // After upgrading, you may find that changes have been made to this file.
// If this happens, please commit the changes. Do not manually edit this file. // If this happens, please commit the changes. Do not manually edit this file.

View file

@ -11,6 +11,8 @@ Automation service that maintains liquidity alignment and tax enforcement for th
- `service.js` - Main loop that polls the GraphQL endpoint, evaluates triggers, and submits transactions. - `service.js` - Main loop that polls the GraphQL endpoint, evaluates triggers, and submits transactions.
- `generateKey.js` - Utility for provisioning dedicated bot wallets. - `generateKey.js` - Utility for provisioning dedicated bot wallets.
- `package.json` scripts - `npm install`, `npm start`, and debug runs via `DEBUG=* npm start`. - `package.json` scripts - `npm install`, `npm start`, and debug runs via `DEBUG=* npm start`.
- **ES Module**: This service uses `"type": "module"` and imports kraiken-lib as an ES module. All imports use ES module syntax (`import` instead of `require()`).
- **Node.js Compatibility**: Requires Node.js ≥14 with ES module support. The `__dirname` and `__filename` globals are not available; use `import.meta.url` with `fileURLToPath()` instead.
## Configuration ## Configuration
Set the following environment variables (automatically generated when the stack script is used): Set the following environment variables (automatically generated when the stack script is used):

View file

@ -1,6 +1,7 @@
{ {
"name": "marketMaker", "name": "marketMaker",
"version": "0.0.1", "version": "0.0.1",
"type": "module",
"main": "index.js", "main": "index.js",
"license": "GPL3", "license": "GPL3",
"scripts": { "scripts": {

View file

@ -1,13 +1,19 @@
const path = require('path'); import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
import { ethers } from 'ethers';
import express from 'express';
import { decodePositionId } from 'kraiken-lib/ids';
import { isPositionDelinquent } from 'kraiken-lib/staking';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const dotenvPath = process.env.TXN_BOT_ENV_FILE const dotenvPath = process.env.TXN_BOT_ENV_FILE
? path.resolve(process.env.TXN_BOT_ENV_FILE) ? path.resolve(process.env.TXN_BOT_ENV_FILE)
: path.resolve(__dirname, '.env'); : path.resolve(__dirname, '.env');
require('dotenv').config({ path: dotenvPath }); dotenv.config({ path: dotenvPath });
const { ethers } = require('ethers');
const express = require('express');
const { decodePositionId } = require('kraiken-lib/ids');
const { isPositionDelinquent } = require('kraiken-lib/staking');
const ACTIVE_POSITIONS_QUERY = ` const ACTIVE_POSITIONS_QUERY = `
query ActivePositions { query ActivePositions {