Skip to content
Draft
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
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
109 changes: 109 additions & 0 deletions js/token-interface/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# `@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 { buildTransferInstructions } from '@lightprotocol/token-interface/kit';
```

## Canonical for web3.js users

Use `buildTransferInstructions` from the root export.

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

const instructions = await buildTransferInstructions({
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
```

Backwards-compatible alias:

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

## 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 { buildTransferInstructionsNowrap } 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 (`buildTransferInstructions`, `createLoadInstructions`, `createApproveInstructions`, `createRevokeInstructions`).
- If sender SPL/T22 balances were wrapped by the flow, source SPL/T22 ATAs are closed afterward.
- Recipient ATA is derived from `(recipient, mint, tokenProgram)`; default is light token program.
- Recipient-side load is still intentionally disabled.
113 changes: 113 additions & 0 deletions js/token-interface/eslint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
const js = require('@eslint/js');
const tseslint = require('@typescript-eslint/eslint-plugin');
const tsParser = require('@typescript-eslint/parser');

module.exports = [
{
ignores: [
'node_modules/**',
'dist/**',
'build/**',
'coverage/**',
'*.config.js',
'eslint.config.js',
'jest.config.js',
'rollup.config.js',
],
},
js.configs.recommended,
{
files: ['**/*.js', '**/*.cjs', '**/*.mjs'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: {
require: 'readonly',
module: 'readonly',
process: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
exports: 'readonly',
console: 'readonly',
Buffer: 'readonly',
},
},
},
{
files: [
'tests/**/*.ts',
'**/*.test.ts',
'**/*.spec.ts',
'vitest.config.ts',
],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
globals: {
process: 'readonly',
console: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
Buffer: 'readonly',
describe: 'readonly',
it: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
beforeAll: 'readonly',
afterAll: 'readonly',
jest: 'readonly',
test: 'readonly',
},
},
plugins: {
'@typescript-eslint': tseslint,
},
rules: {
...tseslint.configs.recommended.rules,
'@typescript-eslint/ban-ts-comment': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-var-requires': 0,
'@typescript-eslint/no-unused-vars': 0,
'@typescript-eslint/no-require-imports': 0,
'no-prototype-builtins': 0,
'no-undef': 0,
'no-unused-vars': 0,
},
},
{
files: ['src/**/*.ts', 'src/**/*.tsx'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: './tsconfig.json',
ecmaVersion: 2022,
sourceType: 'module',
},
globals: {
process: 'readonly',
console: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
Buffer: 'readonly',
},
},
plugins: {
'@typescript-eslint': tseslint,
},
rules: {
...tseslint.configs.recommended.rules,
'@typescript-eslint/ban-ts-comment': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-var-requires': 0,
'@typescript-eslint/no-unused-vars': 0,
'@typescript-eslint/no-require-imports': 0,
'no-prototype-builtins': 0,
'no-undef': 0,
'no-unused-vars': 0,
},
},
];
90 changes: 90 additions & 0 deletions js/token-interface/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"name": "@lightprotocol/token-interface",
"version": "0.23.0",
"description": "JS enhancement layer for SPL and Token-2022 flows using Light rent-free token accounts",
"sideEffects": false,
"main": "dist/cjs/index.cjs",
"type": "module",
"exports": {
".": {
"require": "./dist/cjs/index.cjs",
"import": "./dist/es/index.js",
"types": "./dist/types/index.d.ts"
},
"./instructions": {
"require": "./dist/cjs/instructions/index.cjs",
"import": "./dist/es/instructions/index.js",
"types": "./dist/types/instructions/index.d.ts"
},
"./kit": {
"require": "./dist/cjs/kit/index.cjs",
"import": "./dist/es/kit/index.js",
"types": "./dist/types/kit/index.d.ts"
}
},
"types": "./dist/types/index.d.ts",
"files": [
"dist"
],
"maintainers": [
{
"name": "Light Protocol Maintainers",
"email": "friends@lightprotocol.com"
}
],
"license": "Apache-2.0",
"peerDependencies": {
"@coral-xyz/borsh": "^0.29.0",
"@lightprotocol/stateless.js": "workspace:*",
"@solana/spl-token": ">=0.3.9",
"@solana/web3.js": ">=1.73.5"
},
"dependencies": {
"@solana/buffer-layout": "^4.0.1",
"@solana/buffer-layout-utils": "^0.2.0",
"@solana/compat": "^6.5.0",
"@solana/instruction-plans": "^6.5.0",
"@solana/kit": "^6.5.0",
"bn.js": "^5.2.1",
"buffer": "6.0.3"
},
"devDependencies": {
"@lightprotocol/compressed-token": "workspace:*",
"@eslint/js": "9.36.0",
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6",
"@types/bn.js": "^5.1.5",
"@types/node": "^22.5.5",
"@typescript-eslint/eslint-plugin": "^8.44.0",
"@typescript-eslint/parser": "^8.44.0",
"eslint": "^9.36.0",
"eslint-plugin-vitest": "^0.5.4",
"prettier": "^3.3.3",
"rimraf": "^6.0.1",
"rollup": "^4.21.3",
"rollup-plugin-dts": "^6.1.1",
"tslib": "^2.7.0",
"typescript": "^5.6.2",
"vitest": "^2.1.1"
},
"scripts": {
"build": "pnpm build:v2",
"build:v2": "pnpm build:deps:v2 && pnpm build:bundle",
"build:deps:v2": "pnpm --dir ../stateless.js build:v2",
"build:bundle": "rimraf dist && rollup -c",
"test": "pnpm test:unit:all && pnpm test:e2e:all",
"test:unit:all": "pnpm build:deps:v2 && LIGHT_PROTOCOL_VERSION=V2 EXCLUDE_E2E=true vitest run tests/unit --reporter=verbose",
"test:e2e:all": "pnpm build:deps:v2 && pnpm test-validator && LIGHT_PROTOCOL_VERSION=V2 vitest run tests/e2e --reporter=verbose --bail=1",
"test-validator": "./../../cli/test_bin/run test-validator",
"lint": "eslint .",
"format": "prettier --write ."
},
"keywords": [
"light",
"solana",
"token",
"interface",
"payments"
]
}
74 changes: 74 additions & 0 deletions js/token-interface/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import typescript from '@rollup/plugin-typescript';
import dts from 'rollup-plugin-dts';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

