Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ts-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name: TypeScript CI
on:
pull_request:
branches:
- develop
- "**"
push:
branches:
- develop
- "**"
workflow_dispatch:

permissions:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ts-standalone-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: TypeScript Standalone Artifacts
on:
push:
branches:
- develop
- master
workflow_dispatch:

permissions:
Expand Down
4 changes: 2 additions & 2 deletions ts/docs/commands/account/activate.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Requires the payer account and the master password via `--password-stdin`; watch
| `--dry-run` | Build and estimate only; no signature/broadcast, no password. Excludes `--sign-only` / `--build-only` |
| `--sign-only` | Build and sign, output the signed hex (feed [`tx broadcast`](../tx/broadcast.md)). Excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex (feed [`tx multisig --create`](../tx/multisig.md)). Excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only` |
| `--permission-id <n>` | Permission group to sign with (default `0`) |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
4 changes: 2 additions & 2 deletions ts/docs/commands/account/set.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Requires the account and the master password via `--password-stdin`; watch-only
| `--dry-run` | Build and estimate only; no signature/broadcast, no password. Excludes `--sign-only` / `--build-only` |
| `--sign-only` | Build and sign, output the signed hex (feed [`tx broadcast`](../tx/broadcast.md)). Excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex (feed [`tx multisig --create`](../tx/multisig.md)). Excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only` |
| `--permission-id <n>` | Permission group to sign with (default `0`) |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/contract/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Requires an account. The master password (via `--password-stdin`) is needed only
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/contract/send.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Requires an account. The master password (via `--password-stdin`) is needed only
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
4 changes: 2 additions & 2 deletions ts/docs/commands/permission/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ Changing only `keys`, `threshold` or `name` needs no such deletion.
| `--dry-run` | Mock receipt — fee, resulting-structure card, and warnings — matching a real submission; no signature, no broadcast, no password. Excludes `--sign-only` / `--build-only` |
| `--sign-only` | Build and sign, output the signed hex without broadcasting (feed [`tx broadcast`](../tx/broadcast.md) for on-chain co-signing). Excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex (feed [`tx multisig --create`](../tx/multisig.md) for service-relayed multi-sig). Excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only` |
| `--permission-id <n>` | Permission group to sign with — changing permissions is owner-level, so normally `0` (default `0`) |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); changing permissions normally uses `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/reward/withdraw.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Moves your accumulated voting rewards (plus block rewards if you are an SR) into
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/stake/cancel-unfreeze.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Cancels **every** unstake still in its waiting period and rolls those amounts ba
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/stake/delegate.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Check how much you can still delegate with [`stake delegated`](delegated.md) (`M
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/stake/freeze.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Amount is in SUN (1 TRX = 1,000,000 SUN). Staked TRX stays yours; to get it back
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/stake/undelegate.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Reclaiming is immediate (no waiting period — the TRX was staked all along, onl
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/stake/unfreeze.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Stake 2.0 allows at most **32 pending unstakes** per account at a time; check re
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/stake/withdraw.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Withdrawing also frees up unstake slots (max 32 pending unstakes per account).
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin |

Expand Down
4 changes: 2 additions & 2 deletions ts/docs/commands/tx/send.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ Requires an account and the master password via `--password-stdin` — signing c
| `--dry-run` | Build and estimate only; excludes `--sign-only` / `--build-only` |
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default 60000; on cap returns the submitted receipt) |
| `--password-stdin` | Master password from stdin |

Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/vote/cast.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Votes take effect at the next maintenance cycle (~6 h). Each vote uses 1 TP (it
| `--sign-only` | Sign without broadcasting, output the signed hex; excludes `--dry-run` / `--build-only`; pairs with `--expiration` |
| `--build-only` | Build only, output the **unsigned** hex; excludes `--dry-run` / `--sign-only`; pairs with `--expiration` |
| `--expiration <ms>` | Transaction expiration in ms, up to `86400000` (24h); only with `--sign-only` or `--build-only`; omitted = node default (~60s) |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 29=active); default `0` |
| `--permission-id <n>` | Permission group to sign with (0=owner, 1=witness, 2-9=active); default `0` |
| `--wait` / `--wait-timeout <ms>` | Poll after broadcast until confirmed/failed (cap default: config `waitTimeoutMs`, built-in 60000) |
| `--password-stdin` | Master password from stdin (fd 0) |

Expand Down
4 changes: 4 additions & 0 deletions ts/src/adapters/inbound/cli/input/prompt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ export class TtyBackend implements PromptBackend {
#pendingKey?: (key: KeyEvent) => void;
#keyListener?: (s: string, key: KeyEvent) => void;
constructor() {
if (process.env.WALLET_CLI_NO_TTY === "1") {
this.#tty = false;
return;
}
// Probe for a controlling terminal without holding the fd; the real stream opens on first prompt.
try {
closeSync(openSync("/dev/tty", "r"));
Expand Down
15 changes: 14 additions & 1 deletion ts/src/adapters/inbound/cli/input/prompt/prompter.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { Prompter, type PromptBackend, type KeyEvent } from "./index.js";
import { createPrompter, Prompter, type PromptBackend, type KeyEvent } from "./index.js";

class FakeBackend implements PromptBackend {
out = "";
Expand All @@ -25,6 +25,19 @@ describe("Prompter.setInteractive", () => {
});
});

describe("createPrompter", () => {
it("can force non-interactive mode for subprocess tests", () => {
const previous = process.env.WALLET_CLI_NO_TTY;
process.env.WALLET_CLI_NO_TTY = "1";
try {
expect(createPrompter().isTTY()).toBe(false);
} finally {
if (previous === undefined) delete process.env.WALLET_CLI_NO_TTY;
else process.env.WALLET_CLI_NO_TTY = previous;
}
});
});

describe("Prompter.text", () => {
it("re-prompts until validate passes", async () => {
const be = new FakeBackend(["", " ", "ok"]);
Expand Down
15 changes: 14 additions & 1 deletion ts/src/adapters/inbound/cli/shell/positional-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { tmpdir } from "node:os";
import { buildCli, type ShellOptions } from "./index.js";
import { isChainCommand, type SessionRef } from "../contracts/index.js";
import { composeCliRuntime } from "../../../../bootstrap/composition.js";
import { Prompter } from "../input/prompt/index.js";
import { SecretResolver } from "../input/secret/index.js";

/**
* The other shell tests drive synthetic command definitions, which proves the mechanism but not
Expand All @@ -31,11 +33,22 @@ describe("every registered positional command rejects its --<field> spelling", (
// fresh per invocation: StreamManager permits one result emission, so a runtime cannot be shared
// across commands that actually run.
function newRuntime() {
return composeCliRuntime({
const runtime = composeCliRuntime({
globals: { output: "json", verbose: false },
secretPaths: {},
startedAt: Date.now(),
});
const prompter = new Prompter({
isTTY: () => false,
async question() { return ""; },
async readKey() { return { name: "return" }; },
write() {},
beginRaw() {},
endRaw() {},
});
runtime.deps.prompter = prompter;
runtime.deps.secrets = new SecretResolver(runtime.streams, {}, prompter);
return runtime;
}

function shellOpts(): ShellOptions {
Expand Down
2 changes: 1 addition & 1 deletion ts/src/adapters/outbound/ledger/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { closeSpy, tip712Calls, failures } = vi.hoisted(() => ({
tip712Calls: [] as Array<{ path: string; domainHash: string; messageHash: string }>,
failures: { tip712: undefined as Error | undefined, tip712Hang: false },
}));
vi.mock("@ledgerhq/hw-transport-node-hid", () => ({
vi.mock("@ledgerhq/hw-transport-node-hid-noevents", () => ({
default: { open: async () => ({ close: closeSpy }) },
}));
// Every device APDU never resolves — models an on-device prompt that is never tapped.
Expand Down
2 changes: 1 addition & 1 deletion ts/src/adapters/outbound/ledger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ async function openTransport(): Promise<{ transport: unknown; close: () => Promi
});
return { transport, close: () => transport.close() };
}
const Hid = unwrap<any>(await import("@ledgerhq/hw-transport-node-hid"));
const Hid = unwrap<any>(await import("@ledgerhq/hw-transport-node-hid-noevents"));
const transport = await Hid.open("");
return { transport, close: () => transport.close() };
}
Expand Down
8 changes: 4 additions & 4 deletions ts/test/contract-deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { AtomicFileStore } from "../src/adapters/outbound/persistence/fs/index.j
// RUN_LIVE_BROADCAST=1 → actually deploy + confirm on Nile (spends testnet TRX)

const HERE = dirname(fileURLToPath(import.meta.url));
const TSX = join(process.cwd(), "node_modules", ".bin", "tsx");
const NODE = process.execPath;
const ENTRY = join(process.cwd(), "src", "index.ts");
const PW = "testpw123A";

Expand Down Expand Up @@ -62,11 +62,11 @@ function deploy(
];
if (opts.dryRun) local.push("--dry-run");
local.push("--password-stdin");
const r = spawnSync(TSX, [ENTRY, ...globals, ...local], {
const r = spawnSync(NODE, ["--import", "tsx", ENTRY, ...globals, ...local], {
input: PW + "\n",
encoding: "utf8",
env: { ...process.env, WALLET_CLI_HOME: HOME, NO_COLOR: "1" },
timeout: opts.timeoutMs ?? 30_000,
env: { ...process.env, WALLET_CLI_HOME: HOME, NO_COLOR: "1", WALLET_CLI_NO_TTY: "1" },
timeout: opts.timeoutMs ?? 18_000,
});
return JSON.parse(r.stdout);
}
Expand Down
Loading