Skip to content
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
100 changes: 100 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!--
Delete any section that does not apply. A short, accurate PR is better than a
long one padded with boilerplate.
-->

## Summary

<!-- What changed and why, in two or three sentences. -->

Closes #

## Type of change

- [ ] Contract change (Rust / Soroban)
- [ ] SDK change (`packages/swaptrade-sdk`)
- [ ] Example DApp change (`examples/swap-demo`)
- [ ] CI / tooling
- [ ] Documentation

## What changed

<!--
List the files that matter and why. Skip mechanical churn.

- `packages/swaptrade-sdk/src/client.ts` — added `cancelOrder`
- `packages/swaptrade-sdk/test/client.test.ts` — argument-mapping test
-->

## Contract compatibility

<!-- For SDK changes. Delete if not applicable. -->

- [ ] Every method added or changed matches a real entry point in `swaptrade-contracts/`
- [ ] Argument order matches the Rust signature (positional on the wire)
- [ ] `i128` / `u128` / `u64` values are `bigint`, not `number`
- [ ] `Option::None` decodes to `undefined`, not `0`
- [ ] No contract behaviour was changed to make the SDK or demo simpler

Contract entry point(s) this relies on:

<!-- e.g. `counter/src/lib.rs::cancel_order` (line 1795) -->

## Validation

Paste **real output**. If something failed, say so and classify it as caused by
this change, pre-existing, or environmental.

```
$ npm run typecheck

$ npm run test

$ npm run build --workspace @swaptrade/sdk

$ npm run test:e2e --workspace @swaptrade/swap-demo
```

### Localnet

<!--
If you touched signing, submission or encoding, run the live check in
docs/LOCALNET.md — a fake RPC server cannot catch a malformed footprint or a
wrong passphrase. Paste the contract ID and transaction hash.
-->

- [ ] Verified against localnet (`scripts/verify_localnet.ts`)
- [ ] Not applicable

### Not verified

<!--
State the gaps explicitly. An honest gap is fine; an unverified claim is not.
"The counter contract does not compile on a clean checkout, so X could not be
exercised on-chain" is a good entry.
-->

## Tests

- [ ] Added or updated tests for this change
- [ ] No unit test makes a real network call
- [ ] Component tests assert on rendered output, not component internals
- [ ] No Cypress was added (Playwright is the only browser-test tool here)

## Checklist

- [ ] No secrets: no private keys, seed phrases, RPC credentials, contract IDs or wallet data in source, tests, fixtures or docs
- [ ] No secret reaches the browser: no `VITE_*` secret variable, no key input field, no `keypairSigner` import under `examples/`
- [ ] No `.env` file is committed (`.env.example` with placeholders is fine)
- [ ] Configuration is read from the environment, not hardcoded
- [ ] No generated artifacts (`node_modules/`, `dist/`, `playwright-report/`, `target/`)
- [ ] No editor/IDE files
- [ ] No debugging statements left behind
- [ ] No unrelated reformatting or lockfile churn
- [ ] Layering respected: no chain logic inside React components
- [ ] Docs updated if behaviour or setup changed
- [ ] Reviewed my own `git diff` before requesting review

## Notes for reviewers

<!-- Anything non-obvious: a trade-off, something you were unsure about, a follow-up. -->
138 changes: 138 additions & 0 deletions .github/workflows/sdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# SDK and example DApp checks.
#
# Scoped deliberately narrowly: this workflow covers only `packages/` and
# `examples/`. The existing Rust workflows (ci.yml, format.yml,
# formal_verification.yml) are left exactly as they are — they are currently
# commented out, and re-enabling them is a separate decision from this change.
#
# Path filters keep the workflow proportionate: a contract-only commit does not
# need to boot a browser.
name: SDK

on:
push:
branches: [main]
paths:
- 'packages/**'
- 'examples/**'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/sdk.yml'
pull_request:
paths:
- 'packages/**'
- 'examples/**'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/sdk.yml'

# A new push supersedes an in-flight run for the same ref.
concurrency:
group: sdk-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
build-and-test:
name: Build, typecheck and test
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm

# `npm ci` fails on a lockfile that disagrees with package.json, which is
# the check we want: dependencies must be reproducible from the committed
# lockfile alone.
- name: Install dependencies
run: npm ci

- name: Build SDK
run: npm run build --workspace @swaptrade/sdk

- name: Typecheck SDK
run: npm run typecheck --workspace @swaptrade/sdk

- name: Test SDK
run: npm run test --workspace @swaptrade/sdk

