@wlfi-agent/cli 1.4.17 → 1.4.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +5 -0
- package/README.md +61 -28
- package/crates/vault-cli-admin/src/io_utils.rs +149 -1
- package/crates/vault-cli-admin/src/main.rs +639 -16
- package/crates/vault-cli-admin/src/shared_config.rs +18 -18
- package/crates/vault-cli-admin/src/tui/token_rpc.rs +190 -3
- package/crates/vault-cli-admin/src/tui/utils.rs +59 -0
- package/crates/vault-cli-admin/src/tui.rs +1205 -120
- package/crates/vault-cli-agent/Cargo.toml +1 -0
- package/crates/vault-cli-agent/src/io_utils.rs +163 -2
- package/crates/vault-cli-agent/src/main.rs +648 -32
- package/crates/vault-cli-daemon/Cargo.toml +4 -0
- package/crates/vault-cli-daemon/src/main.rs +617 -67
- package/crates/vault-cli-daemon/src/relay_sync.rs +776 -4
- package/crates/vault-cli-daemon/tests/system_keychain_helper_acl.rs +5 -0
- package/crates/vault-daemon/src/daemon_parts/api_impl_and_utils.rs +32 -1
- package/crates/vault-daemon/src/persistence.rs +637 -100
- package/crates/vault-daemon/src/tests.rs +1013 -3
- package/crates/vault-daemon/src/tests_parts/part2.rs +99 -0
- package/crates/vault-daemon/src/tests_parts/part4.rs +11 -7
- package/crates/vault-domain/src/nonce.rs +4 -0
- package/crates/vault-domain/src/tests.rs +616 -0
- package/crates/vault-policy/src/engine.rs +55 -32
- package/crates/vault-policy/src/tests.rs +195 -0
- package/crates/vault-sdk-agent/src/lib.rs +415 -22
- package/crates/vault-signer/Cargo.toml +3 -0
- package/crates/vault-signer/src/lib.rs +266 -40
- package/crates/vault-transport-unix/src/lib.rs +653 -5
- package/crates/vault-transport-xpc/src/tests.rs +531 -3
- package/crates/vault-transport-xpc/tests/e2e_flow.rs +3 -0
- package/dist/cli.cjs +756 -194
- package/dist/cli.cjs.map +1 -1
- package/package.json +5 -2
- package/packages/cache/.turbo/turbo-build.log +20 -20
- package/packages/cache/coverage/clover.xml +529 -394
- package/packages/cache/coverage/coverage-final.json +2 -2
- package/packages/cache/coverage/index.html +21 -21
- package/packages/cache/coverage/src/client/index.html +1 -1
- package/packages/cache/coverage/src/client/index.ts.html +1 -1
- package/packages/cache/coverage/src/errors/index.html +1 -1
- package/packages/cache/coverage/src/errors/index.ts.html +12 -12
- package/packages/cache/coverage/src/index.html +1 -1
- package/packages/cache/coverage/src/index.ts.html +1 -1
- package/packages/cache/coverage/src/service/index.html +21 -21
- package/packages/cache/coverage/src/service/index.ts.html +769 -313
- package/packages/cache/dist/{chunk-QNK6GOTI.js → chunk-KC53LH5Z.js} +35 -2
- package/packages/cache/dist/chunk-KC53LH5Z.js.map +1 -0
- package/packages/cache/dist/{chunk-QF4XKEIA.cjs → chunk-UVU7VFE3.cjs} +35 -2
- package/packages/cache/dist/chunk-UVU7VFE3.cjs.map +1 -0
- package/packages/cache/dist/index.cjs +2 -2
- package/packages/cache/dist/index.js +1 -1
- package/packages/cache/dist/service/index.cjs +2 -2
- package/packages/cache/dist/service/index.js +1 -1
- package/packages/cache/node_modules/.bin/tsc +2 -2
- package/packages/cache/node_modules/.bin/tsserver +2 -2
- package/packages/cache/node_modules/.bin/tsup +2 -2
- package/packages/cache/node_modules/.bin/tsup-node +2 -2
- package/packages/cache/node_modules/.bin/vitest +4 -4
- package/packages/cache/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/cache/src/service/index.test.ts +165 -19
- package/packages/cache/src/service/index.ts +38 -1
- package/packages/config/.turbo/turbo-build.log +4 -4
- package/packages/config/dist/index.cjs +0 -17
- package/packages/config/dist/index.cjs.map +1 -1
- package/packages/config/src/index.ts +0 -17
- package/packages/rpc/.turbo/turbo-build.log +11 -11
- package/packages/rpc/dist/index.cjs +0 -17
- package/packages/rpc/dist/index.cjs.map +1 -1
- package/packages/rpc/src/index.js +1 -0
- package/packages/ui/node_modules/.bin/tsc +2 -2
- package/packages/ui/node_modules/.bin/tsserver +2 -2
- package/packages/ui/node_modules/.bin/tsup +2 -2
- package/packages/ui/node_modules/.bin/tsup-node +2 -2
- package/scripts/install-cli-launcher.mjs +37 -0
- package/scripts/install-rust-binaries.mjs +47 -0
- package/scripts/run-tests-isolated.mjs +210 -0
- package/src/cli.ts +310 -50
- package/src/lib/admin-reset.ts +101 -33
- package/src/lib/admin-setup.ts +285 -55
- package/src/lib/agent-auth-migrate.ts +5 -1
- package/src/lib/asset-broadcast.ts +15 -4
- package/src/lib/config-amounts.ts +6 -4
- package/src/lib/hidden-tty-prompt.js +1 -0
- package/src/lib/hidden-tty-prompt.ts +105 -0
- package/src/lib/keychain.ts +1 -0
- package/src/lib/local-admin-access.ts +4 -29
- package/src/lib/rust.ts +129 -33
- package/src/lib/signed-tx.ts +1 -0
- package/src/lib/sudo.ts +15 -5
- package/src/lib/wallet-profile.ts +3 -0
- package/src/lib/wallet-setup.ts +52 -0
- package/packages/cache/dist/chunk-QF4XKEIA.cjs.map +0 -1
- package/packages/cache/dist/chunk-QNK6GOTI.js.map +0 -1
package/src/cli.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
1
2
|
import * as configPackage from '../packages/config/src/index.js';
|
|
2
|
-
import * as rpcPackage from '../packages/rpc/src/index.
|
|
3
|
+
import * as rpcPackage from '../packages/rpc/src/index.js';
|
|
3
4
|
import type { ChainProfile, TokenChainProfile, WlfiConfig } from '../packages/config/src/index.js';
|
|
4
5
|
import { Command, Option } from 'commander';
|
|
5
6
|
import { type Address, type Hex, isAddress, isHex } from 'viem';
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
encodeErc20ApproveData,
|
|
30
31
|
encodeErc20TransferData,
|
|
31
32
|
formatBroadcastedAssetOutput,
|
|
33
|
+
resolveEstimatedPriorityFeePerGasWei,
|
|
32
34
|
resolveAssetBroadcastPlan,
|
|
33
35
|
waitForOnchainReceipt,
|
|
34
36
|
} from './lib/asset-broadcast.js';
|
|
@@ -151,6 +153,14 @@ interface RustManualApprovalRequiredOutput {
|
|
|
151
153
|
cli_approval_command: string;
|
|
152
154
|
}
|
|
153
155
|
|
|
156
|
+
type AgentCommandAttemptResult<T> =
|
|
157
|
+
| { type: 'success'; value: T }
|
|
158
|
+
| {
|
|
159
|
+
type: 'manualApproval';
|
|
160
|
+
output: RustManualApprovalRequiredOutput;
|
|
161
|
+
exitCode: number;
|
|
162
|
+
};
|
|
163
|
+
|
|
154
164
|
function rewriteAgentAmountError(
|
|
155
165
|
error: unknown,
|
|
156
166
|
symbolAwareAsset: { decimals: number; symbol: string; assetId: string },
|
|
@@ -179,10 +189,12 @@ function isManualApprovalRequiredOutput(value: unknown): value is RustManualAppr
|
|
|
179
189
|
);
|
|
180
190
|
}
|
|
181
191
|
|
|
182
|
-
function
|
|
192
|
+
function renderManualApprovalRequired(
|
|
193
|
+
output: RustManualApprovalRequiredOutput,
|
|
194
|
+
asJson: boolean,
|
|
195
|
+
): string {
|
|
183
196
|
if (asJson) {
|
|
184
|
-
|
|
185
|
-
return;
|
|
197
|
+
return formatJson(output);
|
|
186
198
|
}
|
|
187
199
|
|
|
188
200
|
const lines = [
|
|
@@ -196,7 +208,37 @@ function printManualApprovalRequired(output: RustManualApprovalRequiredOutput, a
|
|
|
196
208
|
lines.push(`Relay URL: ${output.relay_url}`);
|
|
197
209
|
}
|
|
198
210
|
lines.push(`CLI Approval Command: ${output.cli_approval_command}`);
|
|
199
|
-
|
|
211
|
+
return lines.join('\n');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function printManualApprovalRequired(
|
|
215
|
+
output: RustManualApprovalRequiredOutput,
|
|
216
|
+
asJson: boolean,
|
|
217
|
+
useStderr = false,
|
|
218
|
+
) {
|
|
219
|
+
const rendered = renderManualApprovalRequired(output, asJson);
|
|
220
|
+
if (useStderr) {
|
|
221
|
+
console.error(rendered);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
console.log(rendered);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function printManualApprovalWaiting(
|
|
228
|
+
output: RustManualApprovalRequiredOutput,
|
|
229
|
+
asJson: boolean,
|
|
230
|
+
) {
|
|
231
|
+
if (asJson) {
|
|
232
|
+
console.error(
|
|
233
|
+
formatJson({
|
|
234
|
+
event: 'manualApprovalPending',
|
|
235
|
+
approvalRequestId: output.approval_request_id,
|
|
236
|
+
}),
|
|
237
|
+
);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
console.error(`Waiting for manual approval decision: ${output.approval_request_id}`);
|
|
200
242
|
}
|
|
201
243
|
|
|
202
244
|
const MAX_SECRET_STDIN_BYTES = 16 * 1024;
|
|
@@ -335,6 +377,16 @@ function print(payload: unknown, asJson: boolean) {
|
|
|
335
377
|
|
|
336
378
|
const ONCHAIN_RECEIPT_TIMEOUT_MS = 30_000;
|
|
337
379
|
const ONCHAIN_RECEIPT_POLL_INTERVAL_MS = 2_000;
|
|
380
|
+
const MANUAL_APPROVAL_POLL_INTERVAL_MS = 2_000;
|
|
381
|
+
const MANUAL_APPROVAL_WAIT_TIMEOUT_MS =
|
|
382
|
+
(() => {
|
|
383
|
+
const raw = process.env.WLFI_TEST_MANUAL_APPROVAL_TIMEOUT_MS;
|
|
384
|
+
if (!raw) {
|
|
385
|
+
return 5 * 60_000;
|
|
386
|
+
}
|
|
387
|
+
const parsed = Number(raw);
|
|
388
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 5 * 60_000;
|
|
389
|
+
})();
|
|
338
390
|
|
|
339
391
|
async function reportOnchainReceiptStatus(input: {
|
|
340
392
|
rpcUrl: string;
|
|
@@ -510,44 +562,45 @@ async function resolveAgentCommandContext(
|
|
|
510
562
|
return { agentKeyId, agentAuthToken, daemonSocket };
|
|
511
563
|
}
|
|
512
564
|
|
|
513
|
-
async function
|
|
565
|
+
async function runAgentCommandJsonOnce<T>(input: {
|
|
514
566
|
commandArgs: string[];
|
|
515
|
-
auth: AgentCommandAuthOptions;
|
|
516
567
|
config: WlfiConfig;
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
input.config,
|
|
522
|
-
);
|
|
523
|
-
|
|
568
|
+
agentKeyId: string;
|
|
569
|
+
agentAuthToken: string;
|
|
570
|
+
daemonSocket: string;
|
|
571
|
+
}): Promise<AgentCommandAttemptResult<T>> {
|
|
524
572
|
try {
|
|
525
|
-
return
|
|
526
|
-
'
|
|
527
|
-
|
|
528
|
-
'
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
573
|
+
return {
|
|
574
|
+
type: 'success',
|
|
575
|
+
value: await runRustBinaryJson<T>(
|
|
576
|
+
'wlfi-agent-agent',
|
|
577
|
+
[
|
|
578
|
+
'--json',
|
|
579
|
+
'--agent-key-id',
|
|
580
|
+
input.agentKeyId,
|
|
581
|
+
'--agent-auth-token-stdin',
|
|
582
|
+
'--daemon-socket',
|
|
583
|
+
input.daemonSocket,
|
|
584
|
+
...input.commandArgs,
|
|
585
|
+
],
|
|
586
|
+
input.config,
|
|
587
|
+
{
|
|
588
|
+
stdin: `${input.agentAuthToken}\n`,
|
|
589
|
+
preSuppliedSecretStdin: 'agentAuthToken',
|
|
590
|
+
scrubSensitiveEnv: true,
|
|
591
|
+
},
|
|
592
|
+
),
|
|
593
|
+
};
|
|
543
594
|
} catch (error) {
|
|
544
595
|
if (error instanceof RustBinaryExitError && error.stdout.trim()) {
|
|
545
596
|
try {
|
|
546
597
|
const parsed = JSON.parse(error.stdout) as unknown;
|
|
547
598
|
if (isManualApprovalRequiredOutput(parsed)) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
599
|
+
return {
|
|
600
|
+
type: 'manualApproval',
|
|
601
|
+
output: parsed,
|
|
602
|
+
exitCode: error.code,
|
|
603
|
+
};
|
|
551
604
|
}
|
|
552
605
|
} catch {
|
|
553
606
|
// fall through to the original error
|
|
@@ -557,6 +610,64 @@ async function runAgentCommandJson<T>(input: {
|
|
|
557
610
|
}
|
|
558
611
|
}
|
|
559
612
|
|
|
613
|
+
async function runAgentCommandJson<T>(input: {
|
|
614
|
+
commandArgs: string[];
|
|
615
|
+
auth: AgentCommandAuthOptions;
|
|
616
|
+
config: WlfiConfig;
|
|
617
|
+
asJson: boolean;
|
|
618
|
+
waitForManualApproval?: boolean;
|
|
619
|
+
}): Promise<T | null> {
|
|
620
|
+
const { agentKeyId, agentAuthToken, daemonSocket } = await resolveAgentCommandContext(
|
|
621
|
+
input.auth,
|
|
622
|
+
input.config,
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
const runOnce = () =>
|
|
626
|
+
runAgentCommandJsonOnce<T>({
|
|
627
|
+
commandArgs: input.commandArgs,
|
|
628
|
+
config: input.config,
|
|
629
|
+
agentKeyId,
|
|
630
|
+
agentAuthToken,
|
|
631
|
+
daemonSocket,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
const firstAttempt = await runOnce();
|
|
635
|
+
if (firstAttempt.type === 'success') {
|
|
636
|
+
return firstAttempt.value;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (!input.waitForManualApproval) {
|
|
640
|
+
printManualApprovalRequired(firstAttempt.output, input.asJson);
|
|
641
|
+
process.exitCode = firstAttempt.exitCode;
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
printManualApprovalRequired(firstAttempt.output, input.asJson, true);
|
|
646
|
+
printManualApprovalWaiting(firstAttempt.output, input.asJson);
|
|
647
|
+
const pendingApprovalRequestId = firstAttempt.output.approval_request_id;
|
|
648
|
+
const startedWaitingAt = Date.now();
|
|
649
|
+
|
|
650
|
+
for (;;) {
|
|
651
|
+
await sleep(MANUAL_APPROVAL_POLL_INTERVAL_MS);
|
|
652
|
+
const nextAttempt = await runOnce();
|
|
653
|
+
if (nextAttempt.type === 'success') {
|
|
654
|
+
return nextAttempt.value;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (nextAttempt.output.approval_request_id !== pendingApprovalRequestId) {
|
|
658
|
+
throw new Error(
|
|
659
|
+
`manual approval request changed while waiting for a decision (${pendingApprovalRequestId} -> ${nextAttempt.output.approval_request_id}); stop and rerun the command after checking the approval status.`,
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
if (Date.now() - startedWaitingAt >= MANUAL_APPROVAL_WAIT_TIMEOUT_MS) {
|
|
664
|
+
throw new Error(
|
|
665
|
+
`Timed out after ${Math.ceil(MANUAL_APPROVAL_WAIT_TIMEOUT_MS / 1000)}s waiting for manual approval decision: ${pendingApprovalRequestId}`,
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
560
671
|
function legacyAmountToDecimalString(value: number | undefined): string | undefined {
|
|
561
672
|
if (value === undefined) {
|
|
562
673
|
return undefined;
|
|
@@ -1487,6 +1598,7 @@ async function main() {
|
|
|
1487
1598
|
auth: options,
|
|
1488
1599
|
config,
|
|
1489
1600
|
asJson: options.json,
|
|
1601
|
+
waitForManualApproval: true,
|
|
1490
1602
|
});
|
|
1491
1603
|
if (!signed) {
|
|
1492
1604
|
return;
|
|
@@ -1550,22 +1662,128 @@ async function main() {
|
|
|
1550
1662
|
.requiredOption('--network <name>', 'Network name')
|
|
1551
1663
|
.requiredOption('--to <address>', 'Recipient address')
|
|
1552
1664
|
.requiredOption('--amount <amount>', 'Transfer amount in configured native token units')
|
|
1665
|
+
.option('--broadcast', 'Broadcast the signed transaction through RPC', false)
|
|
1666
|
+
.option('--rpc-url <url>', 'Ethereum RPC URL override used only for broadcast')
|
|
1667
|
+
.option(
|
|
1668
|
+
'--from <address>',
|
|
1669
|
+
'Sender address override for broadcast; defaults to configured wallet address',
|
|
1670
|
+
)
|
|
1671
|
+
.option('--nonce <nonce>', 'Explicit nonce override for broadcast')
|
|
1672
|
+
.option('--gas-limit <gas>', 'Gas limit override for broadcast')
|
|
1673
|
+
.option('--max-fee-per-gas-wei <wei>', 'Max fee per gas override for broadcast')
|
|
1674
|
+
.option('--max-priority-fee-per-gas-wei <wei>', 'Priority fee per gas override for broadcast')
|
|
1675
|
+
.option('--tx-type <type>', 'Typed tx value for broadcast', '0x02')
|
|
1676
|
+
.option('--no-wait', 'Do not wait up to 30s for an on-chain receipt after broadcast')
|
|
1677
|
+
.option(
|
|
1678
|
+
'--reveal-raw-tx',
|
|
1679
|
+
'Include the signed raw transaction bytes in broadcast output',
|
|
1680
|
+
false,
|
|
1681
|
+
)
|
|
1682
|
+
.option('--reveal-signature', 'Include signer r/s/v fields in broadcast output', false)
|
|
1553
1683
|
.addOption(new Option('--amount-wei <wei>').hideHelp()),
|
|
1554
1684
|
).action(async (options) => {
|
|
1555
1685
|
const config = readConfig();
|
|
1556
1686
|
const network = resolveCliNetworkProfile(options.network, config).chainId;
|
|
1557
1687
|
const asset = resolveConfiguredNativeAsset(config, network);
|
|
1688
|
+
const recipient = assertAddress(options.to, 'to');
|
|
1558
1689
|
const amountWei = options.amount
|
|
1559
1690
|
? parseConfiguredAmount(options.amount, asset.decimals, 'amount')
|
|
1560
1691
|
: parseBigIntString(options.amountWei, 'amountWei');
|
|
1561
1692
|
try {
|
|
1693
|
+
if (options.broadcast) {
|
|
1694
|
+
const plan = await resolveAssetBroadcastPlan(
|
|
1695
|
+
{
|
|
1696
|
+
rpcUrl: resolveCliRpcUrl(options.rpcUrl, options.network, config),
|
|
1697
|
+
chainId: network,
|
|
1698
|
+
from: options.from ? assertAddress(options.from, 'from') : resolveWalletAddress(config),
|
|
1699
|
+
to: recipient,
|
|
1700
|
+
valueWei: amountWei,
|
|
1701
|
+
dataHex: '0x',
|
|
1702
|
+
nonce: options.nonce ? parseIntegerString(options.nonce, 'nonce') : undefined,
|
|
1703
|
+
gasLimit: options.gasLimit
|
|
1704
|
+
? parsePositiveBigIntString(options.gasLimit, 'gasLimit')
|
|
1705
|
+
: undefined,
|
|
1706
|
+
maxFeePerGasWei: options.maxFeePerGasWei
|
|
1707
|
+
? parsePositiveBigIntString(options.maxFeePerGasWei, 'maxFeePerGasWei')
|
|
1708
|
+
: undefined,
|
|
1709
|
+
maxPriorityFeePerGasWei: options.maxPriorityFeePerGasWei
|
|
1710
|
+
? parseBigIntString(options.maxPriorityFeePerGasWei, 'maxPriorityFeePerGasWei')
|
|
1711
|
+
: undefined,
|
|
1712
|
+
txType: options.txType,
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
getChainInfo,
|
|
1716
|
+
assertRpcChainIdMatches,
|
|
1717
|
+
getNonce,
|
|
1718
|
+
estimateGas,
|
|
1719
|
+
estimateFees,
|
|
1720
|
+
},
|
|
1721
|
+
);
|
|
1722
|
+
const signed = await runAgentCommandJson<RustBroadcastOutput>({
|
|
1723
|
+
commandArgs: [
|
|
1724
|
+
'broadcast',
|
|
1725
|
+
'--network',
|
|
1726
|
+
String(plan.chainId),
|
|
1727
|
+
'--nonce',
|
|
1728
|
+
String(plan.nonce),
|
|
1729
|
+
'--to',
|
|
1730
|
+
recipient,
|
|
1731
|
+
'--value-wei',
|
|
1732
|
+
amountWei.toString(),
|
|
1733
|
+
'--data-hex',
|
|
1734
|
+
'0x',
|
|
1735
|
+
'--gas-limit',
|
|
1736
|
+
plan.gasLimit.toString(),
|
|
1737
|
+
'--max-fee-per-gas-wei',
|
|
1738
|
+
plan.maxFeePerGasWei.toString(),
|
|
1739
|
+
'--max-priority-fee-per-gas-wei',
|
|
1740
|
+
plan.maxPriorityFeePerGasWei.toString(),
|
|
1741
|
+
'--tx-type',
|
|
1742
|
+
plan.txType,
|
|
1743
|
+
],
|
|
1744
|
+
auth: options,
|
|
1745
|
+
config,
|
|
1746
|
+
asJson: options.json,
|
|
1747
|
+
waitForManualApproval: true,
|
|
1748
|
+
});
|
|
1749
|
+
if (!signed) {
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
const completed = await completeAssetBroadcast(plan, signed, {
|
|
1753
|
+
assertSignedBroadcastTransactionMatchesRequest,
|
|
1754
|
+
broadcastRawTransaction,
|
|
1755
|
+
});
|
|
1756
|
+
print(
|
|
1757
|
+
formatBroadcastedAssetOutput({
|
|
1758
|
+
command: 'transfer-native',
|
|
1759
|
+
counterparty: recipient,
|
|
1760
|
+
asset,
|
|
1761
|
+
signed,
|
|
1762
|
+
plan,
|
|
1763
|
+
signedNonce: completed.signedNonce,
|
|
1764
|
+
networkTxHash: completed.networkTxHash,
|
|
1765
|
+
revealRawTx: options.revealRawTx,
|
|
1766
|
+
revealSignature: options.revealSignature,
|
|
1767
|
+
}),
|
|
1768
|
+
options.json,
|
|
1769
|
+
);
|
|
1770
|
+
if (options.wait) {
|
|
1771
|
+
await reportOnchainReceiptStatus({
|
|
1772
|
+
rpcUrl: plan.rpcUrl,
|
|
1773
|
+
txHash: completed.networkTxHash,
|
|
1774
|
+
asJson: options.json,
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
return;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1562
1780
|
const result = await runAgentCommandJson<RustBroadcastOutput>({
|
|
1563
1781
|
commandArgs: [
|
|
1564
1782
|
'transfer-native',
|
|
1565
1783
|
'--network',
|
|
1566
1784
|
String(network),
|
|
1567
1785
|
'--to',
|
|
1568
|
-
|
|
1786
|
+
recipient,
|
|
1569
1787
|
'--amount-wei',
|
|
1570
1788
|
amountWei.toString(),
|
|
1571
1789
|
],
|
|
@@ -1672,6 +1890,7 @@ async function main() {
|
|
|
1672
1890
|
auth: options,
|
|
1673
1891
|
config,
|
|
1674
1892
|
asJson: options.json,
|
|
1893
|
+
waitForManualApproval: true,
|
|
1675
1894
|
});
|
|
1676
1895
|
if (!signed) {
|
|
1677
1896
|
return;
|
|
@@ -1736,34 +1955,53 @@ async function main() {
|
|
|
1736
1955
|
.requiredOption('--to <address>', 'Recipient or target contract')
|
|
1737
1956
|
.requiredOption('--gas-limit <gas>', 'Gas limit')
|
|
1738
1957
|
.requiredOption('--max-fee-per-gas-wei <wei>', 'Max fee per gas in wei')
|
|
1739
|
-
.option('--nonce <nonce>', 'Explicit nonce override'
|
|
1958
|
+
.option('--nonce <nonce>', 'Explicit nonce override')
|
|
1740
1959
|
.option('--value-wei <wei>', 'Value in wei', '0')
|
|
1741
1960
|
.option('--data-hex <hex>', 'Calldata hex', '0x')
|
|
1742
|
-
.option('--max-priority-fee-per-gas-wei <wei>', 'Priority fee per gas in wei'
|
|
1743
|
-
.option('--tx-type <type>', 'Typed tx value', '
|
|
1961
|
+
.option('--max-priority-fee-per-gas-wei <wei>', 'Priority fee per gas in wei')
|
|
1962
|
+
.option('--tx-type <type>', 'Typed tx value', '0x02')
|
|
1744
1963
|
.option('--delegation-enabled', 'Forward delegation flag to Rust signing request', false),
|
|
1745
1964
|
).action(async (options) => {
|
|
1746
1965
|
const config = readConfig();
|
|
1747
1966
|
const network = resolveCliNetworkProfile(options.network, config);
|
|
1748
|
-
const
|
|
1967
|
+
const to = assertAddress(options.to, 'to');
|
|
1968
|
+
const valueWei = parseBigIntString(options.valueWei, 'valueWei');
|
|
1969
|
+
const dataHex = assertHex(options.dataHex, 'dataHex');
|
|
1970
|
+
const gasLimit = parsePositiveBigIntString(options.gasLimit, 'gasLimit');
|
|
1971
|
+
const maxFeePerGasWei = parsePositiveBigIntString(options.maxFeePerGasWei, 'maxFeePerGasWei');
|
|
1972
|
+
const explicitNonce = options.nonce ? parseIntegerString(options.nonce, 'nonce') : undefined;
|
|
1973
|
+
const rpcUrl = resolveCliRpcUrl(undefined, options.network, config);
|
|
1974
|
+
const from = resolveWalletAddress(config);
|
|
1975
|
+
const chainInfo = await getChainInfo(rpcUrl);
|
|
1976
|
+
assertRpcChainIdMatches(network.chainId, chainInfo.chainId);
|
|
1977
|
+
const nonce = explicitNonce ?? (await getNonce(rpcUrl, from));
|
|
1978
|
+
const fees = options.maxPriorityFeePerGasWei ? null : await estimateFees(rpcUrl);
|
|
1979
|
+
const maxPriorityFeePerGasWei = options.maxPriorityFeePerGasWei
|
|
1980
|
+
? parseBigIntString(options.maxPriorityFeePerGasWei, 'maxPriorityFeePerGasWei')
|
|
1981
|
+
: resolveEstimatedPriorityFeePerGasWei({
|
|
1982
|
+
gasPrice: fees?.gasPrice ?? null,
|
|
1983
|
+
maxFeePerGas: fees?.maxFeePerGas ?? null,
|
|
1984
|
+
maxPriorityFeePerGas: fees?.maxPriorityFeePerGas ?? null,
|
|
1985
|
+
});
|
|
1986
|
+
const signed = await runAgentCommandJson<RustBroadcastOutput>({
|
|
1749
1987
|
commandArgs: [
|
|
1750
1988
|
'broadcast',
|
|
1751
1989
|
'--network',
|
|
1752
1990
|
String(network.chainId),
|
|
1753
1991
|
'--nonce',
|
|
1754
|
-
String(
|
|
1992
|
+
String(nonce),
|
|
1755
1993
|
'--to',
|
|
1756
|
-
|
|
1994
|
+
to,
|
|
1757
1995
|
'--value-wei',
|
|
1758
|
-
|
|
1996
|
+
valueWei.toString(),
|
|
1759
1997
|
'--data-hex',
|
|
1760
|
-
|
|
1998
|
+
dataHex,
|
|
1761
1999
|
'--gas-limit',
|
|
1762
|
-
|
|
2000
|
+
gasLimit.toString(),
|
|
1763
2001
|
'--max-fee-per-gas-wei',
|
|
1764
|
-
|
|
2002
|
+
maxFeePerGasWei.toString(),
|
|
1765
2003
|
'--max-priority-fee-per-gas-wei',
|
|
1766
|
-
|
|
2004
|
+
maxPriorityFeePerGasWei.toString(),
|
|
1767
2005
|
'--tx-type',
|
|
1768
2006
|
options.txType,
|
|
1769
2007
|
...(options.delegationEnabled ? ['--delegation-enabled'] : []),
|
|
@@ -1772,9 +2010,31 @@ async function main() {
|
|
|
1772
2010
|
config,
|
|
1773
2011
|
asJson: options.json,
|
|
1774
2012
|
});
|
|
1775
|
-
if (
|
|
1776
|
-
|
|
2013
|
+
if (!signed) {
|
|
2014
|
+
return;
|
|
1777
2015
|
}
|
|
2016
|
+
|
|
2017
|
+
if (!signed.raw_tx_hex) {
|
|
2018
|
+
throw new Error('Rust agent did not return raw_tx_hex for broadcast signing');
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
await assertSignedBroadcastTransactionMatchesRequest({
|
|
2022
|
+
rawTxHex: signed.raw_tx_hex as Hex,
|
|
2023
|
+
from,
|
|
2024
|
+
to,
|
|
2025
|
+
chainId: network.chainId,
|
|
2026
|
+
nonce,
|
|
2027
|
+
allowHigherNonce: false,
|
|
2028
|
+
value: valueWei,
|
|
2029
|
+
data: dataHex,
|
|
2030
|
+
gasLimit,
|
|
2031
|
+
maxFeePerGas: maxFeePerGasWei,
|
|
2032
|
+
maxPriorityFeePerGas: maxPriorityFeePerGasWei,
|
|
2033
|
+
txType: options.txType,
|
|
2034
|
+
});
|
|
2035
|
+
|
|
2036
|
+
await broadcastRawTransaction(rpcUrl, signed.raw_tx_hex as Hex);
|
|
2037
|
+
print(signed, options.json);
|
|
1778
2038
|
});
|
|
1779
2039
|
|
|
1780
2040
|
const rpc = program.command('rpc').description('RPC methods implemented in TypeScript');
|
|
@@ -2083,7 +2343,7 @@ async function main() {
|
|
|
2083
2343
|
to,
|
|
2084
2344
|
chainId,
|
|
2085
2345
|
nonce,
|
|
2086
|
-
allowHigherNonce:
|
|
2346
|
+
allowHigherNonce: false,
|
|
2087
2347
|
value: valueWei,
|
|
2088
2348
|
data: dataHex,
|
|
2089
2349
|
gasLimit,
|