diff --git a/Cargo.lock b/Cargo.lock index 9ef713a..cfa5d38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2083,7 +2083,7 @@ checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "beam-cli" -version = "0.2.0" +version = "0.2.1" dependencies = [ "argon2", "async-trait", diff --git a/beam-apps/apps/uniswap/Cargo.lock b/beam-apps/apps/uniswap/Cargo.lock index 5f54eed..8a4e0dd 100644 --- a/beam-apps/apps/uniswap/Cargo.lock +++ b/beam-apps/apps/uniswap/Cargo.lock @@ -10,7 +10,7 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "beam-app-uniswap" -version = "1.0.0" +version = "1.0.2" dependencies = [ "hex", "num-bigint", diff --git a/beam-apps/apps/uniswap/Cargo.toml b/beam-apps/apps/uniswap/Cargo.toml index 7b710f6..79429f9 100644 --- a/beam-apps/apps/uniswap/Cargo.toml +++ b/beam-apps/apps/uniswap/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "beam-app-uniswap" -version = "1.0.0" +version = "1.0.2" edition = "2024" publish = false diff --git a/beam-apps/apps/uniswap/manifest.json b/beam-apps/apps/uniswap/manifest.json index cff6f6e..7838619 100644 --- a/beam-apps/apps/uniswap/manifest.json +++ b/beam-apps/apps/uniswap/manifest.json @@ -2,10 +2,10 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm": { "sha256": "", "entrypoint": "beam_app_main" diff --git a/beam-apps/apps/uniswap/src/host.rs b/beam-apps/apps/uniswap/src/host.rs index a86fb5c..671c17d 100644 --- a/beam-apps/apps/uniswap/src/host.rs +++ b/beam-apps/apps/uniswap/src/host.rs @@ -273,9 +273,11 @@ pub fn token_metadata(chain: &str, token: &str) -> Result { value: None, })?; let response = parse_host_value::(response)?; - let decimals = response.decimals.ok_or_else(|| Error::InvalidHostResponse { - reason: format!("token {token} missing decimals"), - })?; + let decimals = response + .decimals + .ok_or_else(|| Error::InvalidHostResponse { + reason: format!("token {token} missing decimals"), + })?; Ok(SwapToken { is_native: is_native_token(&response.address, &response.label), address: response.address, @@ -408,12 +410,11 @@ fn host_call(request: HostRequest) -> Result { })?; let mut response = vec![0_u8; HOST_RESPONSE_CAPACITY]; let len = beam_host_call_wrapper(&request, &mut response)?; - let response = - serde_json::from_slice::(&response[..len]).map_err(|err| { - Error::InvalidHostResponse { - reason: err.to_string(), - } - })?; + let response = serde_json::from_slice::(&response[..len]).map_err(|err| { + Error::InvalidHostResponse { + reason: err.to_string(), + } + })?; if !response.ok { return Err(Error::HostCallFailed { message: response diff --git a/beam-apps/apps/uniswap/src/lib.rs b/beam-apps/apps/uniswap/src/lib.rs index 5792ecd..2b5a361 100644 --- a/beam-apps/apps/uniswap/src/lib.rs +++ b/beam-apps/apps/uniswap/src/lib.rs @@ -71,13 +71,14 @@ fn run_guest(input_ptr: *const u8, input_len: usize) -> Result { reason: err.to_string(), })?; host::ensure_host_abi(&invocation)?; - let command = invocation - .args - .first() - .map(String::as_str) - .ok_or_else(|| Error::UnsupportedCommand { - command: "".to_string(), - })?; + let command = + invocation + .args + .first() + .map(String::as_str) + .ok_or_else(|| Error::UnsupportedCommand { + command: "".to_string(), + })?; match command { "swap" => { let plan = run_swap(invocation)?; @@ -146,8 +147,10 @@ fn run_swap(invocation: GuestInvocation) -> Result { &swap_payload("e, &wallet), )?; let mut swap = SwapResponse { - transaction: find_transaction(&swap_value).ok_or_else(|| Error::InvalidUniswapResponse { - reason: "swap response missing transaction".to_string(), + transaction: find_transaction(&swap_value).ok_or_else(|| { + Error::InvalidUniswapResponse { + reason: "swap response missing transaction".to_string(), + } })?, raw: swap_value, }; diff --git a/beam-apps/apps/uniswap/src/tests.rs b/beam-apps/apps/uniswap/src/tests.rs index 396c4df..2742d68 100644 --- a/beam-apps/apps/uniswap/src/tests.rs +++ b/beam-apps/apps/uniswap/src/tests.rs @@ -105,7 +105,7 @@ fn builds_approval_and_swap_action_plan() { buy: token("ETH", "0x0000000000000000000000000000000000000000", true), context: PlanContext { app_id: "uniswap".to_string(), - app_version: "1.0.0".to_string(), + app_version: "1.0.2".to_string(), chain: "base".to_string(), manifest_sha256: "sha256:manifest".to_string(), wallet: "0x3333333333333333333333333333333333333333".to_string(), diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/manifest.json.sig b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/manifest.json.sig deleted file mode 100644 index d16074d..0000000 --- a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/manifest.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" -} diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/version.json.sig b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/version.json.sig deleted file mode 100644 index 082e83b..0000000 --- a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/version.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" -} diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/icon.svg b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/icon.svg similarity index 100% rename from beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/icon.svg rename to beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/icon.svg diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/manifest.json b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/manifest.json similarity index 96% rename from beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/manifest.json rename to beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/manifest.json index 770cbe4..64199df 100644 --- a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/manifest.json +++ b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/manifest.json @@ -2,12 +2,12 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm": { - "sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "entrypoint": "beam_app_main" }, "catalog": { @@ -211,7 +211,7 @@ "privacy_reserved": true }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -219,6 +219,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:7606f4bb87567420778c2688804cb3cbfdc7d8dd49d712f10bb71177fabd4a0f" + "value": "sha256:847162262ed6ee2a090a77fdc0b7caa2bf90cbfc385fb4f18b271c00a9558f36" } } diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/manifest.json.sig b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/manifest.json.sig new file mode 100644 index 0000000..d927149 --- /dev/null +++ b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/manifest.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" +} diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/module.wasm b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/module.wasm similarity index 82% rename from beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/module.wasm rename to beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/module.wasm index 1d2b3fd..852d975 100644 Binary files a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/module.wasm and b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/module.wasm differ diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/version.json.sig b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/version.json.sig new file mode 100644 index 0000000..2a5951d --- /dev/null +++ b/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.2/version.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" +} diff --git a/beam-apps/fixtures/broad-wildcard/catalog/apps.json b/beam-apps/fixtures/broad-wildcard/catalog/apps.json index 569485f..dbba548 100644 --- a/beam-apps/fixtures/broad-wildcard/catalog/apps.json +++ b/beam-apps/fixtures/broad-wildcard/catalog/apps.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "detail_url": "https://registry.beam.payy.network/catalog/apps/uniswap.json", "install_command": "beam apps install uniswap", - "pinned_install_command": "beam apps install uniswap --version 1.0.0", + "pinned_install_command": "beam apps install uniswap --version 1.0.2", "supported_chains": [ { "id": "ethereum", @@ -90,11 +90,11 @@ "App storage" ], "version": { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -104,6 +104,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } } diff --git a/beam-apps/fixtures/broad-wildcard/catalog/apps.json.sig b/beam-apps/fixtures/broad-wildcard/catalog/apps.json.sig index e8eb833..4d6ed71 100644 --- a/beam-apps/fixtures/broad-wildcard/catalog/apps.json.sig +++ b/beam-apps/fixtures/broad-wildcard/catalog/apps.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } diff --git a/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json b/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json index a6fca62..8528dea 100644 --- a/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json +++ b/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "install_commands": { "latest": "beam apps install uniswap", - "pinned": "beam apps install uniswap --version 1.0.0", + "pinned": "beam apps install uniswap --version 1.0.2", "dry_run": "beam apps install uniswap --dry-run" }, "supported_chains": [ @@ -274,17 +274,17 @@ "readme_markdown": "# Uniswap App\n\nThe Uniswap app turns a swap request into a Beam-approved action plan. It asks\nthe Uniswap Trading API for a quote, checks your current ERC-20 allowance,\nprepares an exact approval only when one is needed, builds the swap transaction,\nand hands the whole plan to Beam for approval and execution.\n\nBeam owns your wallet boundary. The app never receives private keys, cannot sign\ntransactions, and cannot send a transaction on its own.\n\n## Install\n\n```bash\nbeam apps install uniswap\n```\n\nBeam shows the publisher, version, supported chains, network access, wallet\ncapabilities, and storage permissions before activating the app. To inspect the\nsame permission summary without installing:\n\n```bash\nbeam apps install uniswap --dry-run\n```\n\n## Swap\n\n```bash\nbeam x uniswap swap [options]\n```\n\nCommand help is exported through the app manifest and rendered by Beam without\nfetching a quote or invoking guest WASM:\n\n```bash\nbeam x uniswap swap --help\n```\n\nExample:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice\n```\n\nBeam shows the quote, any required approval, and the swap as a single plan. You\napprove the final plan before Beam signs or submits anything.\n\n## Options\n\n- `--min-receive ` sets the minimum acceptable output amount.\n- `--max-gas ` rejects the plan if estimated gas exceeds the limit.\n- `--slippage-bps ` sets max slippage in basis points.\n- `--recipient ` sends output to another wallet, ENS name, or\n EVM address.\n- `--deadline-seconds ` sets the quote and transaction deadline window.\n- `--unlimited-approval` asks Beam to request an unlimited ERC-20 approval\n instead of the default exact approval.\n\nToken inputs can be Beam token labels, `native`, the active chain's native\nsymbol, or EVM token addresses.\n\n## How a Swap Works\n\n1. The app fetches a quote through Beam-mediated HTTPS access.\n2. Beam reads your token balance and allowance through its chain APIs.\n3. If allowance is short, Beam adds an exact ERC-20 approval step.\n4. The app prepares the swap transaction.\n5. Beam renders the typed plan, asks for approval, signs, submits, and tracks the\n receipt.\n\nIf an approval is required, Beam submits it first and submits the swap only after\nthe approval is confirmed. If fresh allowance already satisfies the exact plan,\nBeam skips the approval step. Execution output reports confirmed, pending,\ndropped, or skipped transaction state; confirmed receipts include the RPC status\nvalue.\n\n## Agents\n\nAgents and other non-interactive callers should prepare a continuation, inspect\nit, then explicitly approve and execute it:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice --prepare --format json\nbeam apps approvals show \nbeam apps approvals approve --execute\n```\n\n`--no-prompt` fails closed for wallet-affecting swaps unless the command is\npreparing a continuation or executing an already-approved continuation.\n\n## Permissions\n\nThe app requests HTTPS access to the Uniswap Trading API, read/simulate/send\naccess on supported public EVM chains, ERC-20 approval planning, wallet balance\nreads, transaction proposals, and app-local storage. It does not request Beam\nprivacy capabilities in v1.\n\nSupported chains are Ethereum, Base, Arbitrum, Polygon, BNB, and Sepolia.\n\nApprovals default to the exact amount required. Unlimited approvals require the\nexplicit `--unlimited-approval` flag and are shown in the Beam approval prompt.\n", "manifest_summary": { "format_version": 1, - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm_entrypoint": "beam_app_main" }, "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" } ], "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -293,6 +293,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } } diff --git a/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json.sig b/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json.sig index add7d00..44aaaeb 100644 --- a/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json.sig +++ b/beam-apps/fixtures/broad-wildcard/catalog/apps/uniswap.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } diff --git a/beam-apps/fixtures/broad-wildcard/index.json b/beam-apps/fixtures/broad-wildcard/index.json index 872607e..d6d0817 100644 --- a/beam-apps/fixtures/broad-wildcard/index.json +++ b/beam-apps/fixtures/broad-wildcard/index.json @@ -9,16 +9,16 @@ "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2", - "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/manifest.json", - "manifest_sha256": "sha256:679a551bf48519a586975b25385e310519b077853383a4b3f7c2ff7b66ca3470", - "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/module.wasm", - "module_sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "version": "1.0.2", + "min_beam_version": "0.2.1", + "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/manifest.json", + "manifest_sha256": "sha256:07b1223ee0855508eb0c46743a3345e96422f97a7cf12175c504bfee8850341b", + "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/module.wasm", + "module_sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" } } ] @@ -27,6 +27,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } } diff --git a/beam-apps/fixtures/broad-wildcard/index.json.sig b/beam-apps/fixtures/broad-wildcard/index.json.sig index 9c8b5f1..1593252 100644 --- a/beam-apps/fixtures/broad-wildcard/index.json.sig +++ b/beam-apps/fixtures/broad-wildcard/index.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/manifest.json.sig b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/manifest.json.sig deleted file mode 100644 index d16074d..0000000 --- a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/manifest.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" -} diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/version.json.sig b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/version.json.sig deleted file mode 100644 index 082e83b..0000000 --- a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/version.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" -} diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/icon.svg b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/icon.svg similarity index 100% rename from beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/icon.svg rename to beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/icon.svg diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/manifest.json b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/manifest.json similarity index 96% rename from beam-apps/fixtures/valid/apps/uniswap/1.0.0/manifest.json rename to beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/manifest.json index a953177..5ec8c40 100644 --- a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/manifest.json +++ b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/manifest.json @@ -2,12 +2,12 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm": { - "sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "entrypoint": "beam_app_main" }, "catalog": { @@ -282,7 +282,7 @@ "privacy_reserved": true }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -290,6 +290,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" } } diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/manifest.json.sig b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/manifest.json.sig new file mode 100644 index 0000000..d927149 --- /dev/null +++ b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/manifest.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" +} diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/module.wasm b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/module.wasm similarity index 82% rename from beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/module.wasm rename to beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/module.wasm index 1d2b3fd..852d975 100644 Binary files a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/module.wasm and b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/module.wasm differ diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/version.json.sig b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/version.json.sig new file mode 100644 index 0000000..2a5951d --- /dev/null +++ b/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.2/version.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" +} diff --git a/beam-apps/fixtures/invalid-digest/catalog/apps.json b/beam-apps/fixtures/invalid-digest/catalog/apps.json index 569485f..dbba548 100644 --- a/beam-apps/fixtures/invalid-digest/catalog/apps.json +++ b/beam-apps/fixtures/invalid-digest/catalog/apps.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "detail_url": "https://registry.beam.payy.network/catalog/apps/uniswap.json", "install_command": "beam apps install uniswap", - "pinned_install_command": "beam apps install uniswap --version 1.0.0", + "pinned_install_command": "beam apps install uniswap --version 1.0.2", "supported_chains": [ { "id": "ethereum", @@ -90,11 +90,11 @@ "App storage" ], "version": { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -104,6 +104,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } } diff --git a/beam-apps/fixtures/invalid-digest/catalog/apps.json.sig b/beam-apps/fixtures/invalid-digest/catalog/apps.json.sig index e8eb833..4d6ed71 100644 --- a/beam-apps/fixtures/invalid-digest/catalog/apps.json.sig +++ b/beam-apps/fixtures/invalid-digest/catalog/apps.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } diff --git a/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json b/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json index a6fca62..8528dea 100644 --- a/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json +++ b/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "install_commands": { "latest": "beam apps install uniswap", - "pinned": "beam apps install uniswap --version 1.0.0", + "pinned": "beam apps install uniswap --version 1.0.2", "dry_run": "beam apps install uniswap --dry-run" }, "supported_chains": [ @@ -274,17 +274,17 @@ "readme_markdown": "# Uniswap App\n\nThe Uniswap app turns a swap request into a Beam-approved action plan. It asks\nthe Uniswap Trading API for a quote, checks your current ERC-20 allowance,\nprepares an exact approval only when one is needed, builds the swap transaction,\nand hands the whole plan to Beam for approval and execution.\n\nBeam owns your wallet boundary. The app never receives private keys, cannot sign\ntransactions, and cannot send a transaction on its own.\n\n## Install\n\n```bash\nbeam apps install uniswap\n```\n\nBeam shows the publisher, version, supported chains, network access, wallet\ncapabilities, and storage permissions before activating the app. To inspect the\nsame permission summary without installing:\n\n```bash\nbeam apps install uniswap --dry-run\n```\n\n## Swap\n\n```bash\nbeam x uniswap swap [options]\n```\n\nCommand help is exported through the app manifest and rendered by Beam without\nfetching a quote or invoking guest WASM:\n\n```bash\nbeam x uniswap swap --help\n```\n\nExample:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice\n```\n\nBeam shows the quote, any required approval, and the swap as a single plan. You\napprove the final plan before Beam signs or submits anything.\n\n## Options\n\n- `--min-receive ` sets the minimum acceptable output amount.\n- `--max-gas ` rejects the plan if estimated gas exceeds the limit.\n- `--slippage-bps ` sets max slippage in basis points.\n- `--recipient ` sends output to another wallet, ENS name, or\n EVM address.\n- `--deadline-seconds ` sets the quote and transaction deadline window.\n- `--unlimited-approval` asks Beam to request an unlimited ERC-20 approval\n instead of the default exact approval.\n\nToken inputs can be Beam token labels, `native`, the active chain's native\nsymbol, or EVM token addresses.\n\n## How a Swap Works\n\n1. The app fetches a quote through Beam-mediated HTTPS access.\n2. Beam reads your token balance and allowance through its chain APIs.\n3. If allowance is short, Beam adds an exact ERC-20 approval step.\n4. The app prepares the swap transaction.\n5. Beam renders the typed plan, asks for approval, signs, submits, and tracks the\n receipt.\n\nIf an approval is required, Beam submits it first and submits the swap only after\nthe approval is confirmed. If fresh allowance already satisfies the exact plan,\nBeam skips the approval step. Execution output reports confirmed, pending,\ndropped, or skipped transaction state; confirmed receipts include the RPC status\nvalue.\n\n## Agents\n\nAgents and other non-interactive callers should prepare a continuation, inspect\nit, then explicitly approve and execute it:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice --prepare --format json\nbeam apps approvals show \nbeam apps approvals approve --execute\n```\n\n`--no-prompt` fails closed for wallet-affecting swaps unless the command is\npreparing a continuation or executing an already-approved continuation.\n\n## Permissions\n\nThe app requests HTTPS access to the Uniswap Trading API, read/simulate/send\naccess on supported public EVM chains, ERC-20 approval planning, wallet balance\nreads, transaction proposals, and app-local storage. It does not request Beam\nprivacy capabilities in v1.\n\nSupported chains are Ethereum, Base, Arbitrum, Polygon, BNB, and Sepolia.\n\nApprovals default to the exact amount required. Unlimited approvals require the\nexplicit `--unlimited-approval` flag and are shown in the Beam approval prompt.\n", "manifest_summary": { "format_version": 1, - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm_entrypoint": "beam_app_main" }, "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" } ], "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -293,6 +293,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } } diff --git a/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json.sig b/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json.sig index add7d00..44aaaeb 100644 --- a/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json.sig +++ b/beam-apps/fixtures/invalid-digest/catalog/apps/uniswap.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } diff --git a/beam-apps/fixtures/invalid-digest/index.json b/beam-apps/fixtures/invalid-digest/index.json index b20a5c9..d689508 100644 --- a/beam-apps/fixtures/invalid-digest/index.json +++ b/beam-apps/fixtures/invalid-digest/index.json @@ -9,16 +9,16 @@ "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2", - "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/manifest.json", - "manifest_sha256": "sha256:679a551bf48519a586975b25385e310519b077853383a4b3f7c2ff7b66ca3470", - "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/module.wasm", + "version": "1.0.2", + "min_beam_version": "0.2.1", + "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/manifest.json", + "manifest_sha256": "sha256:07b1223ee0855508eb0c46743a3345e96422f97a7cf12175c504bfee8850341b", + "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/module.wasm", "module_sha256": "sha256:0000000000000000000000000000000000000000000000000000000000000000", "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" } } ] @@ -27,6 +27,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:c71291f48e084cb773bc003d3fa7536acd0c653632547da79d32373107f89d6d" + "value": "sha256:293d1e56cb7ac2c07c4136e2fd94afd9a8d175702bb8e8bd9c5afce93184fa7a" } } diff --git a/beam-apps/fixtures/invalid-digest/index.json.sig b/beam-apps/fixtures/invalid-digest/index.json.sig index 9c8b5f1..1593252 100644 --- a/beam-apps/fixtures/invalid-digest/index.json.sig +++ b/beam-apps/fixtures/invalid-digest/index.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/manifest.json.sig b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/manifest.json.sig deleted file mode 100644 index d16074d..0000000 --- a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/manifest.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" -} diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/version.json.sig b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/version.json.sig deleted file mode 100644 index 082e83b..0000000 --- a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/version.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" -} diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/icon.svg b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/icon.svg similarity index 100% rename from beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/icon.svg rename to beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/icon.svg diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/manifest.json b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/manifest.json similarity index 96% rename from beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/manifest.json rename to beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/manifest.json index 43856d7..007c650 100644 --- a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.0/manifest.json +++ b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/manifest.json @@ -2,12 +2,12 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm": { - "sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "entrypoint": "beam_app_main" }, "catalog": { @@ -213,7 +213,7 @@ "privacy_reserved": true }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -221,6 +221,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:e8ec17a0f387c153dbc952556c9f4b320e15694de2c564fafc998098121fcba5" + "value": "sha256:bb1fb10740ad500c6a37064acf750be47297a8a8889c2d4df6333accbb5a8ff6" } } diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/manifest.json.sig b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/manifest.json.sig new file mode 100644 index 0000000..d927149 --- /dev/null +++ b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/manifest.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" +} diff --git a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/module.wasm b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/module.wasm similarity index 82% rename from beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/module.wasm rename to beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/module.wasm index 1d2b3fd..852d975 100644 Binary files a/beam-apps/fixtures/broad-wildcard/apps/uniswap/1.0.0/module.wasm and b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/module.wasm differ diff --git a/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/version.json.sig b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/version.json.sig new file mode 100644 index 0000000..2a5951d --- /dev/null +++ b/beam-apps/fixtures/malformed-permissions/apps/uniswap/1.0.2/version.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" +} diff --git a/beam-apps/fixtures/malformed-permissions/catalog/apps.json b/beam-apps/fixtures/malformed-permissions/catalog/apps.json index 569485f..dbba548 100644 --- a/beam-apps/fixtures/malformed-permissions/catalog/apps.json +++ b/beam-apps/fixtures/malformed-permissions/catalog/apps.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "detail_url": "https://registry.beam.payy.network/catalog/apps/uniswap.json", "install_command": "beam apps install uniswap", - "pinned_install_command": "beam apps install uniswap --version 1.0.0", + "pinned_install_command": "beam apps install uniswap --version 1.0.2", "supported_chains": [ { "id": "ethereum", @@ -90,11 +90,11 @@ "App storage" ], "version": { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -104,6 +104,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } } diff --git a/beam-apps/fixtures/malformed-permissions/catalog/apps.json.sig b/beam-apps/fixtures/malformed-permissions/catalog/apps.json.sig index e8eb833..4d6ed71 100644 --- a/beam-apps/fixtures/malformed-permissions/catalog/apps.json.sig +++ b/beam-apps/fixtures/malformed-permissions/catalog/apps.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } diff --git a/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json b/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json index a6fca62..8528dea 100644 --- a/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json +++ b/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "install_commands": { "latest": "beam apps install uniswap", - "pinned": "beam apps install uniswap --version 1.0.0", + "pinned": "beam apps install uniswap --version 1.0.2", "dry_run": "beam apps install uniswap --dry-run" }, "supported_chains": [ @@ -274,17 +274,17 @@ "readme_markdown": "# Uniswap App\n\nThe Uniswap app turns a swap request into a Beam-approved action plan. It asks\nthe Uniswap Trading API for a quote, checks your current ERC-20 allowance,\nprepares an exact approval only when one is needed, builds the swap transaction,\nand hands the whole plan to Beam for approval and execution.\n\nBeam owns your wallet boundary. The app never receives private keys, cannot sign\ntransactions, and cannot send a transaction on its own.\n\n## Install\n\n```bash\nbeam apps install uniswap\n```\n\nBeam shows the publisher, version, supported chains, network access, wallet\ncapabilities, and storage permissions before activating the app. To inspect the\nsame permission summary without installing:\n\n```bash\nbeam apps install uniswap --dry-run\n```\n\n## Swap\n\n```bash\nbeam x uniswap swap [options]\n```\n\nCommand help is exported through the app manifest and rendered by Beam without\nfetching a quote or invoking guest WASM:\n\n```bash\nbeam x uniswap swap --help\n```\n\nExample:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice\n```\n\nBeam shows the quote, any required approval, and the swap as a single plan. You\napprove the final plan before Beam signs or submits anything.\n\n## Options\n\n- `--min-receive ` sets the minimum acceptable output amount.\n- `--max-gas ` rejects the plan if estimated gas exceeds the limit.\n- `--slippage-bps ` sets max slippage in basis points.\n- `--recipient ` sends output to another wallet, ENS name, or\n EVM address.\n- `--deadline-seconds ` sets the quote and transaction deadline window.\n- `--unlimited-approval` asks Beam to request an unlimited ERC-20 approval\n instead of the default exact approval.\n\nToken inputs can be Beam token labels, `native`, the active chain's native\nsymbol, or EVM token addresses.\n\n## How a Swap Works\n\n1. The app fetches a quote through Beam-mediated HTTPS access.\n2. Beam reads your token balance and allowance through its chain APIs.\n3. If allowance is short, Beam adds an exact ERC-20 approval step.\n4. The app prepares the swap transaction.\n5. Beam renders the typed plan, asks for approval, signs, submits, and tracks the\n receipt.\n\nIf an approval is required, Beam submits it first and submits the swap only after\nthe approval is confirmed. If fresh allowance already satisfies the exact plan,\nBeam skips the approval step. Execution output reports confirmed, pending,\ndropped, or skipped transaction state; confirmed receipts include the RPC status\nvalue.\n\n## Agents\n\nAgents and other non-interactive callers should prepare a continuation, inspect\nit, then explicitly approve and execute it:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice --prepare --format json\nbeam apps approvals show \nbeam apps approvals approve --execute\n```\n\n`--no-prompt` fails closed for wallet-affecting swaps unless the command is\npreparing a continuation or executing an already-approved continuation.\n\n## Permissions\n\nThe app requests HTTPS access to the Uniswap Trading API, read/simulate/send\naccess on supported public EVM chains, ERC-20 approval planning, wallet balance\nreads, transaction proposals, and app-local storage. It does not request Beam\nprivacy capabilities in v1.\n\nSupported chains are Ethereum, Base, Arbitrum, Polygon, BNB, and Sepolia.\n\nApprovals default to the exact amount required. Unlimited approvals require the\nexplicit `--unlimited-approval` flag and are shown in the Beam approval prompt.\n", "manifest_summary": { "format_version": 1, - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm_entrypoint": "beam_app_main" }, "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" } ], "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -293,6 +293,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } } diff --git a/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json.sig b/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json.sig index add7d00..44aaaeb 100644 --- a/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json.sig +++ b/beam-apps/fixtures/malformed-permissions/catalog/apps/uniswap.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } diff --git a/beam-apps/fixtures/malformed-permissions/index.json b/beam-apps/fixtures/malformed-permissions/index.json index 872607e..d6d0817 100644 --- a/beam-apps/fixtures/malformed-permissions/index.json +++ b/beam-apps/fixtures/malformed-permissions/index.json @@ -9,16 +9,16 @@ "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2", - "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/manifest.json", - "manifest_sha256": "sha256:679a551bf48519a586975b25385e310519b077853383a4b3f7c2ff7b66ca3470", - "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/module.wasm", - "module_sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "version": "1.0.2", + "min_beam_version": "0.2.1", + "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/manifest.json", + "manifest_sha256": "sha256:07b1223ee0855508eb0c46743a3345e96422f97a7cf12175c504bfee8850341b", + "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/module.wasm", + "module_sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" } } ] @@ -27,6 +27,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } } diff --git a/beam-apps/fixtures/malformed-permissions/index.json.sig b/beam-apps/fixtures/malformed-permissions/index.json.sig index 9c8b5f1..1593252 100644 --- a/beam-apps/fixtures/malformed-permissions/index.json.sig +++ b/beam-apps/fixtures/malformed-permissions/index.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/manifest.json.sig b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/manifest.json.sig deleted file mode 100644 index d16074d..0000000 --- a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/manifest.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" -} diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/version.json.sig b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/version.json.sig deleted file mode 100644 index 082e83b..0000000 --- a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/version.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" -} diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/icon.svg b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/icon.svg similarity index 100% rename from beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/icon.svg rename to beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/icon.svg diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/manifest.json b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/manifest.json similarity index 91% rename from beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/manifest.json rename to beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/manifest.json index d6ef0b8..e1b0e0b 100644 --- a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/manifest.json +++ b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/manifest.json @@ -2,12 +2,12 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm": { - "sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "entrypoint": "beam_app_main" }, "catalog": { @@ -121,7 +121,7 @@ "privacy_reserved": true }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -129,6 +129,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:80eaa89c54f1d5eb38198f9de7c261e6446ffe700d6c9313232f076bb783c518" + "value": "sha256:2baa744c8f1d81ebe4e28aff957d05f1371ed81e22c604ed4fc4a9dabce0c1d8" } } diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/manifest.json.sig b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/manifest.json.sig new file mode 100644 index 0000000..d927149 --- /dev/null +++ b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/manifest.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" +} diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/module.wasm b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/module.wasm similarity index 82% rename from beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/module.wasm rename to beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/module.wasm index 1d2b3fd..852d975 100644 Binary files a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.0/module.wasm and b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/module.wasm differ diff --git a/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/version.json.sig b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/version.json.sig new file mode 100644 index 0000000..2a5951d --- /dev/null +++ b/beam-apps/fixtures/missing-fields/apps/uniswap/1.0.2/version.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" +} diff --git a/beam-apps/fixtures/missing-fields/catalog/apps.json b/beam-apps/fixtures/missing-fields/catalog/apps.json index 569485f..dbba548 100644 --- a/beam-apps/fixtures/missing-fields/catalog/apps.json +++ b/beam-apps/fixtures/missing-fields/catalog/apps.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "detail_url": "https://registry.beam.payy.network/catalog/apps/uniswap.json", "install_command": "beam apps install uniswap", - "pinned_install_command": "beam apps install uniswap --version 1.0.0", + "pinned_install_command": "beam apps install uniswap --version 1.0.2", "supported_chains": [ { "id": "ethereum", @@ -90,11 +90,11 @@ "App storage" ], "version": { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -104,6 +104,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } } diff --git a/beam-apps/fixtures/missing-fields/catalog/apps.json.sig b/beam-apps/fixtures/missing-fields/catalog/apps.json.sig index e8eb833..4d6ed71 100644 --- a/beam-apps/fixtures/missing-fields/catalog/apps.json.sig +++ b/beam-apps/fixtures/missing-fields/catalog/apps.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } diff --git a/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json b/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json index a6fca62..8528dea 100644 --- a/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json +++ b/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "install_commands": { "latest": "beam apps install uniswap", - "pinned": "beam apps install uniswap --version 1.0.0", + "pinned": "beam apps install uniswap --version 1.0.2", "dry_run": "beam apps install uniswap --dry-run" }, "supported_chains": [ @@ -274,17 +274,17 @@ "readme_markdown": "# Uniswap App\n\nThe Uniswap app turns a swap request into a Beam-approved action plan. It asks\nthe Uniswap Trading API for a quote, checks your current ERC-20 allowance,\nprepares an exact approval only when one is needed, builds the swap transaction,\nand hands the whole plan to Beam for approval and execution.\n\nBeam owns your wallet boundary. The app never receives private keys, cannot sign\ntransactions, and cannot send a transaction on its own.\n\n## Install\n\n```bash\nbeam apps install uniswap\n```\n\nBeam shows the publisher, version, supported chains, network access, wallet\ncapabilities, and storage permissions before activating the app. To inspect the\nsame permission summary without installing:\n\n```bash\nbeam apps install uniswap --dry-run\n```\n\n## Swap\n\n```bash\nbeam x uniswap swap [options]\n```\n\nCommand help is exported through the app manifest and rendered by Beam without\nfetching a quote or invoking guest WASM:\n\n```bash\nbeam x uniswap swap --help\n```\n\nExample:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice\n```\n\nBeam shows the quote, any required approval, and the swap as a single plan. You\napprove the final plan before Beam signs or submits anything.\n\n## Options\n\n- `--min-receive ` sets the minimum acceptable output amount.\n- `--max-gas ` rejects the plan if estimated gas exceeds the limit.\n- `--slippage-bps ` sets max slippage in basis points.\n- `--recipient ` sends output to another wallet, ENS name, or\n EVM address.\n- `--deadline-seconds ` sets the quote and transaction deadline window.\n- `--unlimited-approval` asks Beam to request an unlimited ERC-20 approval\n instead of the default exact approval.\n\nToken inputs can be Beam token labels, `native`, the active chain's native\nsymbol, or EVM token addresses.\n\n## How a Swap Works\n\n1. The app fetches a quote through Beam-mediated HTTPS access.\n2. Beam reads your token balance and allowance through its chain APIs.\n3. If allowance is short, Beam adds an exact ERC-20 approval step.\n4. The app prepares the swap transaction.\n5. Beam renders the typed plan, asks for approval, signs, submits, and tracks the\n receipt.\n\nIf an approval is required, Beam submits it first and submits the swap only after\nthe approval is confirmed. If fresh allowance already satisfies the exact plan,\nBeam skips the approval step. Execution output reports confirmed, pending,\ndropped, or skipped transaction state; confirmed receipts include the RPC status\nvalue.\n\n## Agents\n\nAgents and other non-interactive callers should prepare a continuation, inspect\nit, then explicitly approve and execute it:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice --prepare --format json\nbeam apps approvals show \nbeam apps approvals approve --execute\n```\n\n`--no-prompt` fails closed for wallet-affecting swaps unless the command is\npreparing a continuation or executing an already-approved continuation.\n\n## Permissions\n\nThe app requests HTTPS access to the Uniswap Trading API, read/simulate/send\naccess on supported public EVM chains, ERC-20 approval planning, wallet balance\nreads, transaction proposals, and app-local storage. It does not request Beam\nprivacy capabilities in v1.\n\nSupported chains are Ethereum, Base, Arbitrum, Polygon, BNB, and Sepolia.\n\nApprovals default to the exact amount required. Unlimited approvals require the\nexplicit `--unlimited-approval` flag and are shown in the Beam approval prompt.\n", "manifest_summary": { "format_version": 1, - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm_entrypoint": "beam_app_main" }, "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" } ], "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -293,6 +293,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } } diff --git a/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json.sig b/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json.sig index add7d00..44aaaeb 100644 --- a/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json.sig +++ b/beam-apps/fixtures/missing-fields/catalog/apps/uniswap.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } diff --git a/beam-apps/fixtures/missing-fields/index.json b/beam-apps/fixtures/missing-fields/index.json index 872607e..d6d0817 100644 --- a/beam-apps/fixtures/missing-fields/index.json +++ b/beam-apps/fixtures/missing-fields/index.json @@ -9,16 +9,16 @@ "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2", - "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/manifest.json", - "manifest_sha256": "sha256:679a551bf48519a586975b25385e310519b077853383a4b3f7c2ff7b66ca3470", - "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/module.wasm", - "module_sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "version": "1.0.2", + "min_beam_version": "0.2.1", + "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/manifest.json", + "manifest_sha256": "sha256:07b1223ee0855508eb0c46743a3345e96422f97a7cf12175c504bfee8850341b", + "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/module.wasm", + "module_sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" } } ] @@ -27,6 +27,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } } diff --git a/beam-apps/fixtures/missing-fields/index.json.sig b/beam-apps/fixtures/missing-fields/index.json.sig index 9c8b5f1..1593252 100644 --- a/beam-apps/fixtures/missing-fields/index.json.sig +++ b/beam-apps/fixtures/missing-fields/index.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/manifest.json.sig b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/manifest.json.sig deleted file mode 100644 index d16074d..0000000 --- a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/manifest.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" -} diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/module.wasm b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/module.wasm deleted file mode 100644 index 1d2b3fd..0000000 Binary files a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/module.wasm and /dev/null differ diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/version.json.sig b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/version.json.sig deleted file mode 100644 index 082e83b..0000000 --- a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/version.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" -} diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/icon.svg b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/icon.svg similarity index 100% rename from beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/icon.svg rename to beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/icon.svg diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/manifest.json b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/manifest.json similarity index 97% rename from beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/manifest.json rename to beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/manifest.json index a8bf809..4c68d88 100644 --- a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.0/manifest.json +++ b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/manifest.json @@ -2,12 +2,12 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "min_beam_version": "999.0.0", "wasm": { - "sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "entrypoint": "beam_app_main" }, "catalog": { @@ -282,7 +282,7 @@ "privacy_reserved": true }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -290,6 +290,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:52aa83b6ee6df8f59c6abbfef5593fcb4f05c0b6d2a9d7468de5c0428ecc0d15" + "value": "sha256:0b2b6fa6ae3017fbc1316892bd357652c70f66a9b3f9dabe7e313946c604b07f" } } diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/manifest.json.sig b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/manifest.json.sig new file mode 100644 index 0000000..d927149 --- /dev/null +++ b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/manifest.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" +} diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/module.wasm b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/module.wasm new file mode 100644 index 0000000..852d975 Binary files /dev/null and b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/module.wasm differ diff --git a/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/version.json.sig b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/version.json.sig new file mode 100644 index 0000000..2a5951d --- /dev/null +++ b/beam-apps/fixtures/unsupported-beam/apps/uniswap/1.0.2/version.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" +} diff --git a/beam-apps/fixtures/unsupported-beam/catalog/apps.json b/beam-apps/fixtures/unsupported-beam/catalog/apps.json index 569485f..dbba548 100644 --- a/beam-apps/fixtures/unsupported-beam/catalog/apps.json +++ b/beam-apps/fixtures/unsupported-beam/catalog/apps.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "detail_url": "https://registry.beam.payy.network/catalog/apps/uniswap.json", "install_command": "beam apps install uniswap", - "pinned_install_command": "beam apps install uniswap --version 1.0.0", + "pinned_install_command": "beam apps install uniswap --version 1.0.2", "supported_chains": [ { "id": "ethereum", @@ -90,11 +90,11 @@ "App storage" ], "version": { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -104,6 +104,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } } diff --git a/beam-apps/fixtures/unsupported-beam/catalog/apps.json.sig b/beam-apps/fixtures/unsupported-beam/catalog/apps.json.sig index e8eb833..4d6ed71 100644 --- a/beam-apps/fixtures/unsupported-beam/catalog/apps.json.sig +++ b/beam-apps/fixtures/unsupported-beam/catalog/apps.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } diff --git a/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json b/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json index a6fca62..8528dea 100644 --- a/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json +++ b/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "install_commands": { "latest": "beam apps install uniswap", - "pinned": "beam apps install uniswap --version 1.0.0", + "pinned": "beam apps install uniswap --version 1.0.2", "dry_run": "beam apps install uniswap --dry-run" }, "supported_chains": [ @@ -274,17 +274,17 @@ "readme_markdown": "# Uniswap App\n\nThe Uniswap app turns a swap request into a Beam-approved action plan. It asks\nthe Uniswap Trading API for a quote, checks your current ERC-20 allowance,\nprepares an exact approval only when one is needed, builds the swap transaction,\nand hands the whole plan to Beam for approval and execution.\n\nBeam owns your wallet boundary. The app never receives private keys, cannot sign\ntransactions, and cannot send a transaction on its own.\n\n## Install\n\n```bash\nbeam apps install uniswap\n```\n\nBeam shows the publisher, version, supported chains, network access, wallet\ncapabilities, and storage permissions before activating the app. To inspect the\nsame permission summary without installing:\n\n```bash\nbeam apps install uniswap --dry-run\n```\n\n## Swap\n\n```bash\nbeam x uniswap swap [options]\n```\n\nCommand help is exported through the app manifest and rendered by Beam without\nfetching a quote or invoking guest WASM:\n\n```bash\nbeam x uniswap swap --help\n```\n\nExample:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice\n```\n\nBeam shows the quote, any required approval, and the swap as a single plan. You\napprove the final plan before Beam signs or submits anything.\n\n## Options\n\n- `--min-receive ` sets the minimum acceptable output amount.\n- `--max-gas ` rejects the plan if estimated gas exceeds the limit.\n- `--slippage-bps ` sets max slippage in basis points.\n- `--recipient ` sends output to another wallet, ENS name, or\n EVM address.\n- `--deadline-seconds ` sets the quote and transaction deadline window.\n- `--unlimited-approval` asks Beam to request an unlimited ERC-20 approval\n instead of the default exact approval.\n\nToken inputs can be Beam token labels, `native`, the active chain's native\nsymbol, or EVM token addresses.\n\n## How a Swap Works\n\n1. The app fetches a quote through Beam-mediated HTTPS access.\n2. Beam reads your token balance and allowance through its chain APIs.\n3. If allowance is short, Beam adds an exact ERC-20 approval step.\n4. The app prepares the swap transaction.\n5. Beam renders the typed plan, asks for approval, signs, submits, and tracks the\n receipt.\n\nIf an approval is required, Beam submits it first and submits the swap only after\nthe approval is confirmed. If fresh allowance already satisfies the exact plan,\nBeam skips the approval step. Execution output reports confirmed, pending,\ndropped, or skipped transaction state; confirmed receipts include the RPC status\nvalue.\n\n## Agents\n\nAgents and other non-interactive callers should prepare a continuation, inspect\nit, then explicitly approve and execute it:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice --prepare --format json\nbeam apps approvals show \nbeam apps approvals approve --execute\n```\n\n`--no-prompt` fails closed for wallet-affecting swaps unless the command is\npreparing a continuation or executing an already-approved continuation.\n\n## Permissions\n\nThe app requests HTTPS access to the Uniswap Trading API, read/simulate/send\naccess on supported public EVM chains, ERC-20 approval planning, wallet balance\nreads, transaction proposals, and app-local storage. It does not request Beam\nprivacy capabilities in v1.\n\nSupported chains are Ethereum, Base, Arbitrum, Polygon, BNB, and Sepolia.\n\nApprovals default to the exact amount required. Unlimited approvals require the\nexplicit `--unlimited-approval` flag and are shown in the Beam approval prompt.\n", "manifest_summary": { "format_version": 1, - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm_entrypoint": "beam_app_main" }, "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" } ], "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -293,6 +293,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } } diff --git a/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json.sig b/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json.sig index add7d00..44aaaeb 100644 --- a/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json.sig +++ b/beam-apps/fixtures/unsupported-beam/catalog/apps/uniswap.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } diff --git a/beam-apps/fixtures/unsupported-beam/index.json b/beam-apps/fixtures/unsupported-beam/index.json index 872607e..d6d0817 100644 --- a/beam-apps/fixtures/unsupported-beam/index.json +++ b/beam-apps/fixtures/unsupported-beam/index.json @@ -9,16 +9,16 @@ "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2", - "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/manifest.json", - "manifest_sha256": "sha256:679a551bf48519a586975b25385e310519b077853383a4b3f7c2ff7b66ca3470", - "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/module.wasm", - "module_sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "version": "1.0.2", + "min_beam_version": "0.2.1", + "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/manifest.json", + "manifest_sha256": "sha256:07b1223ee0855508eb0c46743a3345e96422f97a7cf12175c504bfee8850341b", + "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/module.wasm", + "module_sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" } } ] @@ -27,6 +27,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } } diff --git a/beam-apps/fixtures/unsupported-beam/index.json.sig b/beam-apps/fixtures/unsupported-beam/index.json.sig index 9c8b5f1..1593252 100644 --- a/beam-apps/fixtures/unsupported-beam/index.json.sig +++ b/beam-apps/fixtures/unsupported-beam/index.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/manifest.json.sig b/beam-apps/fixtures/valid/apps/uniswap/1.0.0/manifest.json.sig deleted file mode 100644 index d16074d..0000000 --- a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/manifest.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" -} diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/module.wasm b/beam-apps/fixtures/valid/apps/uniswap/1.0.0/module.wasm deleted file mode 100644 index 1d2b3fd..0000000 Binary files a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/module.wasm and /dev/null differ diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/version.json.sig b/beam-apps/fixtures/valid/apps/uniswap/1.0.0/version.json.sig deleted file mode 100644 index 082e83b..0000000 --- a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/version.json.sig +++ /dev/null @@ -1,5 +0,0 @@ -{ - "algorithm": "sha256-dev", - "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" -} diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.0/icon.svg b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/icon.svg similarity index 100% rename from beam-apps/fixtures/valid/apps/uniswap/1.0.0/icon.svg rename to beam-apps/fixtures/valid/apps/uniswap/1.0.2/icon.svg diff --git a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/manifest.json b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/manifest.json similarity index 96% rename from beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/manifest.json rename to beam-apps/fixtures/valid/apps/uniswap/1.0.2/manifest.json index a953177..5ec8c40 100644 --- a/beam-apps/fixtures/invalid-digest/apps/uniswap/1.0.0/manifest.json +++ b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/manifest.json @@ -2,12 +2,12 @@ "format_version": 1, "id": "uniswap", "display_name": "Uniswap", - "version": "1.0.0", + "version": "1.0.2", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm": { - "sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "entrypoint": "beam_app_main" }, "catalog": { @@ -282,7 +282,7 @@ "privacy_reserved": true }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -290,6 +290,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:2f47a3e064fdc3572cc68eb52929147275f5e57fc958e82e59e8c2a5f21ab57e" + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" } } diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.2/manifest.json.sig b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/manifest.json.sig new file mode 100644 index 0000000..d927149 --- /dev/null +++ b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/manifest.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:a7bac552c206a4a3a86a0261d6e8efe4e374b62780e692669d4055c7f2933178" +} diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.2/module.wasm b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/module.wasm new file mode 100644 index 0000000..852d975 Binary files /dev/null and b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/module.wasm differ diff --git a/beam-apps/fixtures/valid/apps/uniswap/1.0.2/version.json.sig b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/version.json.sig new file mode 100644 index 0000000..2a5951d --- /dev/null +++ b/beam-apps/fixtures/valid/apps/uniswap/1.0.2/version.json.sig @@ -0,0 +1,5 @@ +{ + "algorithm": "sha256-dev", + "key_id": "payy-dev-2026-05", + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" +} diff --git a/beam-apps/fixtures/valid/catalog/apps.json b/beam-apps/fixtures/valid/catalog/apps.json index 569485f..dbba548 100644 --- a/beam-apps/fixtures/valid/catalog/apps.json +++ b/beam-apps/fixtures/valid/catalog/apps.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "detail_url": "https://registry.beam.payy.network/catalog/apps/uniswap.json", "install_command": "beam apps install uniswap", - "pinned_install_command": "beam apps install uniswap --version 1.0.0", + "pinned_install_command": "beam apps install uniswap --version 1.0.2", "supported_chains": [ { "id": "ethereum", @@ -90,11 +90,11 @@ "App storage" ], "version": { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" }, "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -104,6 +104,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } } diff --git a/beam-apps/fixtures/valid/catalog/apps.json.sig b/beam-apps/fixtures/valid/catalog/apps.json.sig index e8eb833..4d6ed71 100644 --- a/beam-apps/fixtures/valid/catalog/apps.json.sig +++ b/beam-apps/fixtures/valid/catalog/apps.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:83a8fa8333089b3481f93f9caacd25bae6dab5bdd4d39cdfafaec2ccbc87efab" + "value": "sha256:066b1321d86de07e799ba77ac8a531d7a14c258b5ff79cb6e7f352a6cf8ab5d7" } diff --git a/beam-apps/fixtures/valid/catalog/apps/uniswap.json b/beam-apps/fixtures/valid/catalog/apps/uniswap.json index a6fca62..8528dea 100644 --- a/beam-apps/fixtures/valid/catalog/apps/uniswap.json +++ b/beam-apps/fixtures/valid/catalog/apps/uniswap.json @@ -7,11 +7,11 @@ "display_name": "Uniswap", "publisher": "Payy", "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", - "latest_version": "1.0.0", - "min_beam_version": "0.1.2", + "latest_version": "1.0.2", + "min_beam_version": "0.2.1", "install_commands": { "latest": "beam apps install uniswap", - "pinned": "beam apps install uniswap --version 1.0.0", + "pinned": "beam apps install uniswap --version 1.0.2", "dry_run": "beam apps install uniswap --dry-run" }, "supported_chains": [ @@ -274,17 +274,17 @@ "readme_markdown": "# Uniswap App\n\nThe Uniswap app turns a swap request into a Beam-approved action plan. It asks\nthe Uniswap Trading API for a quote, checks your current ERC-20 allowance,\nprepares an exact approval only when one is needed, builds the swap transaction,\nand hands the whole plan to Beam for approval and execution.\n\nBeam owns your wallet boundary. The app never receives private keys, cannot sign\ntransactions, and cannot send a transaction on its own.\n\n## Install\n\n```bash\nbeam apps install uniswap\n```\n\nBeam shows the publisher, version, supported chains, network access, wallet\ncapabilities, and storage permissions before activating the app. To inspect the\nsame permission summary without installing:\n\n```bash\nbeam apps install uniswap --dry-run\n```\n\n## Swap\n\n```bash\nbeam x uniswap swap [options]\n```\n\nCommand help is exported through the app manifest and rendered by Beam without\nfetching a quote or invoking guest WASM:\n\n```bash\nbeam x uniswap swap --help\n```\n\nExample:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice\n```\n\nBeam shows the quote, any required approval, and the swap as a single plan. You\napprove the final plan before Beam signs or submits anything.\n\n## Options\n\n- `--min-receive ` sets the minimum acceptable output amount.\n- `--max-gas ` rejects the plan if estimated gas exceeds the limit.\n- `--slippage-bps ` sets max slippage in basis points.\n- `--recipient ` sends output to another wallet, ENS name, or\n EVM address.\n- `--deadline-seconds ` sets the quote and transaction deadline window.\n- `--unlimited-approval` asks Beam to request an unlimited ERC-20 approval\n instead of the default exact approval.\n\nToken inputs can be Beam token labels, `native`, the active chain's native\nsymbol, or EVM token addresses.\n\n## How a Swap Works\n\n1. The app fetches a quote through Beam-mediated HTTPS access.\n2. Beam reads your token balance and allowance through its chain APIs.\n3. If allowance is short, Beam adds an exact ERC-20 approval step.\n4. The app prepares the swap transaction.\n5. Beam renders the typed plan, asks for approval, signs, submits, and tracks the\n receipt.\n\nIf an approval is required, Beam submits it first and submits the swap only after\nthe approval is confirmed. If fresh allowance already satisfies the exact plan,\nBeam skips the approval step. Execution output reports confirmed, pending,\ndropped, or skipped transaction state; confirmed receipts include the RPC status\nvalue.\n\n## Agents\n\nAgents and other non-interactive callers should prepare a continuation, inspect\nit, then explicitly approve and execute it:\n\n```bash\nbeam x uniswap swap USDC ETH 100 --chain base --from alice --prepare --format json\nbeam apps approvals show \nbeam apps approvals approve --execute\n```\n\n`--no-prompt` fails closed for wallet-affecting swaps unless the command is\npreparing a continuation or executing an already-approved continuation.\n\n## Permissions\n\nThe app requests HTTPS access to the Uniswap Trading API, read/simulate/send\naccess on supported public EVM chains, ERC-20 approval planning, wallet balance\nreads, transaction proposals, and app-local storage. It does not request Beam\nprivacy capabilities in v1.\n\nSupported chains are Ethereum, Base, Arbitrum, Polygon, BNB, and Sepolia.\n\nApprovals default to the exact amount required. Unlimited approvals require the\nexplicit `--unlimited-approval` flag and are shown in the Beam approval prompt.\n", "manifest_summary": { "format_version": 1, - "min_beam_version": "0.1.2", + "min_beam_version": "0.2.1", "wasm_entrypoint": "beam_app_main" }, "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2" + "version": "1.0.2", + "min_beam_version": "0.2.1" } ], "icon": { - "url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/icon.svg", + "url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/icon.svg", "sha256": "sha256:a7588127f926d7f5aa352cdeca3ab596c4ed673df98fc964af3e9c9f27e65b0d", "media_type": "image/svg+xml", "alt": "Uniswap logo" @@ -293,6 +293,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } } diff --git a/beam-apps/fixtures/valid/catalog/apps/uniswap.json.sig b/beam-apps/fixtures/valid/catalog/apps/uniswap.json.sig index add7d00..44aaaeb 100644 --- a/beam-apps/fixtures/valid/catalog/apps/uniswap.json.sig +++ b/beam-apps/fixtures/valid/catalog/apps/uniswap.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:cf1ff80f294be2c782b248b643bf45ad2aa8d1c45d4fd48ef3e160e601037b42" + "value": "sha256:54e79a5357fd6defd210f7f6ec88d70a6b0212cd805b273fcc6731ae81d59279" } diff --git a/beam-apps/fixtures/valid/index.json b/beam-apps/fixtures/valid/index.json index 872607e..d6d0817 100644 --- a/beam-apps/fixtures/valid/index.json +++ b/beam-apps/fixtures/valid/index.json @@ -9,16 +9,16 @@ "description": "Prepare public Uniswap swaps through Beam-mediated HTTP, chain, approval, and transaction planning.", "versions": [ { - "version": "1.0.0", - "min_beam_version": "0.1.2", - "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/manifest.json", - "manifest_sha256": "sha256:679a551bf48519a586975b25385e310519b077853383a4b3f7c2ff7b66ca3470", - "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.0/module.wasm", - "module_sha256": "sha256:15dadd2f783c783594c5c586f494f7b31be6dc89e5efbab1c479cf317b15ad0f", + "version": "1.0.2", + "min_beam_version": "0.2.1", + "manifest_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/manifest.json", + "manifest_sha256": "sha256:07b1223ee0855508eb0c46743a3345e96422f97a7cf12175c504bfee8850341b", + "module_url": "https://registry.beam.payy.network/apps/uniswap/1.0.2/module.wasm", + "module_sha256": "sha256:18aa6e8845772beccef895e83bbf2d1f3783d24fbf0fb8feee75d1eacfa1a7f9", "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:d66c14c15fb72b7d083a8a61984e2356a130b521fb70e664edefcfabd08ed8dd" + "value": "sha256:c066a56b6703a1d421195be37474192a11a960ce259991ff3cb91fd2f062c8de" } } ] @@ -27,6 +27,6 @@ "signature": { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } } diff --git a/beam-apps/fixtures/valid/index.json.sig b/beam-apps/fixtures/valid/index.json.sig index 9c8b5f1..1593252 100644 --- a/beam-apps/fixtures/valid/index.json.sig +++ b/beam-apps/fixtures/valid/index.json.sig @@ -1,5 +1,5 @@ { "algorithm": "sha256-dev", "key_id": "payy-dev-2026-05", - "value": "sha256:40a78ac42754c32d9e50aab13e98882852a73f14155a648919d1fdae928e78a8" + "value": "sha256:02b57fe91af9b8247f4b71214bbe382ea4b09a63461bd05c5e59e61987a5c98d" } diff --git a/pkg/beam-cli/Cargo.toml b/pkg/beam-cli/Cargo.toml index 2a69627..45e9b41 100644 --- a/pkg/beam-cli/Cargo.toml +++ b/pkg/beam-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "beam-cli" -version = "0.2.0" +version = "0.2.1" edition = "2024" publish = false diff --git a/pkg/beam-cli/src/apps/registry.rs b/pkg/beam-cli/src/apps/registry.rs index c99239a..abe0b97 100644 --- a/pkg/beam-cli/src/apps/registry.rs +++ b/pkg/beam-cli/src/apps/registry.rs @@ -8,6 +8,7 @@ use sha2::{Digest, Sha256}; use crate::apps::{ Error, Result, model::{AppManifest, RegistryApp, RegistryIndex, RegistrySignature, RegistryVersion}, + runtime::validate_wasm_module_bytes, validate::{ensure_beam_version, validate_index, validate_manifest, validate_registry_url}, }; @@ -48,6 +49,7 @@ pub async fn fetch_module(version: &RegistryVersion, manifest: &AppManifest) -> let bytes = fetch_bytes(&version.module_url).await?; ensure_digest("module", &bytes, &version.module_sha256)?; ensure_digest("wasm", &bytes, &manifest.wasm.sha256)?; + validate_wasm_module_bytes(&manifest.id, &manifest.wasm.entrypoint, &bytes)?; Ok(bytes) } diff --git a/pkg/beam-cli/src/apps/runtime.rs b/pkg/beam-cli/src/apps/runtime.rs index 8bd9aec..8a175e6 100644 --- a/pkg/beam-cli/src/apps/runtime.rs +++ b/pkg/beam-cli/src/apps/runtime.rs @@ -28,12 +28,20 @@ const WASM_FUEL: u64 = 30_000_000; pub fn validate_wasm_module(app_id: &str, entrypoint: &str, path: &Path) -> Result<()> { let bytes = std::fs::read(path).context("read beam app wasm module")?; + validate_wasm_module_bytes(app_id, entrypoint, &bytes) +} + +pub(super) fn validate_wasm_module_bytes( + app_id: &str, + entrypoint: &str, + bytes: &[u8], +) -> Result<()> { if bytes.len() < 8 || &bytes[..4] != WASM_MAGIC { return Err(Error::InvalidWasmModule { app: app_id.to_string(), }); } - AppRuntime::default().instantiate_for_validation(app_id, entrypoint, &bytes)?; + AppRuntime::default().instantiate_for_validation(app_id, entrypoint, bytes)?; Ok(()) } @@ -70,12 +78,15 @@ impl AppRuntime { let instance = linker .instantiate_and_start(&mut store, &module) .context("instantiate beam app wasm module")?; - if instance.get_func(&store, entrypoint).is_none() { + if instance.get_memory(&store, "memory").is_none() { return Err(Error::MissingWasmExport { app: app_id.to_string(), - export: entrypoint.to_string(), + export: "memory".to_string(), }); } + typed_func::(&store, &instance, "beam_alloc", app_id)?; + typed_func::<(i32, i32), ()>(&store, &instance, "beam_free", app_id)?; + typed_func::<(i32, i32), i64>(&store, &instance, entrypoint, app_id)?; Ok(()) } diff --git a/pkg/beam-cli/src/cli/apps.rs b/pkg/beam-cli/src/cli/apps.rs index 6092faf..2f659da 100644 --- a/pkg/beam-cli/src/cli/apps.rs +++ b/pkg/beam-cli/src/cli/apps.rs @@ -1,5 +1,7 @@ use clap::{Args, Subcommand}; +pub(crate) const APP_HELP_ARG: &str = "__beam_app_help"; + #[derive(Debug, Subcommand)] pub enum AppsAction { /// Install an app from the Beam registry diff --git a/pkg/beam-cli/src/cli/normalize.rs b/pkg/beam-cli/src/cli/normalize.rs index 8e39b5d..8cfff3f 100644 --- a/pkg/beam-cli/src/cli/normalize.rs +++ b/pkg/beam-cli/src/cli/normalize.rs @@ -1,5 +1,7 @@ use std::ffi::OsString; +use super::apps::APP_HELP_ARG; + pub(crate) fn normalize_cli_args(args: I) -> Vec where I: IntoIterator, @@ -63,7 +65,95 @@ where normalized.push(arg); } - normalized + rewrite_installed_app_help_args(normalized) +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum AppRunParseState { + Root, + XAwaitApp, + XAfterApp, + AppsAwaitAction, + AppsRunAwaitApp, + AppsRunAfterApp, + OtherCommand, +} + +fn rewrite_installed_app_help_args(args: Vec) -> Vec { + let mut rewritten = Vec::with_capacity(args.len()); + let mut state = AppRunParseState::Root; + let mut consume_flag_value = false; + + for (index, arg) in args.into_iter().enumerate() { + if index == 0 { + rewritten.push(arg); + continue; + } + + let Some(value) = arg.to_str().map(ToString::to_string) else { + rewritten.push(arg); + continue; + }; + + if consume_flag_value { + rewritten.push(arg); + consume_flag_value = false; + continue; + } + + if expects_global_flag_value(&value) { + rewritten.push(arg); + consume_flag_value = !value.contains('='); + continue; + } + + let replacement = match state { + AppRunParseState::Root => { + state = match value.as_str() { + "x" => AppRunParseState::XAwaitApp, + "apps" => AppRunParseState::AppsAwaitAction, + _ if is_command_token(&value) => AppRunParseState::OtherCommand, + _ => AppRunParseState::Root, + }; + None + } + AppRunParseState::XAwaitApp => { + if !is_flag(&value) { + state = AppRunParseState::XAfterApp; + } + None + } + AppRunParseState::XAfterApp => rewrite_help_flag(&value), + AppRunParseState::AppsAwaitAction => { + state = if value == "run" { + AppRunParseState::AppsRunAwaitApp + } else { + AppRunParseState::OtherCommand + }; + None + } + AppRunParseState::AppsRunAwaitApp => { + if !is_flag(&value) { + state = AppRunParseState::AppsRunAfterApp; + } + None + } + AppRunParseState::AppsRunAfterApp => rewrite_help_flag(&value), + AppRunParseState::OtherCommand => None, + }; + + rewritten.push(replacement.map_or(arg, OsString::from)); + } + + rewritten +} + +fn is_flag(value: &str) -> bool { + value.starts_with('-') +} + +fn rewrite_help_flag(value: &str) -> Option<&'static str> { + matches!(value, "--help" | "-h").then_some(APP_HELP_ARG) } fn rewrite_output_flag(value: &str, is_fetch_command: bool) -> Option { diff --git a/pkg/beam-cli/src/commands/apps/mod.rs b/pkg/beam-cli/src/commands/apps/mod.rs index 60a2ddf..a801603 100644 --- a/pkg/beam-cli/src/commands/apps/mod.rs +++ b/pkg/beam-cli/src/commands/apps/mod.rs @@ -20,8 +20,9 @@ use crate::{ }, runtime::{AppRuntime, GuestCommandResult, validate_wasm_module}, store::AppCache, + validate::ensure_beam_version, }, - cli::{AppApprovalAction, AppInstallArgs, AppRemoveArgs, AppRunArgs, AppsAction}, + cli::{APP_HELP_ARG, AppApprovalAction, AppInstallArgs, AppRemoveArgs, AppRunArgs, AppsAction}, error::Result, output::CommandOutput, runtime::BeamApp, @@ -56,14 +57,9 @@ pub async fn run_app(app: &BeamApp, args: AppRunArgs) -> Result<()> { let command_args = filtered_app_args(&args.args); let cache = AppCache::load(&app.paths.root).await?; let (installed, manifest) = cache.active_manifest(&args.app).await?; + ensure_beam_version(&manifest.id, &manifest.min_beam_version)?; fs::create_dir_all(cache.data_dir(&args.app)).context("create beam app data directory")?; - validate_wasm_module( - &args.app, - &manifest.wasm.entrypoint, - &cache.module_path(&args.app, &installed.active_version), - )?; - let command = command_args .first() .cloned() @@ -87,6 +83,12 @@ pub async fn run_app(app: &BeamApp, args: AppRunArgs) -> Result<()> { .print(app.output_mode); } + validate_wasm_module( + &args.app, + &manifest.wasm.entrypoint, + &cache.module_path(&args.app, &installed.active_version), + )?; + let runtime = AppRuntime::default(); let result = runtime .run_command( @@ -129,7 +131,13 @@ fn plan_requires_approval(plan: &ActionPlan) -> bool { fn filtered_app_args(args: &[String]) -> Vec { args.iter() .filter(|arg| arg.as_str() != "--prepare" && arg.as_str() != "--no-prompt") - .cloned() + .map(|arg| { + if arg == APP_HELP_ARG { + "--help".to_string() + } else { + arg.clone() + } + }) .collect() } diff --git a/pkg/beam-cli/src/commands/interactive.rs b/pkg/beam-cli/src/commands/interactive.rs index 869eaf2..14f6f36 100644 --- a/pkg/beam-cli/src/commands/interactive.rs +++ b/pkg/beam-cli/src/commands/interactive.rs @@ -263,14 +263,12 @@ pub(crate) async fn prompt(app: &BeamApp) -> Result { (None, Some(address)) => shrink(&format!("{address:#x}")), (None, None) => "no-wallet".to_string(), }; - let rpc_url = shrink(&chain.rpc_url); Ok(ReplPrompt { - plain: render_shell_prefix(&wallet_display, &chain.entry.key, &rpc_url), - colored: app - .color_mode - .colors_stdout() - .then(|| render_colored_shell_prefix(&wallet_display, &chain.entry.key, &rpc_url)), + plain: render_shell_prefix(&wallet_display, &chain.entry.key, &chain.rpc_url), + colored: app.color_mode.colors_stdout().then(|| { + render_colored_shell_prefix(&wallet_display, &chain.entry.key, &chain.rpc_url) + }), }) } diff --git a/pkg/beam-cli/src/display.rs b/pkg/beam-cli/src/display.rs index 0a37314..9912c68 100644 --- a/pkg/beam-cli/src/display.rs +++ b/pkg/beam-cli/src/display.rs @@ -32,6 +32,14 @@ pub fn shrink(value: &str) -> String { format!("{}...{}", &value[..prefix_end], &value[suffix_start..]) } +pub fn shrink_rpc_url(value: &str) -> String { + let value = value + .strip_prefix("https://") + .or_else(|| value.strip_prefix("http://")) + .unwrap_or(value); + shrink(value) +} + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, ValueEnum)] pub enum ColorMode { #[default] @@ -84,7 +92,7 @@ pub(crate) fn notice_message(message: &str, color_enabled: bool) -> String { pub(crate) fn render_shell_prefix(wallet_display: &str, chain: &str, rpc_url: &str) -> String { let wallet_display = sanitize_control_chars(wallet_display); let chain = sanitize_control_chars(chain); - let rpc_url = sanitize_control_chars(rpc_url); + let rpc_url = sanitize_control_chars(&shrink_rpc_url(rpc_url)); format!("[{wallet_display} | {chain} | {rpc_url}] ") } @@ -95,7 +103,7 @@ pub(crate) fn render_colored_shell_prefix( ) -> String { let wallet_display = sanitize_control_chars(wallet_display); let chain = sanitize_control_chars(chain); - let rpc_url = sanitize_control_chars(rpc_url); + let rpc_url = sanitize_control_chars(&shrink_rpc_url(rpc_url)); format!( "{}{}{}{}{}{}{} ", colorize_prompt("[", Style::PromptFrame), diff --git a/pkg/beam-cli/src/tests.rs b/pkg/beam-cli/src/tests.rs index 42d0fb0..bcbc071 100644 --- a/pkg/beam-cli/src/tests.rs +++ b/pkg/beam-cli/src/tests.rs @@ -1,6 +1,7 @@ mod abi; mod apps; mod apps_host; +mod apps_runtime; mod balance; mod call; mod chains; diff --git a/pkg/beam-cli/src/tests/apps.rs b/pkg/beam-cli/src/tests/apps.rs index 4bb3f6d..647a3c7 100644 --- a/pkg/beam-cli/src/tests/apps.rs +++ b/pkg/beam-cli/src/tests/apps.rs @@ -12,7 +12,7 @@ use crate::{ registry::{DEFAULT_REGISTRY_URL, ensure_digest, signing_digest}, validate::{ensure_beam_version, validate_index, validate_manifest}, }, - cli::{AppsAction, Cli, Command}, + cli::{APP_HELP_ARG, AppsAction, Cli, Command, normalize_cli_args}, }; use clap::Parser; @@ -108,6 +108,42 @@ fn parses_x_alias_with_trailing_args() { } } +#[test] +fn preserves_clap_help_for_x_without_app_id() { + let error = + Cli::try_parse_from(normalize_cli_args(["beam", "x", "--help"])).expect_err("show help"); + + assert_eq!(error.kind(), clap::error::ErrorKind::DisplayHelp); +} + +#[test] +fn forwards_x_help_after_app_id_to_installed_app() { + let cli = Cli::try_parse_from(normalize_cli_args(["beam", "x", "uniswap", "--help"])) + .expect("parse app help"); + + match cli.command { + Some(Command::X(args)) + if args.app == "uniswap" && args.args == [APP_HELP_ARG.to_string()] => {} + other => panic!("unexpected command: {other:?}"), + } +} + +#[test] +fn forwards_apps_run_command_help_to_installed_app() { + let cli = Cli::try_parse_from(normalize_cli_args([ + "beam", "apps", "run", "uniswap", "swap", "--help", + ])) + .expect("parse app command help"); + + match cli.command { + Some(Command::Apps { + action: AppsAction::Run(args), + }) if args.app == "uniswap" + && args.args == ["swap".to_string(), APP_HELP_ARG.to_string()] => {} + other => panic!("unexpected command: {other:?}"), + } +} + #[test] fn privacy_capabilities_parse_and_fail_closed() { let mut manifest = manifest(); diff --git a/pkg/beam-cli/src/tests/apps_host.rs b/pkg/beam-cli/src/tests/apps_host.rs index 6b790cf..7f1cb60 100644 --- a/pkg/beam-cli/src/tests/apps_host.rs +++ b/pkg/beam-cli/src/tests/apps_host.rs @@ -1,7 +1,3 @@ -// lint-long-file-override allow-max-lines=300 -use std::path::{Path, PathBuf}; - -use super::fixtures::test_app; use crate::apps::{ approvals::{ensure_approval_executable, plan_hash}, host::{ @@ -10,12 +6,10 @@ use crate::apps::{ }, model::{ ActionBinding, ActionPlan, AppPermissions, ApprovalRecord, ApprovalStatus, ChainOperation, - ChainPermission, HttpPermission, InstalledApp, RegistryIndex, + ChainPermission, HttpPermission, }, - runtime::{AppRuntime, validate_wasm_module}, store::now, }; -use crate::runtime::InvocationOverrides; #[test] fn host_http_permissions_allow_declared_https_and_reject_private_hosts() { @@ -124,51 +118,6 @@ fn host_transaction_permissions_allow_broad_optional_globs() { .expect("omitted optional scopes are broad wildcards"); } -#[test] -fn app_runtime_requires_declared_entrypoint() { - let path = repo_root().join("beam-apps/fixtures/valid/apps/uniswap/1.0.0/module.wasm"); - - validate_wasm_module("uniswap", "beam_app_main", &path).expect("valid app wasm"); - validate_wasm_module("uniswap", "missing_entrypoint", &path) - .expect_err("reject missing entrypoint"); -} - -#[tokio::test] -async fn app_runtime_invokes_guest_and_returns_structured_errors() { - let (_temp_dir, app) = test_app(InvocationOverrides { - chain: Some("base".to_string()), - from: Some("0x1111111111111111111111111111111111111111".to_string()), - ..InvocationOverrides::default() - }) - .await; - let bundle = repo_root().join("beam-apps/fixtures/valid"); - let index = read_json::(&bundle.join("index.json")); - let version = &index.apps[0].versions[0]; - let manifest_path = artifact_path(&bundle, &version.manifest_url); - let module_path = artifact_path(&bundle, &version.module_url); - let manifest = read_json(&manifest_path); - let installed = InstalledApp { - active_version: version.version.clone(), - id: index.apps[0].id.clone(), - installed_at: now(), - manifest_sha256: version.manifest_sha256.clone(), - module_sha256: version.module_sha256.clone(), - }; - - let error = AppRuntime::default() - .run_command( - &app, - &manifest, - &installed, - &module_path, - &["unknown".to_string()], - ) - .await - .expect_err("guest should reject unknown command"); - - assert!(error.to_string().contains("unsupported command")); -} - #[test] fn approval_integrity_rejects_tampered_plan() { let mut plan = action_plan(); @@ -231,16 +180,3 @@ fn action_plan() -> ActionPlan { expires_at: now() + 60, } } - -fn repo_root() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")).join("../..") -} - -fn read_json(path: &Path) -> T { - serde_json::from_slice(&std::fs::read(path).expect("read json")).expect("decode json") -} - -fn artifact_path(bundle: &Path, url: &str) -> PathBuf { - let prefix = "https://registry.beam.payy.network/"; - bundle.join(url.strip_prefix(prefix).expect("registry url")) -} diff --git a/pkg/beam-cli/src/tests/apps_runtime.rs b/pkg/beam-cli/src/tests/apps_runtime.rs new file mode 100644 index 0000000..c962db1 --- /dev/null +++ b/pkg/beam-cli/src/tests/apps_runtime.rs @@ -0,0 +1,182 @@ +use std::path::{Path, PathBuf}; + +use super::fixtures::{test_app, test_app_with_output}; +use crate::{ + apps::{ + Error, + model::{AppManifest, InstalledApp, RegistryIndex}, + runtime::{AppRuntime, validate_wasm_module}, + store::{AppCache, now}, + }, + cli::AppRunArgs, + commands::apps::run_app, + output::OutputMode, + runtime::InvocationOverrides, +}; + +const WASM_WITHOUT_COMMAND_ALLOC: &[u8] = b"\0asm\x01\0\0\0\ +\x01\x04\x01\x60\0\0\ +\x03\x02\x01\0\ +\x05\x03\x01\0\x01\ +\x07\x1a\x02\ +\x06memory\x02\0\ +\x0dbeam_app_main\0\0\ +\x0a\x04\x01\x02\0\x0b"; + +#[test] +fn app_runtime_requires_declared_entrypoint() { + let bundle = repo_root().join("beam-apps/fixtures/valid"); + let index = read_json::(&bundle.join("index.json")); + let version = &index.apps[0].versions[0]; + let path = artifact_path(&bundle, &version.module_url); + + validate_wasm_module("uniswap", "beam_app_main", &path).expect("valid app wasm"); + validate_wasm_module("uniswap", "missing_entrypoint", &path) + .expect_err("reject missing entrypoint"); +} + +#[test] +fn app_runtime_rejects_missing_command_alloc_export() { + let module = tempfile::NamedTempFile::new().expect("create module file"); + std::fs::write(module.path(), WASM_WITHOUT_COMMAND_ALLOC).expect("write module"); + + let error = validate_wasm_module("uniswap", "beam_app_main", module.path()) + .expect_err("reject missing command allocator"); + + assert!(matches!( + error, + Error::MissingWasmExport { export, .. } if export == "beam_alloc" + )); +} + +#[tokio::test] +async fn app_command_help_skips_stale_wasm_validation() { + let (_temp_dir, app) = + test_app_with_output(OutputMode::Quiet, InvocationOverrides::default()).await; + let bundle = repo_root().join("beam-apps/fixtures/valid"); + let index = read_json::(&bundle.join("index.json")); + let version = &index.apps[0].versions[0]; + let manifest_path = artifact_path(&bundle, &version.manifest_url); + let manifest_bytes = std::fs::read(&manifest_path).expect("read manifest"); + let manifest = read_json::(&manifest_path); + let cache = AppCache::load(&app.paths.root) + .await + .expect("load app cache"); + cache + .install( + &manifest, + &manifest_bytes, + WASM_WITHOUT_COMMAND_ALLOC, + &version.manifest_sha256, + "sha256:stale", + "https://registry.beam.payy.network", + ) + .await + .expect("install stale app module"); + + run_app( + &app, + AppRunArgs { + app: "uniswap".to_string(), + prepare: false, + no_prompt: false, + args: vec!["swap".to_string(), "--help".to_string()], + }, + ) + .await + .expect("render command help from manifest"); +} + +#[tokio::test] +async fn app_run_checks_installed_manifest_minimum_version_before_wasm() { + let (_temp_dir, app) = + test_app_with_output(OutputMode::Quiet, InvocationOverrides::default()).await; + let bundle = repo_root().join("beam-apps/fixtures/valid"); + let index = read_json::(&bundle.join("index.json")); + let version = &index.apps[0].versions[0]; + let manifest_path = artifact_path(&bundle, &version.manifest_url); + let mut manifest = read_json::(&manifest_path); + manifest.min_beam_version = "999.0.0".to_string(); + let manifest_bytes = serde_json::to_vec_pretty(&manifest).expect("encode manifest"); + let cache = AppCache::load(&app.paths.root) + .await + .expect("load app cache"); + cache + .install( + &manifest, + &manifest_bytes, + WASM_WITHOUT_COMMAND_ALLOC, + &version.manifest_sha256, + "sha256:stale", + "https://registry.beam.payy.network", + ) + .await + .expect("install unsupported app module"); + + let error = run_app( + &app, + AppRunArgs { + app: "uniswap".to_string(), + prepare: false, + no_prompt: false, + args: vec!["unknown".to_string()], + }, + ) + .await + .expect_err("reject unsupported app before wasm validation"); + + assert!(matches!( + error, + crate::error::Error::App(Error::UnsupportedBeamVersion { required, .. }) + if required == "999.0.0" + )); +} + +#[tokio::test] +async fn app_runtime_invokes_guest_and_returns_structured_errors() { + let (_temp_dir, app) = test_app(InvocationOverrides { + chain: Some("base".to_string()), + from: Some("0x1111111111111111111111111111111111111111".to_string()), + ..InvocationOverrides::default() + }) + .await; + let bundle = repo_root().join("beam-apps/fixtures/valid"); + let index = read_json::(&bundle.join("index.json")); + let version = &index.apps[0].versions[0]; + let manifest_path = artifact_path(&bundle, &version.manifest_url); + let module_path = artifact_path(&bundle, &version.module_url); + let manifest = read_json(&manifest_path); + let installed = InstalledApp { + active_version: version.version.clone(), + id: index.apps[0].id.clone(), + installed_at: now(), + manifest_sha256: version.manifest_sha256.clone(), + module_sha256: version.module_sha256.clone(), + }; + + let error = AppRuntime::default() + .run_command( + &app, + &manifest, + &installed, + &module_path, + &["unknown".to_string()], + ) + .await + .expect_err("guest should reject unknown command"); + + assert!(error.to_string().contains("unsupported command")); +} + +fn repo_root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("../..") +} + +fn read_json(path: &Path) -> T { + serde_json::from_slice(&std::fs::read(path).expect("read json")).expect("decode json") +} + +fn artifact_path(bundle: &Path, url: &str) -> PathBuf { + let prefix = "https://registry.beam.payy.network/"; + bundle.join(url.strip_prefix(prefix).expect("registry url")) +} diff --git a/pkg/beam-cli/src/tests/display.rs b/pkg/beam-cli/src/tests/display.rs index 1dd7f30..d2f792e 100644 --- a/pkg/beam-cli/src/tests/display.rs +++ b/pkg/beam-cli/src/tests/display.rs @@ -1,6 +1,6 @@ use crate::display::{ ColorMode, error_message, render_colored_shell_prefix, render_shell_prefix, should_color, - shrink, warning_message, + shrink, shrink_rpc_url, warning_message, }; #[test] @@ -23,7 +23,7 @@ fn shell_prefix_stays_plain_when_color_is_disabled() { assert_eq!( prefix, - "[wallet-1 0x740747e7...e3a1e112 | ethereum | https://et...node.com] " + "[wallet-1 0x740747e7...e3a1e112 | ethereum | et...node.com] " ); } @@ -43,7 +43,7 @@ fn shell_prefix_uses_brand_colors_for_known_chains() { assert!(prefix.contains("\x1b[1;36mwallet-1 0x740747e7...e3a1e112\x1b[0m")); assert!(prefix.contains(expected_fragment)); - assert!(prefix.contains("\x1b[1;34mhttps://et...node.com\x1b[0m")); + assert!(prefix.contains("\x1b[1;34met...node.com\x1b[0m")); assert!(!prefix.contains('\x01')); assert!(!prefix.contains('\x02')); assert!(prefix.ends_with(' ')); @@ -64,13 +64,13 @@ fn shell_prefix_falls_back_to_the_default_prompt_chain_color_for_unknown_network #[test] fn shell_prefix_sanitizes_control_characters_in_dynamic_segments() { let plain = render_shell_prefix("ali\nce \x1b[31m", "beam-\x1b[32m", "https://rpc/\x1b[0m"); - assert_eq!(plain, "[ali ce ?[31m | beam-?[32m | https://rpc/?[0m] "); + assert_eq!(plain, "[ali ce ?[31m | beam-?[32m | rpc/?[0m] "); let colored = render_colored_shell_prefix("ali\nce \x1b[31m", "beam-\x1b[32m", "https://rpc/\x1b[0m"); assert!(colored.contains("ali ce ?[31m")); assert!(colored.contains("beam-?[32m")); - assert!(colored.contains("https://rpc/?[0m")); + assert!(colored.contains("rpc/?[0m")); } #[test] @@ -80,6 +80,15 @@ fn shrink_truncates_utf8_values_on_character_boundaries() { assert_eq!(shrink(url), "https://例え...éééééééé"); } +#[test] +fn shrink_rpc_url_strips_scheme_before_truncating() { + assert_eq!( + shrink_rpc_url("https://eth-mainnet.g.alchemy.com/v2/PqX1meQy"), + "eth-mainne...PqX1meQy" + ); + assert_eq!(shrink_rpc_url("http://localhost:8545"), "localhost:8545"); +} + #[test] fn label_messages_only_colorize_the_prefix() { assert_eq!(