- name: Typecheck example DApp
run: npm run typecheck --workspace @swaptrade/swap-demo

- name: Test example DApp
run: npm run test --workspace @swaptrade/swap-demo

- name: Build example DApp
run: npm run build --workspace @swaptrade/swap-demo

- name: Verify no secrets are inlined into the bundle
# Vite inlines every VITE_-prefixed variable into the browser bundle, so
# the built output is the artifact that matters here, not the source. The
# demo has no secret-key code path at all; these greps make sure one is
# not reintroduced, whether by a hardcoded literal or by a new env var.
run: |
if grep -rEoh 'S[A-Z2-7]{55}' examples/swap-demo/dist/ | head -1 | grep -q .; then
echo "::error::A Stellar secret-key-shaped string was found in the build output."
exit 1
fi
echo "No secret-key-shaped strings in the bundle."

# A secret-reading env var would show up in the bundle by name.
if grep -rEoh 'VITE_[A-Z0-9_]*(SECRET|PRIVATE|SEED|MNEMONIC|PASSWORD)[A-Z0-9_]*' \
examples/swap-demo/dist/ | head -1 | grep -q .; then
echo "::error::The bundle references a secret-shaped VITE_ variable. Browser signing must go through a wallet, not an environment variable."
exit 1
fi
echo "No secret-shaped VITE_ variables in the bundle."

# And no source file may read one, even if the value happens to be
# unset in CI (which would leave no trace in the bundle).
if grep -rEn 'VITE_[A-Z0-9_]*(SECRET|PRIVATE|SEED|MNEMONIC|PASSWORD)' \
examples/swap-demo/src/ examples/swap-demo/*.ts | grep -q .; then
echo "::error::Source reads a secret-shaped VITE_ variable. Use the SDK signer abstraction with a browser wallet instead."
exit 1
fi
echo "No source file reads a secret-shaped VITE_ variable."

smoke:
name: Browser smoke test
runs-on: ubuntu-latest
timeout-minutes: 20
needs: build-and-test

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm

- name: Install dependencies
run: npm ci

- name: Build SDK
run: npm run build --workspace @swaptrade/sdk

# Only Chromium: the demo uses no browser-specific APIs, so a matrix here
# would add minutes without adding coverage.
- name: Install Playwright Chromium
run: npx playwright install --with-deps chromium
working-directory: examples/swap-demo

- name: Run smoke test
run: npm run test:e2e --workspace @swaptrade/swap-demo

- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: examples/swap-demo/playwright-report/
retention-days: 7
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,29 @@ Thumbs.db

# Logs
*.log

# Node / TypeScript SDK & examples
node_modules/
dist/
coverage/
.env
.env.local
*.tsbuildinfo

# Playwright
test-results/
playwright-report/
blob-report/
playwright/.cache/

# The `*.json` rule above is intentionally broad (it hides generated Soroban
# artifacts), so re-include the JSON files that must be version-controlled for
# the SDK and example app to be installable after a fresh clone.
!package.json
!package-lock.json
!tsconfig*.json
!packages/**/package.json
!packages/**/tsconfig*.json
!examples/**/package.json
!examples/**/tsconfig*.json
!.github/**/*.json
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ swaptrade-contracts/
cd swaptrade-contracts
```

## TypeScript SDK and example DApp

A typed JavaScript/TypeScript client for these contracts, plus a runnable React
demo, live alongside the Rust crates:

| Path | What it is |
| --- | --- |
| [`packages/swaptrade-sdk`](packages/swaptrade-sdk/README.md) | TypeScript SDK — one method per contract entry point, typed errors, ScVal encoding |
| [`examples/swap-demo`](examples/swap-demo/README.md) | React demo walking a create → fund → accept workflow |
| [`docs/LOCALNET.md`](docs/LOCALNET.md) | Reproducible localnet walkthrough, and what was verified on-chain |
| [`docs/CONTRIBUTING_SDK.md`](docs/CONTRIBUTING_SDK.md) | Contributor guide for the SDK and examples |
| [`docs/IMPACT.md`](docs/IMPACT.md) | What this adds, in measured terms |

```bash
npm install
npm run build --workspace @swaptrade/sdk
npm run test # 121 tests, no network access
npm run demo # needs configuration — see the demo README
```

Requires Node.js 20+. Rust contract work is unaffected by these workspaces.

## Migration Process

SwapTrade contracts support versioning and data migration to ensure historical data is preserved during upgrades.
Expand Down
Loading
Loading