const inputs = {
index: 'src/index.ts',
'instructions/index': 'src/instructions/index.ts',
'kit/index': 'src/kit/index.ts',
};

const external = [
'@coral-xyz/borsh',
'@lightprotocol/stateless.js',
'@solana/buffer-layout',
'@solana/buffer-layout-utils',
'@solana/compat',
'@solana/instruction-plans',
'@solana/kit',
'@solana/spl-token',
'@solana/web3.js',
'bn.js',
'buffer',
];

const jsConfig = format => ({
input: inputs,
output: {
dir: `dist/${format}`,
format,
entryFileNames: `[name].${format === 'cjs' ? 'cjs' : 'js'}`,
chunkFileNames: `[name]-[hash].${format === 'cjs' ? 'cjs' : 'js'}`,
sourcemap: true,
},
external,
plugins: [
typescript({
target: format === 'es' ? 'ES2022' : 'ES2017',
outDir: `dist/${format}`,
}),
commonjs(),
resolve({
extensions: ['.mjs', '.js', '.json', '.ts'],
}),
],
onwarn(warning, warn) {
if (warning.code !== 'CIRCULAR_DEPENDENCY') {
warn(warning);
}
},
});

const dtsEntry = (input, file) => ({
input,
output: [{ file, format: 'es' }],
external,
plugins: [
dts({
respectExternal: true,
tsconfig: './tsconfig.json',
}),
],
});

export default [
jsConfig('cjs'),
jsConfig('es'),
dtsEntry('src/index.ts', 'dist/types/index.d.ts'),
dtsEntry(
'src/instructions/index.ts',
'dist/types/instructions/index.d.ts',
),
dtsEntry('src/kit/index.ts', 'dist/types/kit/index.d.ts'),
];
Loading
Loading