-
Notifications
You must be signed in to change notification settings - Fork 346
Port Binding Generation #1287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Port Binding Generation #1287
Changes from 39 commits
0ac31c1
a802b40
b348428
ee062fe
c03ae81
2fcf367
e5ca345
d4c571e
b320cde
7a0b1f5
f065fe7
095f164
33e8b6c
dcd94cf
d38ddeb
98b0ba0
c4b6ad3
f0497dd
08974d5
cb59a14
3a8bad2
5e5b562
6709e01
d8dcfab
0f4bbd3
8fcf247
174278c
4e158ea
0ccb076
c777522
6f6cb68
f11ea04
0437123
ff2bc97
05c25bf
8a873ff
d2741ad
695eb39
ecd3f41
8eb6376
8a09e56
b57ca2d
e6e1744
a3bab12
fc776f0
3bfb72e
058a140
58409a1
0fe49c5
e99d97d
21d140f
916abe3
07c3842
55be278
9eb10e5
d1e7b8d
cc697d8
1ff86bf
6784ed0
caf34bd
0ddb24f
30e6181
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
|
@@ -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] | ||
| ``` | ||
|
|
||
| ### 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) | | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #!/usr/bin/env node | ||
|
Ryang-21 marked this conversation as resolved.
|
||
|
|
||
| // Entry point for the stellar CLI | ||
| require("../lib/cli/index.js").runCli(); | ||
| 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"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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", | ||
|
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); | ||
| }); | ||
There was a problem hiding this comment.
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.