Compare commits

...

23 commits

Author SHA1 Message Date
openhands
ce87847f4e web-app: move env declaration into src and guard pipefail 2025-10-13 19:05:15 +00:00
openhands
d2c1f9c84f ci: switch npm ci to npm install for workspace deps 2025-10-13 18:20:47 +00:00
openhands
ea0d35486b ci: export foundry path in runner scripts 2025-10-13 18:15:13 +00:00
openhands
d351acde78 ci: pin node/playwright images to ci-20251013 tag 2025-10-13 18:12:14 +00:00
openhands
d0ebb0ecf1 ci: adjust yarn --cwd invocation 2025-10-13 18:03:14 +00:00
openhands
953bec25c5 ci: prebuild node/playwright images and switch woodpecker 2025-10-13 17:01:51 +00:00
openhands
76e197a21b Fix npm workspaces in CI 2025-10-12 19:54:02 +00:00
openhands
ea0226179c Drop forge size check in CI 2025-10-12 19:27:23 +00:00
openhands
7aba3bb87e Disable bytecode limit for maxperf profile 2025-10-12 19:23:13 +00:00
openhands
f7e0b4fd24 Disable Foundry bytecode size enforcement for tests 2025-10-12 19:13:42 +00:00
openhands
861bad5b00 Raise local bytecode limit for test helpers 2025-10-12 17:44:53 +00:00
openhands
10f011f136 Install uni-v3-lib dependencies before Foundry runs 2025-10-12 17:30:29 +00:00
openhands
9637fe6df1 Use Foundry prebuilt image for solidity workflows 2025-10-12 17:20:01 +00:00
openhands
91f19539d9 Run foundry suite before node lint 2025-10-12 17:07:47 +00:00
openhands
c2f1690b0d Preserve multiline bash scripts in pipelines 2025-10-12 16:59:55 +00:00
openhands
3915e121bd Wrap docker steps in bash shells 2025-10-12 16:56:42 +00:00
openhands
06b5f6302c Tune release workflow filters 2025-10-12 16:52:44 +00:00
openhands
12f322d441 Run release workflow in containerized steps 2025-10-12 16:28:39 +00:00
openhands
31728401ce Remove shell brace expansions in release workflow 2025-10-12 16:26:33 +00:00
openhands
f5617ad9bf Scope PATH setup to e2e step 2025-10-12 16:18:58 +00:00
openhands
3195ab8725 Use simple runtime dir expansion in e2e workflow 2025-10-12 16:17:46 +00:00
openhands
66cfaed355 Refine Woodpecker e2e workflow 2025-10-12 16:11:17 +00:00
openhands
c8180a30f3 Add Woodpecker pipelines 2025-10-12 15:59:11 +00:00
11 changed files with 508 additions and 25 deletions

60
.woodpecker/ci.yml Normal file
View file

@ -0,0 +1,60 @@
kind: pipeline
type: docker
name: ci
trigger:
event:
- push
- pull_request
steps:
- name: bootstrap-deps
image: registry.sovraigns.network/harb/node-ci:ci-20251013
commands:
- |
bash -lc '
set -euo pipefail
git submodule update --init --recursive
yarn --cwd onchain/lib/uni-v3-lib install --frozen-lockfile
'
- name: foundry-suite
image: registry.sovraigns.network/harb/node-ci:ci-20251013
commands:
- |
bash -lc '
set -euo pipefail
cd onchain
export PATH=/root/.foundry/bin:$PATH
forge --version
forge build
forge test -vvv
forge snapshot
'
- name: node-quality
image: registry.sovraigns.network/harb/node-ci:ci-20251013
environment:
CI: "true"
commands:
- |
bash -lc '
set -euo pipefail
npm config set fund false
npm config set audit false
./scripts/build-kraiken-lib.sh
npm install --prefix landing --no-audit --no-fund
npm run lint --prefix landing
npm run build --prefix landing
npm install --prefix web-app --no-audit --no-fund
npm run lint --prefix web-app
npm run test --prefix web-app -- --run
npm run build --prefix web-app
npm install --prefix services/ponder --no-audit --no-fund
npm run lint --prefix services/ponder
npm run build --prefix services/ponder
npm install --prefix services/txnBot --no-audit --no-fund
npm run lint --prefix services/txnBot
npm run test --prefix services/txnBot -- --runInBand
npm run build --prefix services/txnBot
'

