Skip to content

Commit d456ffb

Browse files
authored
Merge branch 'main' into fix/1278-backend-eslint
2 parents dbd0e75 + 6db14d7 commit d456ffb

59 files changed

Lines changed: 9996 additions & 229 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ jobs:
9494
run: npm run build
9595
working-directory: backend
9696

97+
- name: OpenAPI spec & API types drift check
98+
run: |
99+
cd backend
100+
npm run codegen:openapi
101+
cd ../frontend
102+
npm run codegen:api-types
103+
cd ..
104+
git diff --exit-code -- backend/swagger/flowfi.openapi.json frontend/src/lib/api-types.generated.ts
105+
97106
- name: Install Rollup Native Binding
98107
run: npm install @rollup/rollup-linux-x64-gnu --no-save
99108

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Contract Deployment Workflow for FlowFi
2+
#
3+
# Compiles the Soroban stream contract to optimized WASM, runs contract tests,
4+
# and deploys + initializes the contract on Stellar Testnet on demand (or on
5+
# Mainnet for release tags). The resulting contract ID is surfaced in the job
6+
# summary and published as a release artifact.
7+
name: Deploy Soroban Contracts
8+
9+
on:
10+
release:
11+
types: [published]
12+
workflow_dispatch:
13+
inputs:
14+
network:
15+
description: "Target network (testnet|mainnet)"
16+
required: true
17+
default: "testnet"
18+
type: choice
19+
options:
20+
- testnet
21+
- mainnet
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ inputs.network || github.ref }}
25+
cancel-in-progress: true
26+
27+
permissions:
28+
contents: write
29+
30+
jobs:
31+
deploy:
32+
name: Build & Deploy stream_contract
33+
runs-on: ubuntu-latest
34+
environment: ${{ github.event_name == 'release' && 'production' || 'staging' }}
35+
36+
env:
37+
NETWORK: ${{ inputs.network || (github.event_name == 'release' && 'mainnet' || 'testnet') }}
38+
DEPLOYER_SECRET: ${{ secrets.DEPLOYER_SECRET }}
39+
ADMIN_ADDRESS: ${{ secrets.ADMIN_ADDRESS }}
40+
TREASURY_ADDRESS: ${{ secrets.TREASURY_ADDRESS }}
41+
FEE_RATE_BPS: ${{ secrets.FEE_RATE_BPS }}
42+
43+
steps:
44+
- name: Checkout code
45+
uses: actions/checkout@v4
46+
47+
- name: Setup Rust toolchain
48+
uses: dtolnay/rust-toolchain@stable
49+
with:
50+
toolchain: stable
51+
targets: wasm32-unknown-unknown
52+
components: rustfmt, clippy
53+
54+
- name: Rust Cache
55+
uses: Swatinem/rust-cache@v2
56+
with:
57+
workspace: "contracts -> target"
58+
59+
- name: Install Stellar CLI
60+
run: |
61+
curl -fsSL https://github.com/stellar/stellar-cli/raw/main/install.sh | sh -s -- --install-deps
62+
echo "$HOME/.stellar-cli/bin" >> $GITHUB_PATH
63+
64+
- name: Run Contract Tests
65+
run: cargo test --package stream_contract
66+
working-directory: contracts
67+
68+
- name: Build & Optimize WASM
69+
run: |
70+
set -euo pipefail
71+
cd contracts
72+
cargo build --target wasm32-unknown-unknown --release
73+
RELEASE_DIR="target/wasm32-unknown-unknown/release"
74+
for w in "$RELEASE_DIR"/stream_contract.wasm; do
75+
stellar contract optimize --wasm "$w" --wasm-out "$RELEASE_DIR/stream_contract.optimized.wasm"
76+
done
77+
ls -la "$RELEASE_DIR"/*.wasm
78+
79+
- name: Inspect Contract Interface & WASM Size
80+
run: |
81+
set -euo pipefail
82+
WASM=contracts/target/wasm32-unknown-unknown/release/stream_contract.optimized.wasm
83+
stellar contract inspect --wasm "$WASM"
84+
SIZE=$(stat -c%s "$WASM")
85+
echo "Optimized WASM size: $SIZE bytes"
86+
if [ "$SIZE" -ge 65536 ]; then
87+
echo "ERROR: optimized WASM exceeds 64KB budget ($SIZE bytes)"
88+
exit 1
89+
fi
90+
echo "WASM_WASM_PATH=$WASM" >> $GITHUB_ENV
91+
92+
- name: Deploy & Initialize Contract
93+
run: ./scripts/deploy.sh --network "$NETWORK"
94+
95+
- name: Read Deployed Contract ID
96+
id: contract
97+
run: |
98+
set -euo pipefail
99+
CONTRACT_ID=$(jq -r --arg net "$NETWORK" '.[$net].contractId' deployment-info.json)
100+
echo "contract_id=$CONTRACT_ID" >> $GITHUB_OUTPUT
101+
echo "deployment-json=$(jq -c . deployment-info.json)" >> $GITHUB_OUTPUT
102+
103+
- name: Emit Deployment Summary
104+
if: always()
105+
run: |
106+
{
107+
echo "## Deployment Summary"
108+
echo ""
109+
echo "- **Network**: \`$NETWORK\`"
110+
echo "- **Contract ID**: \`${{ steps.contract.outputs.contract_id }}\`"
111+
echo "- **WASM**: \`${{ env.WASM_WASM_PATH }}\`"
112+
echo "- **Deployment info**: "
113+
echo '```json'
114+
echo "${{ steps.contract.outputs.deployment-json }}"
115+
echo '```'
116+
} >> "$GITHUB_STEP_SUMMARY"
117+
118+
- name: Upload Optimized WASM Artifact
119+
uses: actions/upload-artifact@v4
120+
with:
121+
name: stream-contract-${{ env.NETWORK }}
122+
path: contracts/target/wasm32-unknown-unknown/optimized/*.wasm
123+
if-no-files-found: error
124+
125+
- name: Upload Deployment Info
126+
uses: actions/upload-artifact@v4
127+
with:
128+
name: deployment-info-${{ env.NETWORK }}
129+
path: deployment-info.json
130+
if-no-files-found: error
131+
132+
- name: Commit Deployment Info
133+
if: github.event_name == 'release'
134+
env:
135+
NETWORK: ${{ env.NETWORK }}
136+
run: |
137+
set -euo pipefail
138+
git config user.name "github-actions[bot]"
139+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
140+
git add deployment-info.json
141+
if git diff --cached --quiet; then
142+
echo "No deployment-info.json changes to commit"
143+
exit 0
144+
fi
145+
git commit -m "chore(contracts): record $NETWORK contract deployment"
146+
git push

backend/.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ REDIS_URL=
8888
# Time in milliseconds between periodic sweeps to prune expired memory cache entries (default: 60000)
8989
MEMORY_CACHE_SWEEP_MS=60000
9090

91+
# Maximum number of entries kept in the in-memory cache. When exceeded, the
92+
# least-recently-used entries are evicted immediately so memory stays bounded
93+
# even between sweeps (default: 10000)
94+
MEMORY_CACHE_MAX_ITEMS=10000
95+
9196
# Cache time-to-live (TTL) for claimable amount calculations in milliseconds (default: 5000)
9297
CLAIMABLE_CACHE_TTL_MS=5000
9398

backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"prisma:migrate": "prisma migrate dev",
2020
"prisma:deploy": "prisma migrate deploy",
2121
"prisma:seed": "prisma db seed",
22-
"prisma:studio": "prisma studio"
22+
"prisma:studio": "prisma studio",
23+
"codegen:openapi": "tsx scripts/export-openapi.mts"
2324
},
2425
"prisma": {
2526
"seed": "tsx prisma/seed.ts"

backend/scripts/export-openapi.mts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Export the OpenAPI spec to a committed JSON file so it can be consumed
3+
* without booting the API server (e.g. by `openapi-typescript` codegen and the
4+
* CI drift check).
5+
*
6+
* npm run codegen:openapi
7+
*/
8+
import { mkdirSync, writeFileSync } from 'node:fs';
9+
import { dirname, join } from 'node:path';
10+
import { fileURLToPath } from 'node:url';
11+
import { swaggerSpec } from '../src/config/swagger.js';
12+
13+
const here = dirname(fileURLToPath(import.meta.url));
14+
const outDir = join(here, '..', 'swagger');
15+
const outFile = join(outDir, 'flowfi.openapi.json');
16+
17+
mkdirSync(outDir, { recursive: true });
18+
writeFileSync(outFile, `${JSON.stringify(swaggerSpec, null, 2)}\n`);
19+
console.log(`OpenAPI spec written to ${outFile}`);

0 commit comments

Comments
 (0)