Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3883e4e
init
SwenSchaeferjohann Mar 25, 2026
a0a9489
cleanup
SwenSchaeferjohann Mar 26, 2026
e2204e0
refactor(token-interface): unify instruction APIs and SPL interface n…
SwenSchaeferjohann Mar 28, 2026
f2e01c2
simplify load
SwenSchaeferjohann Mar 28, 2026
b6ce011
reduce async
SwenSchaeferjohann Mar 28, 2026
149d806
rm redundant rpc
SwenSchaeferjohann Mar 28, 2026
2855847
add tests
SwenSchaeferjohann Mar 28, 2026
22cdd49
dedupe amount helper, unify ix disc
SwenSchaeferjohann Mar 28, 2026
7f8c061
upd ci
SwenSchaeferjohann Mar 28, 2026
43009a9
add perms
SwenSchaeferjohann Mar 28, 2026
0bd3fcc
more robust getsplinterface
SwenSchaeferjohann Mar 29, 2026
46ee479
rm close acc for transfer
SwenSchaeferjohann Mar 29, 2026
822c2a1
upd typed err in splinterface
SwenSchaeferjohann Mar 29, 2026
df81770
add test cov for nowrap
SwenSchaeferjohann Mar 29, 2026
1671d05
add test cov for race condition on transfer
SwenSchaeferjohann Mar 29, 2026
e0354c8
dedup rpc calls between load and transfer
SwenSchaeferjohann Mar 29, 2026
6b7f932
strict condition for spl interface fetch
SwenSchaeferjohann Mar 29, 2026
283464e
concurrently fetch getMintDecimals and getSplInterfaces
SwenSchaeferjohann Mar 29, 2026
92fd88b
build -> transfer
SwenSchaeferjohann Mar 29, 2026
6a3bc05
payer optional for all ixns + test cov
SwenSchaeferjohann Mar 29, 2026
c16c59b
stricter typing
SwenSchaeferjohann Mar 29, 2026
5741b28
refactor load
SwenSchaeferjohann Mar 29, 2026
963ac04
format
SwenSchaeferjohann Mar 29, 2026
ff7552d
refactor(token-interface): migrate tests from vitest to cucumber-js
ananas-block Mar 29, 2026
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
102 changes: 102 additions & 0 deletions .github/workflows/js-token-interface-v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
on:
push:
branches:
- main
pull_request:
branches:
- "**"
types:
- opened
- synchronize
- reopened
- ready_for_review

name: js-token-interface-v2

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
token-interface-js-v2:
name: token-interface-js-v2
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest

services:
redis:
image: redis:8.0.1
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

env:
LIGHT_PROTOCOL_VERSION: V2
REDIS_URL: redis://localhost:6379
CI: true

steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
submodules: true

- name: Setup and build
uses: ./.github/actions/setup-and-build
with:
skip-components: "redis,disk-cleanup,go"
cache-key: "js"

- name: Build token-interface with V2
run: |
cd js/token-interface
pnpm build:v2

- name: Build CLI
run: |
just cli build

- name: Run token-interface unit tests with V2
run: |
echo "Running token-interface unit tests with retry logic (max 2 attempts)..."
attempt=1
max_attempts=2
until just js test-token-interface-unit-v2; do
attempt=$((attempt + 1))
if [ $attempt -gt $max_attempts ]; then
echo "Tests failed after $max_attempts attempts"
exit 1
fi
echo "Attempt $attempt/$max_attempts failed, retrying..."
sleep 5
done
echo "Tests passed on attempt $attempt"

- name: Run token-interface e2e tests with V2
run: |
echo "Running token-interface e2e tests with retry logic (max 2 attempts)..."
attempt=1
max_attempts=2
until just js test-token-interface-e2e-v2; do
attempt=$((attempt + 1))
if [ $attempt -gt $max_attempts ]; then
echo "Tests failed after $max_attempts attempts"
exit 1
fi
echo "Attempt $attempt/$max_attempts failed, retrying..."
sleep 5
done
echo "Tests passed on attempt $attempt"

- name: Display prover logs on failure
if: failure()
run: |
echo "=== Displaying prover logs ==="
find . -path "*/test-ledger/*prover*.log" -type f -exec echo "=== Contents of {} ===" \; -exec cat {} \; -exec echo "=== End of {} ===" \; || echo "No prover logs found"
2 changes: 1 addition & 1 deletion .github/workflows/js-v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
- main
pull_request:
branches:
- "*"
- "**"
types:
- opened
- synchronize
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ api-docs/
# Third-party dependencies
/.local
/.vscode
.cursor/