74
.woodpecker/contracts.yml Normal file
View file

@ -0,0 +1,74 @@
kind: pipeline
type: docker
name: contracts-local-fork
trigger:
event:
- push
- pull_request
steps:
- name: bootstrap-deps
image: registry.sovraigns.network/harb/node-ci:ci-20251013
commands:
- |
bash -lc '
set -euo pipefail
git submodule update --init --recursive
yarn --cwd onchain/lib/uni-v3-lib install --frozen-lockfile
'
- name: forge-suite
image: registry.sovraigns.network/harb/node-ci:ci-20251013
environment:
HARB_ENV: BASE_SEPOLIA_LOCAL_FORK
commands:
- |
bash -lc '
set -euo pipefail
cd onchain
export PATH=/root/.foundry/bin:$PATH
forge build
forge test -vv --ffi
forge snapshot
'
---
kind: pipeline
type: docker
name: contracts-base-sepolia
trigger:
event:
- push
- pull_request
steps:
- name: bootstrap-deps
image: registry.sovraigns.network/harb/node-ci:ci-20251013
commands:
- |
bash -lc '
set -euo pipefail
git submodule update --init --recursive
yarn --cwd onchain/lib/uni-v3-lib install --frozen-lockfile
'
- name: forge-suite
image: registry.sovraigns.network/harb/node-ci:latest
environment:
HARB_ENV: BASE_SEPOLIA
BASE_SEPOLIA_RPC:
from_secret: base_sepolia_rpc
commands:
- |
bash -lc '
set -euo pipefail
cd onchain
export BASE_SEPOLIA_RPC="$BASE_SEPOLIA_RPC"
export PATH=/root/.foundry/bin:$PATH
forge build
forge test -vv --ffi
forge snapshot
'

60
.woodpecker/e2e.yml Normal file
View file

@ -0,0 +1,60 @@
kind: pipeline
type: docker
name: e2e
labels:
podman: "true"
trigger:
event:
- push
- pull_request
steps:
- name: run-e2e
image: registry.sovraigns.network/harb/playwright-ci:ci-20251013
privileged: true
environment:
PNPM_HOME: /root/.local/share/pnpm
PATH: /root/.local/share/pnpm:/root/.local/bin:/usr/local/bin:/usr/bin:/bin
HARB_ENV: BASE_SEPOLIA_LOCAL_FORK
SKIP_WATCH: "1"
XDG_RUNTIME_DIR: /tmp/podman-run
commands:
- |
set -eu
set -o pipefail 2>/dev/null || true
mkdir -p "$XDG_RUNTIME_DIR"
git submodule update --init --recursive
yarn --cwd onchain/lib/uni-v3-lib install --frozen-lockfile
npm config set fund false
npm config set audit false
npm install --prefix kraiken-lib --no-audit --no-fund
./scripts/build-kraiken-lib.sh
npm install --prefix landing --no-audit --no-fund
npm install --prefix web-app --no-audit --no-fund
npm install --prefix services/ponder --no-audit --no-fund
npm install --prefix services/txnBot --no-audit --no-fund
npm install --no-audit --no-fund
npx playwright install chromium
trap "./scripts/dev.sh stop || true" EXIT
./scripts/dev.sh start
timeout 240 bash -c 'until curl -sf http://localhost:8081/api/graphql > /dev/null; do sleep 3; done'
npm run test:e2e
- name: collect-artifacts
image: alpine:3.20
depends_on:
- run-e2e
when:
status:
- success
- failure
commands:
- |
set -euo pipefail
apk add --no-cache tar gzip
mkdir -p artifacts
if [ -d playwright-report ]; then tar -czf artifacts/playwright-report.tgz playwright-report; fi
if [ -d test-results ]; then tar -czf artifacts/test-results.tgz test-results; fi
if [ -d logs ]; then tar -czf artifacts/stack-logs.tgz logs; fi

