feat: deploy from wasm - #23
Conversation
Replaces the stub button from #23 with a working "Deploy a contract using this Wasm" flow on the wasm overview page: - Connects a wallet via @creit.tech/stellar-wallets-kit (Freighter, xBull, Albedo, Lobstr, Hana, Ledger, WalletConnect, etc.) - Fetches the wasm's constructor spec from the indexer's existing GET /wasms/{wasm_hash}/deploy-spec endpoint - Renders a typed form for primitive constructor args (address, string, symbol, integers, bool, bytes); wasms with unsupported arg types (vec, map, option, tuple, udt — the endpoint can't describe their shape) show a clear "not supported yet" message instead of a broken form - Builds, simulates, signs, and submits a `deploy_unnamed` invocation against the Registry contract via @stellar/stellar-sdk, then polls for the result and shows the new contract's address Also adds: - REGISTRY_RPC_URL env var (wrangler.jsonc/.dev.vars.example/workers/app.ts), network-dependent like REGISTRY_API_URL — testnet defaults to the public SDF RPC; the mainnet value is a placeholder that needs a real provider URL before this works in the mainnet environment - app/lib/network.ts: network passphrase + Registry contract ID constants (stable, deterministically-deployed addresses per network) - app/components/dialog.tsx: generic Radix-based modal primitive - vite-plugin-node-polyfills for the Buffer global stellar-sdk needs client-side Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
From Q2 deliverable 5: > A "deploy this Wasm" button that initiates a Registry deploy from the UI This should call `deploy_unnamed` on the Registry contract. It first needs to figure out what constructor args to use with the contract, and provide a form for filling these in.
Replaces the stub button from #23 with a working "Deploy a contract using this Wasm" flow on the wasm overview page: - Connects a wallet via @creit.tech/stellar-wallets-kit (Freighter, xBull, Albedo, Lobstr, Hana, Ledger, WalletConnect, etc.) - Fetches the wasm's constructor spec from the indexer's existing GET /wasms/{wasm_hash}/deploy-spec endpoint - Renders a typed form for primitive constructor args (address, string, symbol, integers, bool, bytes); wasms with unsupported arg types (vec, map, option, tuple, udt — the endpoint can't describe their shape) show a clear "not supported yet" message instead of a broken form - Builds, simulates, signs, and submits a `deploy_unnamed` invocation against the Registry contract via @stellar/stellar-sdk, then polls for the result and shows the new contract's address Also adds: - REGISTRY_RPC_URL env var (wrangler.jsonc/.dev.vars.example/workers/app.ts), network-dependent like REGISTRY_API_URL — testnet defaults to the public SDF RPC; the mainnet value is a placeholder that needs a real provider URL before this works in the mainnet environment - app/lib/network.ts: network passphrase + Registry contract ID constants (stable, deterministically-deployed addresses per network) - app/components/dialog.tsx: generic Radix-based modal primitive - vite-plugin-node-polyfills for the Buffer global stellar-sdk needs client-side Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
e06efca to
051d9bf
Compare
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Replaces the stub button from #23 with a working "Deploy a contract using this Wasm" flow on the wasm overview page: - Connects a wallet via @creit.tech/stellar-wallets-kit (Freighter, xBull, Albedo, Lobstr, Hana, Ledger, WalletConnect, etc.) - Fetches the wasm's constructor spec from the indexer's existing GET /wasms/{wasm_hash}/deploy-spec endpoint - Renders a typed form for primitive constructor args (address, string, symbol, integers, bool, bytes); wasms with unsupported arg types (vec, map, option, tuple, udt — the endpoint can't describe their shape) show a clear "not supported yet" message instead of a broken form - Builds, simulates, signs, and submits a `deploy_unnamed` invocation against the Registry contract via @stellar/stellar-sdk, then polls for the result and shows the new contract's address Also adds: - REGISTRY_RPC_URL env var (wrangler.jsonc/.dev.vars.example/workers/app.ts), network-dependent like REGISTRY_API_URL — testnet defaults to the public SDF RPC; the mainnet value is a placeholder that needs a real provider URL before this works in the mainnet environment - app/lib/network.ts: network passphrase + Registry contract ID constants (stable, deterministically-deployed addresses per network) - app/components/dialog.tsx: generic Radix-based modal primitive - vite-plugin-node-polyfills for the Buffer global stellar-sdk needs client-side - an npm "overrides" pin forcing protobufjs to 7.5.5 everywhere in the tree: @creit.tech/stellar-wallets-kit's Trezor hardware-wallet support (@trezor/connect-plugin-stellar -> ... -> @trezor/protobuf) transitively pulled in protobufjs@7.4.0, hit by a critical arbitrary-code-execution CVE (GHSA-xq3m-2v4x-88gg, patched in 7.5.5) that Socket's PR check correctly blocked on. Filed the real fix upstream at trezor/trezor-suite#31421 (their already-published @trezor/protobuf@1.5.3 has the same bump but it never landed on the connect-v9 branch/line this depends on); this override keeps us unblocked in the meantime and can be dropped once that's merged and republished. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
051d9bf to
a324284
Compare
Replaces the stub button from #23 with a working "Deploy a contract using this Wasm" flow on the wasm overview page: - Connects a wallet via @creit.tech/stellar-wallets-kit (Freighter, xBull, Albedo, Lobstr, Hana, Ledger, WalletConnect, etc.) - Fetches the wasm's constructor spec from the indexer's existing GET /wasms/{wasm_hash}/deploy-spec endpoint - Renders a typed form for primitive constructor args (address, string, symbol, integers, bool, bytes); wasms with unsupported arg types (vec, map, option, tuple, udt — the endpoint can't describe their shape) show a clear "not supported yet" message instead of a broken form - Builds, simulates, signs, and submits a `deploy_unnamed` invocation against the Registry contract via @stellar/stellar-sdk, then polls for the result and shows the new contract's address Also adds: - REGISTRY_RPC_URL env var (wrangler.jsonc/.dev.vars.example/workers/app.ts), network-dependent like REGISTRY_API_URL — testnet defaults to the public SDF RPC; the mainnet value is a placeholder that needs a real provider URL before this works in the mainnet environment - app/lib/network.ts: network passphrase + Registry contract ID constants (stable, deterministically-deployed addresses per network) - app/components/dialog.tsx: generic Radix-based modal primitive - vite-plugin-node-polyfills for the Buffer global stellar-sdk needs client-side - an npm "overrides" pin forcing protobufjs to 7.5.5 everywhere in the tree: @creit.tech/stellar-wallets-kit's Trezor hardware-wallet support (@trezor/connect-plugin-stellar -> ... -> @trezor/protobuf) transitively pulled in protobufjs@7.4.0, hit by a critical arbitrary-code-execution CVE (GHSA-xq3m-2v4x-88gg, patched in 7.5.5) that Socket's PR check correctly blocked on. Filed the real fix upstream at trezor/trezor-suite#31421 (their already-published @trezor/protobuf@1.5.3 has the same bump but it never landed on the connect-v9 branch/line this depends on); this override keeps us unblocked in the meantime and can be dropped once that's merged and republished. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
a324284 to
1ca395c
Compare
Replaces the stub button from #23 with a working "Deploy a contract using this Wasm" flow on the wasm overview page: - Connects a wallet via @creit.tech/stellar-wallets-kit (Freighter, xBull, Albedo, Lobstr, Hana, Ledger, WalletConnect, etc.) - Fetches the wasm's constructor spec from the indexer's existing GET /wasms/{wasm_hash}/deploy-spec endpoint - Renders a typed form for primitive constructor args (address, string, symbol, integers, bool, bytes); wasms with unsupported arg types (vec, map, option, tuple, udt — the endpoint can't describe their shape) show a clear "not supported yet" message instead of a broken form - Builds, simulates, signs, and submits a `deploy_unnamed` invocation against the Registry contract via @stellar/stellar-sdk, then polls for the result and shows the new contract's address Also adds: - REGISTRY_RPC_URL env var (wrangler.jsonc/.dev.vars.example/workers/app.ts), network-dependent like REGISTRY_API_URL — testnet defaults to the public SDF RPC; the mainnet value is a placeholder that needs a real provider URL before this works in the mainnet environment - app/lib/network.ts: network passphrase + Registry contract ID constants (stable, deterministically-deployed addresses per network) - app/components/dialog.tsx: generic Radix-based modal primitive - vite-plugin-node-polyfills for the Buffer global stellar-sdk needs client-side - an npm "overrides" pin forcing protobufjs to 7.5.5 everywhere in the tree: @creit.tech/stellar-wallets-kit's Trezor hardware-wallet support (@trezor/connect-plugin-stellar -> ... -> @trezor/protobuf) transitively pulled in protobufjs@7.4.0, hit by a critical arbitrary-code-execution CVE (GHSA-xq3m-2v4x-88gg, patched in 7.5.5) that Socket's PR check correctly blocked on. Filed the real fix upstream at trezor/trezor-suite#31421 (their already-published @trezor/protobuf@1.5.3 has the same bump but it never landed on the connect-v9 branch/line this depends on); this override keeps us unblocked in the meantime and can be dropped once that's merged and republished. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1ca395c to
0112ea5
Compare
restoreAddress() ran on every deploy dialog open (useEffect keyed on `open` in wasmOverview.tsx), and kit.getAddress() fans out to every configured wallet-connector module. At least one connector's SDK attaches a `close` listener per probe without cleanup, so repeatedly opening the dialog accumulated listeners past the default cap: MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added. Cache the restore probe per kit lifetime (reset alongside the existing initializedFor guard on network change) so it runs once per session instead of once per dialog open.
Addresses review feedback on #23 (deploy.ts:120): build the deploy_unnamed call through a generated Registry contract client instead of hand-built TransactionBuilder/Operation/polling code. - Add clients/registry-client, generated TypeScript bindings for the Registry contract (via `stellar registry download` + `stellar contract bindings typescript`), wired in as an npm workspace (clients/*) rather than hand-copied. `npm run generate:registry-client` regenerates it. - Rewrite deployFromWasm to build/sign/send through registry-client's Client + AssembledTransaction. deployFromWasm's external signature is unchanged, so wasmOverview.tsx and wallet.ts need no changes. - Errors now surface from the contract's own Result<Address, Error> via .unwrap() instead of generic status-polling messages. - Ignore clients/ in eslint (generated code). - Document the registry-client generation flow in the README.
… wallets, that the app will update to the new address that is connected
| "format": "prettier . --write", | ||
| "prepare": "husky" | ||
| "prepare": "husky", | ||
| "generate:registry-client": "stellar registry download registry -o /tmp/registry.wasm --network testnet -s me && stellar contract bindings typescript --wasm /tmp/registry.wasm --output-dir clients/registry-client --overwrite" |
There was a problem hiding this comment.
I would rather we do this with stellar-scaffold machinery. An environments.toml with a [staging] section that points at testnet and, once it's there, refers to registry by name (might need to use the id for now), and a [production] section that points at mainnet and again uses it by name/id.
Dog food as much as possible.
| const init = constructorArgs | ||
| ? constructorArgs.map((arg) => { | ||
| const value = parseArgValue(arg.type, arg.rawValue) | ||
| // "bool" isn't a valid nativeToScVal type hint — a JS boolean | ||
| // converts to scvBool unambiguously without one. | ||
| return arg.type === "bool" | ||
| ? nativeToScVal(value) | ||
| : nativeToScVal(value, { type: arg.type }) | ||
| }) | ||
| : undefined |
There was a problem hiding this comment.
Did you try passing just constructorArgs to init? I would hope that the contract.Client / AssembledTransaction logic already prepares the argument correctly, though this is a bit of a special case.
| const registry = new RegistryClient({ | ||
| contractId: registryContractId, | ||
| networkPassphrase, | ||
| rpcUrl, | ||
| allowHttp: true, | ||
| publicKey: deployerAddress, | ||
| // registry-client's ClientOptions expects the Freighter-shaped signer | ||
| // (xdr, opts) => Promise<{ signedTxXdr }>; wallet.ts's signTransaction is | ||
| // the simpler (xdr) => Promise<string> shape used throughout the deploy | ||
| // dialog, so adapt it here rather than changing that call site. | ||
| signTransaction: async (xdr) => ({ | ||
| signedTxXdr: await signTransaction(xdr), | ||
| }), | ||
| }) |
There was a problem hiding this comment.
This is another place where I think I would prefer we follow the Stellar Scaffold pattern, initializing this at app startup with publicKey and signTransaction both initially undefined, then setting them later when we actually call signTransaction. I suspect we may be able to simplify this logic enough that we do not need a separate lib/deploy.ts — it will be so little code that we can inline it in the component.
| let tx | ||
| try { | ||
| tx = await registry.deploy_unnamed({ | ||
| wasm_name: wasmName, | ||
| version: wasmVersion, | ||
| init, | ||
| salt: Buffer.from(salt), | ||
| deployer: deployerAddress, | ||
| }) | ||
| } catch (e) { | ||
| throw new Error( | ||
| `Failed to prepare the deploy transaction: ${e instanceof Error ? e.message : String(e)}`, | ||
| ) | ||
| } | ||
|
|
||
| let sent | ||
| try { | ||
| sent = await tx.signAndSend() | ||
| } catch (e) { | ||
| const message = e instanceof Error ? e.message : String(e) | ||
| // txBadAuth almost always means the connected wallet's account changed | ||
| // (in the extension, out of band) between building and submitting the | ||
| // transaction — surface that instead of the raw RPC failure JSON. | ||
| if (message.includes("txBadAuth")) { | ||
| throw new Error( | ||
| "The network rejected the transaction's signature (txBadAuth) — this usually means the connected wallet account changed. Disconnect and reconnect your wallet, then try deploying again.", | ||
| ) | ||
| } | ||
| throw new Error(`Failed to send the deploy transaction: ${message}`) | ||
| } |
There was a problem hiding this comment.
AssembledTransaction.Errors and SentTransaction.Errors are both fairly extensive. Do we need to add custom error handling beyond what is already provided in Stellar SDK? It's possible it already deals with these edge cases and the AI just cargo-culted unnecessary patterns from stale examples in the wild.
If Stellar SDK is in fact missing these cases, then I'd prefer we send an upstream PR to add the error handling in AssembledTransaction and SentTransaction, so that the entire Stellar ecosystem benefits from them, rather than complicating our specific app with these workarounds.
Closes #37
From Q2 deliverable 5:
Adds a "Deploy a contract using this Wasm" to the wasm overview page. In doing so, this PR also adds Stellar Wallets Kit and Stellar SDK as dependencies, as we need to connect a wallet in order to deploy.
Video demo:
deploy-from-wasm-demo-sm.mov