Skip to content
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
0ac31c1
add contract bindings generation
Ryang-21 Nov 20, 2025
a802b40
add cli for binding generation
Ryang-21 Nov 20, 2025
b348428
change cli name to avoid naming conflict with stellar-cli
Ryang-21 Nov 21, 2025
ee062fe
fix scSymbol type conversion to string
Ryang-21 Nov 21, 2025
c03ae81
extract duplicated typedef parsing and create util for generating imp…
Ryang-21 Nov 24, 2025
2fcf367
include null in Option union type and Address for scVal Address
Ryang-21 Nov 24, 2025
e5ca345
fix parsing of ts type for scVoid
Ryang-21 Nov 24, 2025
d4c571e
simplify type generation
Ryang-21 Nov 24, 2025
b320cde
set option field for contract methods to be type MethodOptions
Ryang-21 Nov 24, 2025
7a0b1f5
sanitize names of functions,interfaces, and enums for js reserved key…
Ryang-21 Nov 24, 2025
f065fe7
add js docs to contract method interface
Ryang-21 Nov 25, 2025
095f164
replace sh -> js script for fetching sac spec
Ryang-21 Nov 25, 2025
33e8b6c
cleanup redundant code
Ryang-21 Nov 25, 2025
dcd94cf
Merge branch 'master' into binding-gen
Ryang-21 Nov 25, 2025
d38ddeb
fix wasm parser import
Ryang-21 Nov 25, 2025
98b0ba0
use --network option for setting passphrase in cli
Ryang-21 Nov 25, 2025
c4b6ad3
fix linter errors
Ryang-21 Nov 25, 2025
f0497dd
parse scVoid typedef as null
Ryang-21 Nov 25, 2025
08974d5
handle nested option types when parsing typedef
Ryang-21 Nov 26, 2025
cb59a14
fix export of types in index file
Ryang-21 Dec 5, 2025
3a8bad2
dedeplicate import formatting from client and type generator
Ryang-21 Dec 5, 2025
5e5b562
refactor import generation
Ryang-21 Dec 5, 2025
6709e01
fortify cleaning of jsdoc
Ryang-21 Dec 5, 2025
d8dcfab
fix formatting
Ryang-21 Jan 8, 2026
0f4bbd3
sanitize method names for dynamic method generation and sanitize meth…
Ryang-21 Jan 8, 2026
8fcf247
change method name from sanitizeName -> sanitizeIdentifier
Ryang-21 Jan 8, 2026
174278c
restrict binding exports to strictly BindingGenerator
Ryang-21 Jan 8, 2026
4e158ea
add testing for binding generation and cli functionalites
Ryang-21 Jan 8, 2026
0ccb076
fix changed method name
Ryang-21 Jan 8, 2026
c777522
improve jsdocs for BindingGeneration class
Ryang-21 Jan 8, 2026
6f6cb68
add cli documentation
Ryang-21 Jan 8, 2026
f11ea04
Merge branch 'master' into binding-gen
Ryang-21 Jan 8, 2026
0437123
allow RpcServer options to be passed into cli
Ryang-21 Jan 9, 2026
ff2bc97
sort functions and types by name for deterministic generation
Ryang-21 Jan 9, 2026
05c25bf
Revert "sort functions and types by name for deterministic generation"
Ryang-21 Jan 9, 2026
8a873ff
update stellar-cli for e2e CI testing
Ryang-21 Jan 9, 2026
d2741ad
replace snapshot testing for a e2e generation -> compile -> execution…
Ryang-21 Jan 9, 2026
695eb39
rename binding e2e test file name
Ryang-21 Jan 9, 2026
ecd3f41
update docs for CLI's optional args
Ryang-21 Jan 9, 2026
8eb6376
include all options in --network description
Ryang-21 Jan 12, 2026
8a09e56
log message from error cause
Ryang-21 Jan 12, 2026
b57ca2d
provide default rpc-urls for tesntet, futurenet, and localnet
Ryang-21 Jan 12, 2026
e6e1744
update test-contracts submodule hash
Ryang-21 Jan 13, 2026
a3bab12
add snapshot tests for generated bindings
Ryang-21 Jan 13, 2026
fc776f0
update quickstart container hash
Ryang-21 Jan 13, 2026
3bfb72e
run snapshot binding test on fixed wasm
Ryang-21 Jan 13, 2026
058a140
sanitize jsdoc escapes with a space
Ryang-21 Jan 13, 2026
58409a1
change Val type parsing from xdr.ScVal to any for drop in replacement
Ryang-21 Jan 13, 2026
0fe49c5
add values: void field to nonvalue unions for cli generation parity
Ryang-21 Jan 13, 2026
e99d97d
implement specific generation for tuple structs for cli generation pa…
Ryang-21 Jan 13, 2026
21d140f
port all cli binding gen method tests
Ryang-21 Jan 14, 2026
916abe3
update changelog
Ryang-21 Jan 14, 2026
07c3842
remove log
Ryang-21 Jan 14, 2026
55be278
cleanup interface instantiation
Ryang-21 Jan 14, 2026
9eb10e5
update submodule to 17190efb9833cb7e4a92059202dfdac41662d6e1
Ryang-21 Jan 15, 2026
d1e7b8d
Fix rpc name from Soroban -> Stellar
Ryang-21 Jan 16, 2026
cc697d8
set SAC spec download to a pinned hash
Ryang-21 Jan 20, 2026
1ff86bf
refactor: simplify WASM fetching logic and config generation
Ryang-21 Jan 20, 2026
6784ed0
refactor binding generator to take rpc server instance
Ryang-21 Jan 20, 2026
caf34bd
refactor: have cli utilize BindingGenerator for wasm fetching
Ryang-21 Jan 20, 2026
0ddb24f
fix jsdoc returns statement
Ryang-21 Jan 20, 2026
30e6181
Merge branch 'master' into binding-gen
Ryang-21 Jan 21, 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
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE }}
- uses: stellar/stellar-cli@v23.1.4
- uses: stellar/stellar-cli@v23.4.0