**/.idea
**/*.iml
Expand Down
14 changes: 13 additions & 1 deletion js/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,34 @@ default:
build:
cd stateless.js && pnpm build
cd compressed-token && pnpm build
cd token-interface && pnpm build

test: test-stateless test-compressed-token
test: test-stateless test-compressed-token test-token-interface

test-stateless:
cd stateless.js && pnpm test

test-compressed-token:
cd compressed-token && pnpm test

test-token-interface:
cd token-interface && pnpm test

test-token-interface-unit-v2:
cd token-interface && pnpm test:unit:all

test-token-interface-e2e-v2:
cd token-interface && pnpm test:e2e:all

test-compressed-token-unit-v2:
cd compressed-token && pnpm test:unit:all:v2

lint:
cd stateless.js && pnpm lint
cd compressed-token && pnpm lint
cd token-interface && pnpm lint

format:
cd stateless.js && pnpm format
cd compressed-token && pnpm format
cd token-interface && pnpm format
10 changes: 10 additions & 0 deletions js/token-interface/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 80,
"useTabs": false,
"tabWidth": 4,
"bracketSpacing": true,
"arrowParens": "avoid"
}
104 changes: 104 additions & 0 deletions js/token-interface/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# `@lightprotocol/token-interface`

Payments-focused helpers for Light rent-free token flows.

Use this when you want SPL-style transfers with unified sender handling:

- sender side auto wraps/loads into light ATA
- recipient ATA can be light (default), SPL, or Token-2022 via `tokenProgram`

## RPC client (required)

All builders expect `createRpc()` from `@lightprotocol/stateless.js`.

```ts
import { createRpc } from '@lightprotocol/stateless.js';

// Add this to your client. It is a superset of web3.js Connection RPC plus Light APIs.
const rpc = createRpc();
// Optional: createRpc(clusterUrl)
```

## Canonical for Kit users

Use `createTransferInstructionPlan` from `/kit`.

```ts
import { createTransferInstructionPlan } from '@lightprotocol/token-interface/kit';

const transferPlan = await createTransferInstructionPlan({
rpc,
payer: payer.publicKey,
mint,
sourceOwner: sender.publicKey,
authority: sender.publicKey,
recipient: customer.publicKey,
// Optional destination program:
// tokenProgram: TOKEN_PROGRAM_ID
amount: 25n,
});
```

If you prefer Kit instruction arrays instead of plans:

```ts
import { createTransferInstructions } from '@lightprotocol/token-interface/kit';
```

## Canonical for web3.js users

Use `createTransferInstructions` from the root export.

```ts
import { createTransferInstructions } from '@lightprotocol/token-interface';

const instructions = await createTransferInstructions({
rpc,
payer: payer.publicKey,
mint,
sourceOwner: sender.publicKey,
authority: sender.publicKey,
recipient: customer.publicKey,
amount: 25n,
});

// add memo if needed, then build/sign/send transaction
```

## Raw single-instruction helpers

Use these when you want manual orchestration:

```ts
import {
createAtaInstruction,
createLoadInstruction,
createTransferCheckedInstruction,
} from '@lightprotocol/token-interface/instructions';
```

## No-wrap instruction-flow builders (advanced)

If you explicitly want to disable automatic sender wrapping, use:

```ts
import { createTransferInstructionsNowrap } from '@lightprotocol/token-interface/instructions';
```

## Read account

```ts
import { getAta } from '@lightprotocol/token-interface';

const account = await getAta({ rpc, owner: customer.publicKey, mint });
console.log(account.amount, account.hotAmount, account.compressedAmount);
```

## Important rules

- Only one compressed sender account is loaded per call; smaller ones are ignored for that call.
- Transfer always builds checked semantics.
- Canonical builders always use wrap-enabled sender setup (`createTransferInstructions`, `createLoadInstructions`, `createApproveInstructions`, `createRevokeInstructions`).
- If sender SPL/T22 balances are wrapped by the flow, source SPL/T22 ATAs are not auto-closed.
- Recipient ATA is derived from `(recipient, mint, tokenProgram)`; default is light token program.
- Recipient-side load is still intentionally disabled.
26 changes: 26 additions & 0 deletions js/token-interface/cucumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const common = {
requireModule: ['tsx'],
require: [
'tests/support/**/*.ts',
'tests/step-definitions/**/*.steps.ts',
],
format: ['progress'],
formatOptions: { snippetInterface: 'async-await' },
};

const defaultProfile = {
...common,
paths: ['features/**/*.feature'],
};

export { defaultProfile as default };

export const unit = {
...common,
paths: ['features/unit/**/*.feature'],
};

export const e2e = {
...common,
paths: ['features/e2e/**/*.feature'],
};
Loading
Loading