View file

@ -0,0 +1,46 @@
kind: pipeline
type: docker
name: fuzz-nightly
trigger:
event:
- cron
steps:
- name: bootstrap-deps
image: registry.sovraigns.network/harb/node-ci:ci-20251013
commands:
- |
bash -lc '
set -euo pipefail
git submodule update --init --recursive
yarn --cwd onchain/lib/uni-v3-lib install --frozen-lockfile
'
- name: fuzz
image: registry.sovraigns.network/harb/node-ci:ci-20251013
commands:
- |
bash -lc '
set -euo pipefail
if ! command -v bc >/dev/null 2>&1; then
apt-get update
apt-get install -y bc
fi
cd onchain
export PATH=/root/.foundry/bin:$PATH
forge --version
./analysis/run-fuzzing.sh BullMarketOptimizer runs=75
'
- name: package-results
image: alpine:3.20
when:
status:
- success
- failure
commands:
- set -e
- apk add --no-cache tar
- mkdir -p artifacts
- if [ -d onchain/analysis ]; then tar -czf artifacts/fuzz-results.tgz onchain/analysis; fi

178
.woodpecker/release.yml Normal file
View file

@ -0,0 +1,178 @@
kind: pipeline
type: docker
name: release
labels:
podman: "true"
when:
event: tag
steps:
- name: version-check
image: registry.sovraigns.network/harb/node-ci:ci-20251013
when:
event: tag
commands:
- |
bash -lc '
set -euo pipefail
git submodule update --init --recursive
corepack enable
yarn --cwd onchain/lib/uni-v3-lib install --frozen-lockfile
npm config set fund false
npm config set audit false
npm install --prefix kraiken-lib --no-audit --no-fund
./scripts/build-kraiken-lib.sh
node <<\"NODE\"
import fs from \"fs\";
const sol = fs.readFileSync(\"onchain/src/Kraiken.sol\", \"utf8\");
const lib = fs.readFileSync(\"kraiken-lib/src/version.ts\", \"utf8\");
const contractVersionMatch = sol.match(/VERSION\\s*=\\s*(\\d+)/);
if (!contractVersionMatch) {
console.error(\"Unable to find VERSION constant in Kraiken.sol\");
process.exit(1);
}
const contractVersion = Number(contractVersionMatch[1]);
const libVersionMatch = lib.match(/KRAIKEN_LIB_VERSION\\s*=\\s*(\\d+)/);
if (!libVersionMatch) {
console.error(\"Unable to find KRAIKEN_LIB_VERSION in kraiken-lib/src/version.ts\");
process.exit(1);
}
const libVersion = Number(libVersionMatch[1]);
const compatMatch = lib.match(/COMPATIBLE_CONTRACT_VERSIONS\\s*=\\s*\\[([^\\]]*)\\]/);
if (!compatMatch) {
console.error(\"Unable to find COMPATIBLE_CONTRACT_VERSIONS in kraiken-lib/src/version.ts\");
process.exit(1);
}
const compatibleVersions = compatMatch[1]
.split(\",\")
.map(v => v.trim())
.filter(Boolean)
.map(Number);
if (contractVersion !== libVersion) {
console.error(\"Contract VERSION (\" + contractVersion + \") and KRAIKEN_LIB_VERSION (\" + libVersion + \") differ\");
process.exit(1);
}
if (!compatibleVersions.includes(contractVersion)) {
console.error(\"Contract VERSION \" + contractVersion + \" missing from COMPATIBLE_CONTRACT_VERSIONS [\" + compatibleVersions.join(\", \") + \"]\");
process.exit(1);
}
console.log(\"Version check passed for VERSION \" + contractVersion);
NODE
'
- name: build-artifacts
image: registry.sovraigns.network/harb/node-ci:ci-20251013
depends_on:
- version-check
when:
event: tag
commands:
- |
bash -lc '
set -euo pipefail
npm config set fund false
npm config set audit false
npm install --prefix kraiken-lib --no-audit --no-fund
./scripts/build-kraiken-lib.sh
npm install --prefix landing --no-audit --no-fund
npm install --prefix web-app --no-audit --no-fund
npm install --prefix services/ponder --no-audit --no-fund
npm install --prefix services/txnBot --no-audit --no-fund
npm install --no-audit --no-fund
export PATH=/root/.foundry/bin:$PATH
forge --version
(cd onchain && forge build)
npm run build --prefix landing
npm run build --prefix web-app
npm run build --prefix services/ponder
npm run build --prefix services/txnBot
rm -rf release
mkdir -p release/dist
cp -r onchain/out release/dist/abi
cp -r kraiken-lib/dist release/dist/kraiken-lib
cp -r landing/dist release/dist/landing
cp -r web-app/dist release/dist/web-app
cp -r services/txnBot/dist release/dist/txn-bot
if [ -d services/ponder/generated ]; then
cp -r services/ponder/generated release/dist/ponder-generated
fi
tar -czf release-bundle.tgz -C release dist
'
- name: podman-publish
image: registry.sovraigns.network/harb/playwright-ci:ci-20251013
pull: true
privileged: true
depends_on:
- build-artifacts
when:
event: tag
environment:
REGISTRY_SERVER:
from_secret: registry_server
REGISTRY_NAMESPACE:
from_secret: registry_namespace
REGISTRY_USERNAME:
from_secret: registry_username
REGISTRY_PASSWORD:
from_secret: registry_password
commands:
- |
bash -lc '
set -eo pipefail
if [ -z "${CI_COMMIT_TAG:-}" ]; then
echo "CI_COMMIT_TAG not set" >&2
exit 1
fi
if [ -z "${REGISTRY_SERVER:-}" ] || [ -z "${REGISTRY_NAMESPACE:-}" ]; then
echo "Registry server or namespace missing" >&2
exit 1
fi
TAG=$(printf '%s' "$CI_COMMIT_TAG" | sed "s#^refs/tags/##")
export TAG
if [ -z "${COMPOSE_PROJECT_NAME:-}" ]; then
COMPOSE_PROJECT_NAME=harb
fi
REGISTRY_ROOT="${REGISTRY_SERVER:-registry.sovraigns.network}"
REGISTRY_NS="${REGISTRY_NAMESPACE:-harb}"
REGISTRY_BASE="$REGISTRY_ROOT/$REGISTRY_NS"
podman login "$REGISTRY_ROOT" -u "$REGISTRY_USERNAME" -p "$REGISTRY_PASSWORD"
# Build and publish CI base images
node_ci_tmp=harb-node-ci-build
playwright_ci_tmp=harb-playwright-ci-build
podman build -f docker/Dockerfile.node-ci -t "$node_ci_tmp" .
podman tag "$node_ci_tmp" "$REGISTRY_BASE/node-ci:$TAG"
podman push "$REGISTRY_BASE/node-ci:$TAG"
podman tag "$REGISTRY_BASE/node-ci:$TAG" "$REGISTRY_BASE/node-ci:latest"
podman push "$REGISTRY_BASE/node-ci:latest"
podman build -f docker/Dockerfile.playwright-ci -t "$playwright_ci_tmp" .
podman tag "$playwright_ci_tmp" "$REGISTRY_BASE/playwright-ci:$TAG"
podman push "$REGISTRY_BASE/playwright-ci:$TAG"
podman tag "$REGISTRY_BASE/playwright-ci:$TAG" "$REGISTRY_BASE/playwright-ci:latest"
podman push "$REGISTRY_BASE/playwright-ci:latest"
podman-compose build ponder webapp landing txn-bot
for service in ponder webapp landing txn-bot; do
image=$(podman image ls --filter "label=com.docker.compose.project=$COMPOSE_PROJECT_NAME" --filter "label=com.docker.compose.service=$service" --format "{{.Repository}}:{{ .Tag }}" | head -n1)
if [ -z "$image" ]; then
echo "Unable to find built image for $service" >&2
exit 1
fi
target="$REGISTRY_BASE/$service"
podman tag "$image" "$target:$TAG"
podman push "$target:$TAG"
podman tag "$target:$TAG" "$target:latest"
podman push "$target:latest"
done
'

40
docker/Dockerfile.node-ci Normal file
View file

@ -0,0 +1,40 @@
# syntax=docker/dockerfile:1.6
FROM node:20-bookworm
LABEL org.opencontainers.image.source="https://codeberg.org/johba/harb-ci"
LABEL org.opencontainers.image.description="Node.js toolchain for Harb Stack CI jobs"
ENV DEBIAN_FRONTEND=noninteractive \
PNPM_HOME=/root/.local/share/pnpm \
PATH=/root/.local/share/pnpm:/root/.local/bin:/root/.foundry/bin:$PATH
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends \
git \
ca-certificates \
build-essential \
pkg-config \
libssl-dev \
python3 \
python3-pip \
bc \
jq \
curl && \
rm -rf /var/lib/apt/lists/*
# Enable corepack-managed package managers and pin the versions we expect in CI.
RUN corepack enable && \
corepack prepare pnpm@8.15.4 --activate && \
corepack prepare yarn@1.22.19 --activate
# Install Foundry once so downstream jobs skip the bootstrap step.
RUN curl -L https://foundry.paradigm.xyz | bash && \
~/.foundry/bin/foundryup --version && \
~/.foundry/bin/foundryup
WORKDIR /workspace
CMD ["bash"]

View file

@ -0,0 +1,34 @@
# syntax=docker/dockerfile:1.6
FROM mcr.microsoft.com/playwright:v1.56.0-jammy
LABEL org.opencontainers.image.source="https://codeberg.org/johba/harb-ci"
LABEL org.opencontainers.image.description="Playwright + Podman image for Harb Stack end-to-end CI"
ENV DEBIAN_FRONTEND=noninteractive \
PNPM_HOME=/root/.local/share/pnpm \
PATH=/root/.local/share/pnpm:/root/.local/bin:$PATH
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends \
podman \
slirp4netns \
uidmap \
iptables \
git \
ca-certificates \
python3-pip \
jq \
curl && \
rm -rf /var/lib/apt/lists/*
RUN python3 -m pip install --no-cache-dir podman-compose && \
corepack enable && \
corepack prepare pnpm@8.15.4 --activate && \
corepack prepare yarn@1.22.19 --activate
WORKDIR /workspace
CMD ["bash"]

View file

@ -7,6 +7,10 @@ gas_limit = 1_000_000_000
gas_price = 0
optimizer = true
optimizer_runs = 200
bytecode_size_limit = 0
[profile.maxperf]
bytecode_size_limit = 0
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
[rpc_endpoints]

View file

@ -72,17 +72,17 @@ contract TestEnvironment is TestConstants {
using UniswapHelpers for IUniswapV3Pool;
// Core contracts
IUniswapV3Factory public factory;
IUniswapV3Pool public pool;
IWETH9 public weth;
Kraiken public harberg;
Stake public stake;
LiquidityManager public lm;
Optimizer public optimizer;
IUniswapV3Factory internal factory;
IUniswapV3Pool internal pool;
IWETH9 internal weth;
Kraiken internal harberg;
Stake internal stake;
LiquidityManager internal lm;
Optimizer internal optimizer;
// State variables
bool public token0isWeth;
address public feeDestination;
bool internal token0isWeth;
address internal feeDestination;
constructor(address _feeDestination) {
feeDestination = _feeDestination;
@ -314,17 +314,4 @@ contract TestEnvironment is TestConstants {
return (factory, pool, weth, harberg, stake, lm, optimizer, token0isWeth);
}
/**
* @notice Perform recenter with proper time warp and oracle updates
* @param liquidityManager The LiquidityManager instance to recenter
* @param caller The address that will call recenter
*/
function performRecenter(LiquidityManager liquidityManager, address caller) external {
// Update oracle time
vm.warp(block.timestamp + ORACLE_UPDATE_INTERVAL);
// Perform recenter
vm.prank(caller);
liquidityManager.recenter();
}
}

View file

@ -6,8 +6,8 @@ declare global {
interface Window {
ethereum?: EIP1193Provider;
}
const __APP_VERSION__: string;
}
declare const __APP_VERSION__: string;
export {};

View file

@ -1,6 +1,6 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"include": ["src/env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",