# Install system dependencies required for Stellar CLI
- name: Install system dependencies
Expand Down
127 changes: 127 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The library provides:
- [...with React Native](#usage-with-react-native)
- [...with Expo](#usage-with-expo-managed-workflows)
- [...with CloudFlare Workers](#usage-with-cloudflare-workers)
* [CLI](#cli): generate TypeScript bindings for Stellar smart contracts
* [Developing](#developing): contribute to the project!
* [Understanding `stellar-sdk` vs. `stellar-base`](#stellar-sdk-vs-stellar-base)
* [License](#license)
Expand Down Expand Up @@ -200,6 +201,132 @@ Horizon.AxiosClient.defaults.adapter = fetchAdapter as any;

All HTTP calls will use `fetch`, now, meaning it should work in the CloudFlare Worker environment.

## CLI

The SDK includes a command-line tool for generating TypeScript bindings from Stellar smart contracts. These bindings provide fully-typed client code with IDE autocompletion and compile-time type checking.

### Running the CLI

```shell
# Using npx (no installation required)
npx @stellar/stellar-sdk generate [options]

# Or if installed globally
stellar-js generate [options]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call to make this a generic subcommand of the CLI. Gives us space to add other things in the future.

```

### Generating Bindings

You can generate bindings from three different sources:

#### From a local WASM file

```shell
npx @stellar/stellar-sdk generate \
--wasm ./path/to/wasm_file/my_contract.wasm \
--output-dir ./my-contract-client \
--contract-name my-contract
```

#### From a WASM hash on the network

```shell
npx @stellar/stellar-sdk generate \
--wasm-hash <hex-encoded-hash> \
--rpc-url https://soroban-testnet.stellar.org \
--network testnet \
--output-dir ./my-contract-client \
--contract-name my-contract
```

#### From a deployed contract ID

```shell
npx @stellar/stellar-sdk generate \
--contract-id CABC...XYZ \
--rpc-url https://soroban-testnet.stellar.org \
--network testnet \
--output-dir ./my-contract-client
```

#### With custom RPC server options

For local development or when connecting to RPC servers that require authentication:

```shell
# Allow HTTP connections (useful for local development)
npx @stellar/stellar-sdk generate \
--contract-id CABC...XYZ \
--rpc-url http://localhost:8000/soroban/rpc \
--network localnet \
--output-dir ./my-contract-client \
--allow-http

# With custom timeout and headers
npx @stellar/stellar-sdk generate \
--contract-id CABC...XYZ \
--rpc-url https://my-rpc-server.com \
--network mainnet \
--output-dir ./my-contract-client \
--timeout 30000 \
--headers '{"Authorization": "Bearer my-token"}'
```

### CLI Options

| Option | Description |
|--------|-------------|
| `--wasm <path>` | Path to a local WASM file |
| `--wasm-hash <hash>` | Hex-encoded hash of WASM blob on the network |
| `--contract-id <id>` | Contract ID of a deployed contract |
| `--rpc-url <url>` | Soroban RPC server URL (required for network sources) |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a default RPC URL for things like testnet, futurenet, and localnet? I didn't see default values in the code. If not, it'd be good to add that for consistency with the Stellar CLI.

| `--network <network>` | Network to use: `testnet`, `mainnet`, `futurenet`, or `localnet` (required for network sources) |
| `--output-dir <dir>` | Output directory for generated bindings (required) |
| `--contract-name <name>` | Name for the generated package (derived from filename if not provided) |
| `--overwrite` | Overwrite existing files in the output directory |
| `--allow-http` | Allow insecure HTTP connections to RPC server (default: false) |
| `--timeout <ms>` | RPC request timeout in milliseconds |
| `--headers <json>` | Custom headers as JSON object (e.g., `'{"Authorization": "Bearer token"}'`) |

### Generated Output

The CLI generates a complete npm package structure:

```
my-contract-client/
├── src/
│ ├── index.ts # Barrel exports
│ ├── client.ts # Typed Client class with contract methods
│ └── types.ts # TypeScript interfaces for contract types
├── package.json
├── tsconfig.json
├── README.md
└── .gitignore
```

### Using Generated Bindings

After generating, you can use the bindings in your project:

```typescript
import { Client } from './my-contract-client';

const client = new Client({
contractId: 'CABC...XYZ',
networkPassphrase: Networks.TESTNET,
rpcUrl: 'https://soroban-testnet.stellar.org',
publicKey: keypair.publicKey(),
...basicNodeSigner(keypair, Networks.TESTNET),
});

// Fully typed method calls with IDE autocompletion
const result = await client.transfer({
from: 'GABC...',
to: 'GDEF...',
amount: 1000n,
});
```

## Developing

So you want to contribute to the library: welcome! Whether you're working on a fork or want to make an upstream request, the dev-test loop is pretty straightforward.
Expand Down
4 changes: 4 additions & 0 deletions bin/stellar-js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env node
Comment thread
Ryang-21 marked this conversation as resolved.

// Entry point for the stellar CLI
require("../lib/cli/index.js").runCli();
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@
"files": [
"/types",
"/lib",
"/dist"
"/dist",
"/bin"
],
"bin": {
"stellar-js": "./bin/stellar-js"
},
"exports": {
".": {
"browser": "./dist/stellar-sdk.min.js",
Expand Down Expand Up @@ -107,6 +111,7 @@
"fmt": "yarn _prettier && yarn eslint src/ --fix",
"preversion": "yarn clean && yarn _prettier && yarn build:prod && yarn test",
"prepare": "yarn build:prod && yarn setup",
"download-sac-spec": "node scripts/download-sac-spec.js",
"_build": "yarn build:node:all && yarn build:browser:all",
"_babel": "babel --extensions '.ts' --out-dir ${OUTPUT_DIR:-lib} src/",
"_nyc": "node node_modules/.bin/nyc --nycrc-path config/.nycrc",
Expand Down Expand Up @@ -196,6 +201,7 @@
"@stellar/stellar-base": "^14.0.4",
"axios": "^1.13.2",
"bignumber.js": "^9.3.1",
"commander": "^14.0.2",
"eventsource": "^2.0.2",
"feaxios": "^0.0.23",
"randombytes": "^2.1.0",
Expand Down
82 changes: 82 additions & 0 deletions scripts/download-sac-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env node

import https from "https";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

// Get __dirname equivalent in ESM
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Get repo root
const REPO_ROOT = path.join(__dirname, "..");

// URLs and paths
const REPO_URL =
"https://raw.githubusercontent.com/stellar/stellar-asset-contract-spec/main/stellar-asset-spec.xdr";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a specific commit SHA?

const TS_FILE = path.join(REPO_ROOT, "src/bindings/sac-spec.ts");

console.log("Downloading Stellar Asset Contract spec from GitHub...");

// Download file
https
.get(REPO_URL, (response) => {
if (response.statusCode !== 200) {
console.error(`✗ Failed to download: HTTP ${response.statusCode}`);
process.exit(1);
}

const chunks = [];

response.on("data", (chunk) => {
chunks.push(chunk);
});

response.on("end", () => {
const buffer = Buffer.concat(chunks);

// Verify file has content
if (buffer.length === 0) {
console.error("✗ Downloaded file is empty");
process.exit(1);
}

console.log("✓ Successfully downloaded file");
console.log(` Size: ${buffer.length} bytes`);

// Convert to base64
console.log("Converting to base64...");
const base64Content = buffer.toString("base64");

if (!base64Content) {
console.error("✗ Base64 conversion failed");
process.exit(1);
}

// Update TypeScript file
console.log(`Updating ${path.relative(REPO_ROOT, TS_FILE)}...`);
const tsContent = [
"// Auto-generated by scripts/download-sac-spec.sh",
Comment thread
Ryang-21 marked this conversation as resolved.
Outdated
"// Do not edit manually - run the script to update",
`export const SAC_SPEC = "${base64Content}";`,
"", // trailing newline
].join("\n");

try {
fs.writeFileSync(TS_FILE, tsContent, "utf8");
console.log(
`✓ Successfully updated ${path.relative(REPO_ROOT, TS_FILE)}`,
);
} catch (error) {
console.error(`✗ Failed to write file: ${error.message}`);
process.exit(1);
}

console.log("✓ Done");
});
})
.on("error", (error) => {
console.error(`✗ Error: ${error.message}`);
process.exit(1);
});
Loading
Loading