@manifest-network/manifest-mcp-browser 0.1.1 → 0.1.6
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/.github/workflows/publish.yml +4 -2
- package/CLAUDE.md +11 -6
- package/README.md +1 -1
- package/dist/client.d.ts +6 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +77 -21
- package/dist/client.js.map +1 -1
- package/dist/cosmos.d.ts.map +1 -1
- package/dist/cosmos.js +7 -57
- package/dist/cosmos.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -25
- package/dist/index.js.map +1 -1
- package/dist/modules.d.ts +30 -1
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +98 -1
- package/dist/modules.js.map +1 -1
- package/dist/modules.test.js +60 -1
- package/dist/modules.test.js.map +1 -1
- package/dist/queries/auth.d.ts +7 -1
- package/dist/queries/auth.d.ts.map +1 -1
- package/dist/queries/auth.js +18 -45
- package/dist/queries/auth.js.map +1 -1
- package/dist/queries/bank.d.ts +7 -1
- package/dist/queries/bank.d.ts.map +1 -1
- package/dist/queries/bank.js +24 -38
- package/dist/queries/bank.js.map +1 -1
- package/dist/queries/billing.d.ts +7 -1
- package/dist/queries/billing.d.ts.map +1 -1
- package/dist/queries/billing.js +28 -54
- package/dist/queries/billing.js.map +1 -1
- package/dist/queries/distribution.d.ts +7 -1
- package/dist/queries/distribution.d.ts.map +1 -1
- package/dist/queries/distribution.js +18 -36
- package/dist/queries/distribution.js.map +1 -1
- package/dist/queries/gov.d.ts +7 -1
- package/dist/queries/gov.d.ts.map +1 -1
- package/dist/queries/gov.js +24 -41
- package/dist/queries/gov.js.map +1 -1
- package/dist/queries/index.d.ts +2 -1
- package/dist/queries/index.d.ts.map +1 -1
- package/dist/queries/index.js +1 -1
- package/dist/queries/index.js.map +1 -1
- package/dist/queries/sku.d.ts +13 -0
- package/dist/queries/sku.d.ts.map +1 -0
- package/dist/queries/sku.js +60 -0
- package/dist/queries/sku.js.map +1 -0
- package/dist/queries/staking.d.ts +7 -1
- package/dist/queries/staking.d.ts.map +1 -1
- package/dist/queries/staking.js +36 -59
- package/dist/queries/staking.js.map +1 -1
- package/dist/queries/utils.d.ts +60 -10
- package/dist/queries/utils.d.ts.map +1 -1
- package/dist/queries/utils.js +80 -12
- package/dist/queries/utils.js.map +1 -1
- package/dist/queries/utils.test.js +68 -8
- package/dist/queries/utils.test.js.map +1 -1
- package/dist/transactions/bank.d.ts +2 -2
- package/dist/transactions/bank.d.ts.map +1 -1
- package/dist/transactions/bank.js +9 -18
- package/dist/transactions/bank.js.map +1 -1
- package/dist/transactions/billing.d.ts +2 -2
- package/dist/transactions/billing.d.ts.map +1 -1
- package/dist/transactions/billing.js +125 -89
- package/dist/transactions/billing.js.map +1 -1
- package/dist/transactions/distribution.d.ts +2 -2
- package/dist/transactions/distribution.d.ts.map +1 -1
- package/dist/transactions/distribution.js +7 -13
- package/dist/transactions/distribution.js.map +1 -1
- package/dist/transactions/gov.d.ts +2 -2
- package/dist/transactions/gov.d.ts.map +1 -1
- package/dist/transactions/gov.js +29 -20
- package/dist/transactions/gov.js.map +1 -1
- package/dist/transactions/index.d.ts +1 -1
- package/dist/transactions/index.d.ts.map +1 -1
- package/dist/transactions/index.js +1 -1
- package/dist/transactions/index.js.map +1 -1
- package/dist/transactions/manifest.d.ts +2 -2
- package/dist/transactions/manifest.d.ts.map +1 -1
- package/dist/transactions/manifest.js +7 -14
- package/dist/transactions/manifest.js.map +1 -1
- package/dist/transactions/sku.d.ts +7 -0
- package/dist/transactions/sku.d.ts.map +1 -0
- package/dist/transactions/sku.js +184 -0
- package/dist/transactions/sku.js.map +1 -0
- package/dist/transactions/staking.d.ts +2 -2
- package/dist/transactions/staking.d.ts.map +1 -1
- package/dist/transactions/staking.js +7 -13
- package/dist/transactions/staking.js.map +1 -1
- package/dist/transactions/utils.d.ts +65 -1
- package/dist/transactions/utils.d.ts.map +1 -1
- package/dist/transactions/utils.js +123 -2
- package/dist/transactions/utils.js.map +1 -1
- package/dist/transactions/utils.test.js +351 -1
- package/dist/transactions/utils.test.js.map +1 -1
- package/dist/types.d.ts +218 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wallet/mnemonic.d.ts +1 -0
- package/dist/wallet/mnemonic.d.ts.map +1 -1
- package/dist/wallet/mnemonic.js +34 -13
- package/dist/wallet/mnemonic.js.map +1 -1
- package/package.json +5 -1
- package/src/client.ts +84 -21
- package/src/cosmos.ts +13 -109
- package/src/index.ts +17 -23
- package/src/modules.test.ts +62 -0
- package/src/modules.ts +155 -5
- package/src/queries/auth.ts +35 -74
- package/src/queries/bank.ts +40 -58
- package/src/queries/billing.ts +46 -86
- package/src/queries/distribution.ts +35 -59
- package/src/queries/gov.ts +40 -64
- package/src/queries/index.ts +10 -1
- package/src/queries/sku.ts +85 -0
- package/src/queries/staking.ts +55 -91
- package/src/queries/utils.test.ts +103 -8
- package/src/queries/utils.ts +119 -12
- package/src/transactions/bank.ts +9 -33
- package/src/transactions/billing.ts +155 -141
- package/src/transactions/distribution.ts +7 -29
- package/src/transactions/gov.ts +33 -37
- package/src/transactions/index.ts +1 -1
- package/src/transactions/manifest.ts +7 -29
- package/src/transactions/sku.ts +232 -0
- package/src/transactions/staking.ts +7 -29
- package/src/transactions/utils.test.ts +390 -1
- package/src/transactions/utils.ts +194 -2
- package/src/types.ts +344 -9
- package/src/wallet/mnemonic.ts +41 -17
- package/.claude/settings.local.json +0 -20
package/src/queries/utils.ts
CHANGED
|
@@ -1,20 +1,113 @@
|
|
|
1
1
|
import { ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
|
|
2
|
-
import { parseBigIntWithCode } from '../transactions/utils.js';
|
|
2
|
+
import { parseBigIntWithCode, requireArgs as requireArgsBase, extractFlag, filterConsumedArgs } from '../transactions/utils.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Result from extracting a boolean (valueless) flag from args
|
|
6
|
+
*/
|
|
7
|
+
export interface ExtractedBooleanFlag {
|
|
8
|
+
/** Whether the flag was present */
|
|
9
|
+
value: boolean;
|
|
10
|
+
/** Args with the flag removed */
|
|
11
|
+
remainingArgs: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extract a valueless boolean flag from args array.
|
|
16
|
+
* Returns { value: true, remainingArgs } if flag is present, { value: false, remainingArgs: args } otherwise.
|
|
17
|
+
*
|
|
18
|
+
* @param args - The arguments array to search
|
|
19
|
+
* @param flagName - The flag to look for (e.g., '--active-only')
|
|
20
|
+
* @returns Object with boolean value and filtered args
|
|
21
|
+
*/
|
|
22
|
+
export function extractBooleanFlag(args: string[], flagName: string): ExtractedBooleanFlag {
|
|
23
|
+
const flagIndex = args.indexOf(flagName);
|
|
24
|
+
if (flagIndex === -1) {
|
|
25
|
+
return { value: false, remainingArgs: args };
|
|
26
|
+
}
|
|
27
|
+
const remainingArgs = args.filter((_, index) => index !== flagIndex);
|
|
28
|
+
return { value: true, remainingArgs };
|
|
29
|
+
}
|
|
3
30
|
|
|
4
31
|
/** Default page size limit for paginated queries to prevent resource exhaustion */
|
|
5
32
|
export const DEFAULT_PAGE_LIMIT = BigInt(100);
|
|
6
33
|
|
|
34
|
+
/** Maximum page size limit to prevent DoS */
|
|
35
|
+
export const MAX_PAGE_LIMIT = BigInt(1000);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Cosmos SDK pagination configuration
|
|
39
|
+
*/
|
|
40
|
+
export interface PaginationConfig {
|
|
41
|
+
readonly key: Uint8Array;
|
|
42
|
+
readonly offset: bigint;
|
|
43
|
+
readonly limit: bigint;
|
|
44
|
+
readonly countTotal: boolean;
|
|
45
|
+
readonly reverse: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create pagination configuration with optional custom limit.
|
|
50
|
+
* Validates that limit is within acceptable bounds.
|
|
51
|
+
*
|
|
52
|
+
* @param limit - Optional custom limit (defaults to DEFAULT_PAGE_LIMIT)
|
|
53
|
+
* @returns Cosmos SDK pagination object
|
|
54
|
+
*/
|
|
55
|
+
export function createPagination(limit?: bigint): PaginationConfig {
|
|
56
|
+
let effectiveLimit = limit ?? DEFAULT_PAGE_LIMIT;
|
|
57
|
+
|
|
58
|
+
// Clamp to valid range
|
|
59
|
+
if (effectiveLimit < BigInt(1)) {
|
|
60
|
+
effectiveLimit = BigInt(1);
|
|
61
|
+
} else if (effectiveLimit > MAX_PAGE_LIMIT) {
|
|
62
|
+
effectiveLimit = MAX_PAGE_LIMIT;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
key: new Uint8Array(),
|
|
67
|
+
offset: BigInt(0),
|
|
68
|
+
limit: effectiveLimit,
|
|
69
|
+
countTotal: false,
|
|
70
|
+
reverse: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Default pagination configuration for queries (for backwards compatibility)
|
|
76
|
+
* @deprecated Use createPagination() instead for configurable limits
|
|
77
|
+
*/
|
|
78
|
+
export const defaultPagination = createPagination();
|
|
79
|
+
|
|
7
80
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
81
|
+
* Extract --limit flag from args and return pagination config with remaining args.
|
|
82
|
+
* Use this helper for paginated queries.
|
|
83
|
+
*
|
|
84
|
+
* @param args - The arguments array
|
|
85
|
+
* @param context - Context for error messages
|
|
86
|
+
* @returns Object with pagination config and filtered args
|
|
10
87
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
88
|
+
export function extractPaginationArgs(
|
|
89
|
+
args: string[],
|
|
90
|
+
context: string
|
|
91
|
+
): { pagination: PaginationConfig; remainingArgs: string[] } {
|
|
92
|
+
const { value: limitStr, consumedIndices } = extractFlag(args, '--limit', context);
|
|
93
|
+
const remainingArgs = filterConsumedArgs(args, consumedIndices);
|
|
94
|
+
|
|
95
|
+
let pagination: PaginationConfig;
|
|
96
|
+
if (limitStr) {
|
|
97
|
+
const limit = parseBigInt(limitStr, 'limit');
|
|
98
|
+
if (limit < BigInt(1) || limit > MAX_PAGE_LIMIT) {
|
|
99
|
+
throw new ManifestMCPError(
|
|
100
|
+
ManifestMCPErrorCode.QUERY_FAILED,
|
|
101
|
+
`Invalid limit: ${limit}. Must be between 1 and ${MAX_PAGE_LIMIT}.`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
pagination = createPagination(limit);
|
|
105
|
+
} else {
|
|
106
|
+
pagination = createPagination();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return { pagination, remainingArgs };
|
|
110
|
+
}
|
|
18
111
|
|
|
19
112
|
/**
|
|
20
113
|
* Safely parse a string to BigInt with proper error handling (for queries)
|
|
@@ -24,9 +117,10 @@ export function parseBigInt(value: string, fieldName: string): bigint {
|
|
|
24
117
|
}
|
|
25
118
|
|
|
26
119
|
/**
|
|
27
|
-
* Safely parse a string to integer with proper error handling
|
|
120
|
+
* Safely parse a string to integer with proper error handling.
|
|
121
|
+
* Named parseInteger to avoid shadowing global parseInt.
|
|
28
122
|
*/
|
|
29
|
-
export function
|
|
123
|
+
export function parseInteger(value: string, fieldName: string): number {
|
|
30
124
|
const parsed = Number.parseInt(value, 10);
|
|
31
125
|
if (Number.isNaN(parsed)) {
|
|
32
126
|
throw new ManifestMCPError(
|
|
@@ -36,3 +130,16 @@ export function parseInt(value: string, fieldName: string): number {
|
|
|
36
130
|
}
|
|
37
131
|
return parsed;
|
|
38
132
|
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Validate that required arguments are present (for queries).
|
|
136
|
+
* Uses QUERY_FAILED error code by default.
|
|
137
|
+
*/
|
|
138
|
+
export function requireArgs(
|
|
139
|
+
args: string[],
|
|
140
|
+
minCount: number,
|
|
141
|
+
expectedNames: string[],
|
|
142
|
+
context: string
|
|
143
|
+
): void {
|
|
144
|
+
requireArgsBase(args, minCount, expectedNames, context, ManifestMCPErrorCode.QUERY_FAILED);
|
|
145
|
+
}
|
package/src/transactions/bank.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { SigningStargateClient } from '@cosmjs/stargate';
|
|
2
2
|
import { cosmos } from '@manifest-network/manifestjs';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { CosmosTxResult } from '../types.js';
|
|
4
|
+
import { throwUnsupportedSubcommand } from '../modules.js';
|
|
5
|
+
import { parseAmount, buildTxResult, validateAddress, validateMemo, validateArgsLength, extractFlag, parseColonPair, requireArgs } from './utils.js';
|
|
5
6
|
|
|
6
7
|
const { MsgSend, MsgMultiSend } = cosmos.bank.v1beta1;
|
|
7
8
|
|
|
@@ -13,29 +14,20 @@ export async function routeBankTransaction(
|
|
|
13
14
|
senderAddress: string,
|
|
14
15
|
subcommand: string,
|
|
15
16
|
args: string[],
|
|
16
|
-
_config: ManifestMCPConfig,
|
|
17
17
|
waitForConfirmation: boolean
|
|
18
18
|
): Promise<CosmosTxResult> {
|
|
19
19
|
validateArgsLength(args, 'bank transaction');
|
|
20
20
|
|
|
21
21
|
switch (subcommand) {
|
|
22
22
|
case 'send': {
|
|
23
|
-
|
|
24
|
-
throw new ManifestMCPError(
|
|
25
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
26
|
-
'send requires recipient-address and amount arguments'
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
23
|
+
requireArgs(args, 2, ['recipient-address', 'amount'], 'bank send');
|
|
30
24
|
const [recipientAddress, amountStr] = args;
|
|
31
25
|
validateAddress(recipientAddress, 'recipient address');
|
|
32
26
|
const { amount, denom } = parseAmount(amountStr);
|
|
33
27
|
|
|
34
28
|
// Extract optional memo from args
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (memoIndex !== -1 && args[memoIndex + 1]) {
|
|
38
|
-
memo = args[memoIndex + 1];
|
|
29
|
+
const { value: memo = '' } = extractFlag(args, '--memo', 'bank send');
|
|
30
|
+
if (memo) {
|
|
39
31
|
validateMemo(memo);
|
|
40
32
|
}
|
|
41
33
|
|
|
@@ -53,22 +45,10 @@ export async function routeBankTransaction(
|
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
case 'multi-send': {
|
|
56
|
-
|
|
57
|
-
throw new ManifestMCPError(
|
|
58
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
59
|
-
'multi-send requires at least one recipient:amount pair'
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
48
|
+
requireArgs(args, 1, ['recipient:amount'], 'bank multi-send');
|
|
63
49
|
// Parse format: multi-send recipient1:amount1 recipient2:amount2 ...
|
|
64
50
|
const outputs = args.map((arg) => {
|
|
65
|
-
const [address, amountStr] = arg
|
|
66
|
-
if (!address || !amountStr) {
|
|
67
|
-
throw new ManifestMCPError(
|
|
68
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
69
|
-
`Invalid multi-send format: ${arg}. Expected format: address:amount`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
51
|
+
const [address, amountStr] = parseColonPair(arg, 'address', 'amount', 'multi-send');
|
|
72
52
|
validateAddress(address, 'recipient address');
|
|
73
53
|
const { amount, denom } = parseAmount(amountStr);
|
|
74
54
|
return { address, coins: [{ denom, amount }] };
|
|
@@ -101,10 +81,6 @@ export async function routeBankTransaction(
|
|
|
101
81
|
}
|
|
102
82
|
|
|
103
83
|
default:
|
|
104
|
-
|
|
105
|
-
ManifestMCPErrorCode.UNSUPPORTED_TX,
|
|
106
|
-
`Unsupported bank transaction subcommand: ${subcommand}`,
|
|
107
|
-
{ availableSubcommands: ['send', 'multi-send'] }
|
|
108
|
-
);
|
|
84
|
+
throwUnsupportedSubcommand('tx', 'bank', subcommand);
|
|
109
85
|
}
|
|
110
86
|
}
|
|
@@ -1,46 +1,14 @@
|
|
|
1
1
|
import { SigningStargateClient } from '@cosmjs/stargate';
|
|
2
|
-
import { fromHex } from '@cosmjs/encoding';
|
|
3
2
|
import { liftedinit } from '@manifest-network/manifestjs';
|
|
4
|
-
import { ManifestMCPError, ManifestMCPErrorCode
|
|
5
|
-
import { parseAmount, buildTxResult, parseBigInt, validateAddress, validateArgsLength } from './utils.js';
|
|
6
|
-
import { getSubcommandUsage } from '../modules.js';
|
|
3
|
+
import { CosmosTxResult, ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
|
|
4
|
+
import { parseAmount, buildTxResult, parseBigInt, validateAddress, validateArgsLength, extractFlag, filterConsumedArgs, parseColonPair, requireArgs, parseHexBytes, MAX_META_HASH_BYTES } from './utils.js';
|
|
5
|
+
import { getSubcommandUsage, throwUnsupportedSubcommand } from '../modules.js';
|
|
7
6
|
|
|
8
|
-
const {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Validate and parse a hex string into Uint8Array
|
|
15
|
-
* Uses @cosmjs/encoding for hex validation and conversion
|
|
16
|
-
*/
|
|
17
|
-
function parseMetaHash(hexString: string): Uint8Array {
|
|
18
|
-
// Check even length first to avoid fractional byte counts in error messages
|
|
19
|
-
if (hexString.length % 2 !== 0) {
|
|
20
|
-
throw new ManifestMCPError(
|
|
21
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
22
|
-
`Invalid meta-hash: hex string must have even length. Got ${hexString.length} characters.`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Check max length (64 bytes = 128 hex chars)
|
|
27
|
-
const byteLength = hexString.length / 2;
|
|
28
|
-
if (byteLength > MAX_META_HASH_BYTES) {
|
|
29
|
-
throw new ManifestMCPError(
|
|
30
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
31
|
-
`Invalid meta-hash: exceeds maximum ${MAX_META_HASH_BYTES} bytes. Got ${byteLength} bytes (${hexString.length} hex chars).`
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
return fromHex(hexString);
|
|
37
|
-
} catch (error) {
|
|
38
|
-
throw new ManifestMCPError(
|
|
39
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
40
|
-
`Invalid meta-hash: ${error instanceof Error ? error.message : String(error)}`
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
7
|
+
const {
|
|
8
|
+
MsgFundCredit, MsgCreateLease, MsgCloseLease, MsgWithdraw,
|
|
9
|
+
MsgCreateLeaseForTenant, MsgAcknowledgeLease, MsgRejectLease, MsgCancelLease,
|
|
10
|
+
MsgUpdateParams,
|
|
11
|
+
} = liftedinit.billing.v1;
|
|
44
12
|
|
|
45
13
|
/**
|
|
46
14
|
* Route billing transaction to appropriate handler
|
|
@@ -50,22 +18,13 @@ export async function routeBillingTransaction(
|
|
|
50
18
|
senderAddress: string,
|
|
51
19
|
subcommand: string,
|
|
52
20
|
args: string[],
|
|
53
|
-
_config: ManifestMCPConfig,
|
|
54
21
|
waitForConfirmation: boolean
|
|
55
22
|
): Promise<CosmosTxResult> {
|
|
56
23
|
validateArgsLength(args, 'billing transaction');
|
|
57
24
|
|
|
58
25
|
switch (subcommand) {
|
|
59
26
|
case 'fund-credit': {
|
|
60
|
-
|
|
61
|
-
const usage = getSubcommandUsage('tx', 'billing', 'fund-credit');
|
|
62
|
-
throw new ManifestMCPError(
|
|
63
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
64
|
-
`fund-credit requires tenant-address and amount arguments. Received ${args.length} argument(s): [${args.map(a => `"${a}"`).join(', ')}]. Usage: fund-credit ${usage || '<tenant-address> <amount>'}`,
|
|
65
|
-
{ receivedArgs: args, expectedArgs: ['tenant-address', 'amount'], usage }
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
27
|
+
requireArgs(args, 2, ['tenant-address', 'amount'], 'billing fund-credit');
|
|
69
28
|
const [tenant, amountStr] = args;
|
|
70
29
|
validateAddress(tenant, 'tenant address');
|
|
71
30
|
const { amount, denom } = parseAmount(amountStr);
|
|
@@ -84,42 +43,17 @@ export async function routeBillingTransaction(
|
|
|
84
43
|
}
|
|
85
44
|
|
|
86
45
|
case 'create-lease': {
|
|
87
|
-
// Parse optional --meta-hash flag
|
|
88
|
-
|
|
89
|
-
|
|
46
|
+
// Parse optional --meta-hash flag (can appear anywhere in args)
|
|
47
|
+
const { value: metaHashHex, consumedIndices } = extractFlag(args, '--meta-hash', 'billing create-lease');
|
|
48
|
+
const metaHash = metaHashHex ? parseHexBytes(metaHashHex, 'meta-hash', MAX_META_HASH_BYTES) : undefined;
|
|
90
49
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
throw new ManifestMCPError(
|
|
95
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
96
|
-
`--meta-hash flag requires a hex value. Usage: create-lease ${usage ?? '<args>'}`
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
const hexHash = args[1];
|
|
100
|
-
// Validate and convert hex string to Uint8Array (max 64 bytes)
|
|
101
|
-
metaHash = parseMetaHash(hexHash);
|
|
102
|
-
itemArgs = args.slice(2);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (itemArgs.length < 1) {
|
|
106
|
-
const usage = getSubcommandUsage('tx', 'billing', 'create-lease');
|
|
107
|
-
throw new ManifestMCPError(
|
|
108
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
109
|
-
`create-lease requires at least one sku-uuid:quantity pair. Usage: create-lease ${usage ?? '<args>'}`,
|
|
110
|
-
{ usage }
|
|
111
|
-
);
|
|
112
|
-
}
|
|
50
|
+
// Filter out --meta-hash and its value to get item args
|
|
51
|
+
const itemArgs = filterConsumedArgs(args, consumedIndices);
|
|
52
|
+
requireArgs(itemArgs, 1, ['sku-uuid:quantity'], 'billing create-lease');
|
|
113
53
|
|
|
114
54
|
// Parse items (format: sku-uuid:quantity ...)
|
|
115
55
|
const items = itemArgs.map((arg) => {
|
|
116
|
-
const [skuUuid, quantityStr] = arg
|
|
117
|
-
if (!skuUuid || !quantityStr) {
|
|
118
|
-
throw new ManifestMCPError(
|
|
119
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
120
|
-
`Invalid lease item format: ${arg}. Expected format: sku-uuid:quantity`
|
|
121
|
-
);
|
|
122
|
-
}
|
|
56
|
+
const [skuUuid, quantityStr] = parseColonPair(arg, 'sku-uuid', 'quantity', 'lease item');
|
|
123
57
|
return { skuUuid, quantity: parseBigInt(quantityStr, 'quantity') };
|
|
124
58
|
});
|
|
125
59
|
|
|
@@ -137,25 +71,20 @@ export async function routeBillingTransaction(
|
|
|
137
71
|
}
|
|
138
72
|
|
|
139
73
|
case 'close-lease': {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
`close-lease requires at least one lease-uuid argument. Usage: close-lease ${usage || '<lease-uuid>...'}`,
|
|
145
|
-
{ usage }
|
|
146
|
-
);
|
|
147
|
-
}
|
|
74
|
+
// Parse optional --reason flag
|
|
75
|
+
const { value: reason, consumedIndices } = extractFlag(args, '--reason', 'billing close-lease');
|
|
76
|
+
const leaseArgs = filterConsumedArgs(args, consumedIndices);
|
|
77
|
+
requireArgs(leaseArgs, 1, ['lease-uuid'], 'billing close-lease');
|
|
148
78
|
|
|
149
79
|
// MsgCloseLease can close multiple leases at once
|
|
150
|
-
const leaseUuids =
|
|
151
|
-
const reason = ''; // Optional reason, could be added as a flag later
|
|
80
|
+
const leaseUuids = leaseArgs;
|
|
152
81
|
|
|
153
82
|
const msg = {
|
|
154
83
|
typeUrl: '/liftedinit.billing.v1.MsgCloseLease',
|
|
155
84
|
value: MsgCloseLease.fromPartial({
|
|
156
85
|
sender: senderAddress,
|
|
157
86
|
leaseUuids,
|
|
158
|
-
reason,
|
|
87
|
+
reason: reason ?? '',
|
|
159
88
|
}),
|
|
160
89
|
};
|
|
161
90
|
|
|
@@ -164,57 +93,34 @@ export async function routeBillingTransaction(
|
|
|
164
93
|
}
|
|
165
94
|
|
|
166
95
|
case 'withdraw': {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
{ usage }
|
|
173
|
-
);
|
|
174
|
-
}
|
|
96
|
+
requireArgs(args, 1, ['lease-uuid or --provider'], 'billing withdraw');
|
|
97
|
+
|
|
98
|
+
// Extract flags
|
|
99
|
+
const providerFlag = extractFlag(args, '--provider', 'billing withdraw');
|
|
100
|
+
const limitFlag = extractFlag(args, '--limit', 'billing withdraw');
|
|
175
101
|
|
|
176
|
-
// Check if using provider-wide withdrawal
|
|
177
|
-
const providerFlagIndex = args.indexOf('--provider');
|
|
178
|
-
const limitFlagIndex = args.indexOf('--limit');
|
|
179
102
|
let leaseUuids: string[] = [];
|
|
180
103
|
let providerUuid = '';
|
|
181
104
|
let limit = BigInt(0); // 0 means use default (50)
|
|
182
105
|
|
|
183
|
-
if (
|
|
106
|
+
if (providerFlag.value) {
|
|
184
107
|
// Provider-wide withdrawal mode
|
|
185
|
-
providerUuid =
|
|
186
|
-
if (!providerUuid || providerUuid.startsWith('--')) {
|
|
187
|
-
throw new ManifestMCPError(
|
|
188
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
189
|
-
'withdraw with --provider flag requires provider-uuid argument'
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Track consumed arg indices to detect extra arguments
|
|
194
|
-
const consumedIndices = new Set<number>([providerFlagIndex, providerFlagIndex + 1]);
|
|
108
|
+
providerUuid = providerFlag.value;
|
|
195
109
|
|
|
196
110
|
// Parse optional --limit flag (only valid with --provider)
|
|
197
|
-
if (
|
|
198
|
-
|
|
199
|
-
if (!limitStr || limitStr.startsWith('--')) {
|
|
200
|
-
throw new ManifestMCPError(
|
|
201
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
202
|
-
'withdraw with --limit flag requires a number argument (1-100)'
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
limit = parseBigInt(limitStr, 'limit');
|
|
111
|
+
if (limitFlag.value) {
|
|
112
|
+
limit = parseBigInt(limitFlag.value, 'limit');
|
|
206
113
|
if (limit < BigInt(1) || limit > BigInt(100)) {
|
|
207
114
|
throw new ManifestMCPError(
|
|
208
115
|
ManifestMCPErrorCode.TX_FAILED,
|
|
209
116
|
`Invalid limit: ${limit}. Must be between 1 and 100.`
|
|
210
117
|
);
|
|
211
118
|
}
|
|
212
|
-
consumedIndices.add(limitFlagIndex);
|
|
213
|
-
consumedIndices.add(limitFlagIndex + 1);
|
|
214
119
|
}
|
|
215
120
|
|
|
216
121
|
// Check for any extra arguments that weren't consumed
|
|
217
|
-
const
|
|
122
|
+
const allConsumed = [...providerFlag.consumedIndices, ...limitFlag.consumedIndices];
|
|
123
|
+
const extraArgs = filterConsumedArgs(args, allConsumed);
|
|
218
124
|
if (extraArgs.length > 0) {
|
|
219
125
|
const usage = getSubcommandUsage('tx', 'billing', 'withdraw');
|
|
220
126
|
throw new ManifestMCPError(
|
|
@@ -226,7 +132,7 @@ export async function routeBillingTransaction(
|
|
|
226
132
|
}
|
|
227
133
|
} else {
|
|
228
134
|
// Lease-specific withdrawal mode
|
|
229
|
-
// Check for unexpected flags
|
|
135
|
+
// Check for unexpected flags (--limit without --provider is invalid)
|
|
230
136
|
const unexpectedFlags = args.filter(arg => arg.startsWith('--'));
|
|
231
137
|
if (unexpectedFlags.length > 0) {
|
|
232
138
|
const usage = getSubcommandUsage('tx', 'billing', 'withdraw');
|
|
@@ -238,14 +144,6 @@ export async function routeBillingTransaction(
|
|
|
238
144
|
}
|
|
239
145
|
|
|
240
146
|
leaseUuids = args;
|
|
241
|
-
|
|
242
|
-
if (leaseUuids.length === 0) {
|
|
243
|
-
const usage = getSubcommandUsage('tx', 'billing', 'withdraw');
|
|
244
|
-
throw new ManifestMCPError(
|
|
245
|
-
ManifestMCPErrorCode.TX_FAILED,
|
|
246
|
-
`withdraw requires at least one lease-uuid. Usage: withdraw ${usage ?? '<args>'}`
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
147
|
}
|
|
250
148
|
|
|
251
149
|
const msg = {
|
|
@@ -262,11 +160,127 @@ export async function routeBillingTransaction(
|
|
|
262
160
|
return buildTxResult('billing', 'withdraw', result, waitForConfirmation);
|
|
263
161
|
}
|
|
264
162
|
|
|
163
|
+
case 'create-lease-for-tenant': {
|
|
164
|
+
// Parse optional --meta-hash flag
|
|
165
|
+
const { value: metaHashHex, consumedIndices } = extractFlag(args, '--meta-hash', 'billing create-lease-for-tenant');
|
|
166
|
+
const metaHash = metaHashHex ? parseHexBytes(metaHashHex, 'meta-hash', MAX_META_HASH_BYTES) : undefined;
|
|
167
|
+
|
|
168
|
+
// Filter out --meta-hash and its value to get remaining args
|
|
169
|
+
const remainingArgs = filterConsumedArgs(args, consumedIndices);
|
|
170
|
+
requireArgs(remainingArgs, 2, ['tenant-address', 'sku-uuid:quantity'], 'billing create-lease-for-tenant');
|
|
171
|
+
|
|
172
|
+
const [tenant, ...itemArgs] = remainingArgs;
|
|
173
|
+
validateAddress(tenant, 'tenant address');
|
|
174
|
+
|
|
175
|
+
// Parse items (format: sku-uuid:quantity ...)
|
|
176
|
+
const items = itemArgs.map((arg) => {
|
|
177
|
+
const [skuUuid, quantityStr] = parseColonPair(arg, 'sku-uuid', 'quantity', 'lease item');
|
|
178
|
+
return { skuUuid, quantity: parseBigInt(quantityStr, 'quantity') };
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const msg = {
|
|
182
|
+
typeUrl: '/liftedinit.billing.v1.MsgCreateLeaseForTenant',
|
|
183
|
+
value: MsgCreateLeaseForTenant.fromPartial({
|
|
184
|
+
authority: senderAddress,
|
|
185
|
+
tenant,
|
|
186
|
+
items,
|
|
187
|
+
metaHash: metaHash ?? new Uint8Array(),
|
|
188
|
+
}),
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const result = await client.signAndBroadcast(senderAddress, [msg], 'auto');
|
|
192
|
+
return buildTxResult('billing', 'create-lease-for-tenant', result, waitForConfirmation);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
case 'acknowledge-lease': {
|
|
196
|
+
requireArgs(args, 1, ['lease-uuid'], 'billing acknowledge-lease');
|
|
197
|
+
const leaseUuids = args;
|
|
198
|
+
|
|
199
|
+
const msg = {
|
|
200
|
+
typeUrl: '/liftedinit.billing.v1.MsgAcknowledgeLease',
|
|
201
|
+
value: MsgAcknowledgeLease.fromPartial({
|
|
202
|
+
sender: senderAddress,
|
|
203
|
+
leaseUuids,
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const result = await client.signAndBroadcast(senderAddress, [msg], 'auto');
|
|
208
|
+
return buildTxResult('billing', 'acknowledge-lease', result, waitForConfirmation);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
case 'reject-lease': {
|
|
212
|
+
// Parse optional --reason flag
|
|
213
|
+
const { value: reason, consumedIndices } = extractFlag(args, '--reason', 'billing reject-lease');
|
|
214
|
+
const leaseArgs = filterConsumedArgs(args, consumedIndices);
|
|
215
|
+
requireArgs(leaseArgs, 1, ['lease-uuid'], 'billing reject-lease');
|
|
216
|
+
|
|
217
|
+
const leaseUuids = leaseArgs;
|
|
218
|
+
|
|
219
|
+
const msg = {
|
|
220
|
+
typeUrl: '/liftedinit.billing.v1.MsgRejectLease',
|
|
221
|
+
value: MsgRejectLease.fromPartial({
|
|
222
|
+
sender: senderAddress,
|
|
223
|
+
leaseUuids,
|
|
224
|
+
reason: reason ?? '',
|
|
225
|
+
}),
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const result = await client.signAndBroadcast(senderAddress, [msg], 'auto');
|
|
229
|
+
return buildTxResult('billing', 'reject-lease', result, waitForConfirmation);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
case 'cancel-lease': {
|
|
233
|
+
requireArgs(args, 1, ['lease-uuid'], 'billing cancel-lease');
|
|
234
|
+
const leaseUuids = args;
|
|
235
|
+
|
|
236
|
+
const msg = {
|
|
237
|
+
typeUrl: '/liftedinit.billing.v1.MsgCancelLease',
|
|
238
|
+
value: MsgCancelLease.fromPartial({
|
|
239
|
+
tenant: senderAddress,
|
|
240
|
+
leaseUuids,
|
|
241
|
+
}),
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const result = await client.signAndBroadcast(senderAddress, [msg], 'auto');
|
|
245
|
+
return buildTxResult('billing', 'cancel-lease', result, waitForConfirmation);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
case 'update-params': {
|
|
249
|
+
requireArgs(args, 5, [
|
|
250
|
+
'max-leases-per-tenant', 'max-items-per-lease', 'min-lease-duration',
|
|
251
|
+
'max-pending-leases-per-tenant', 'pending-timeout',
|
|
252
|
+
], 'billing update-params');
|
|
253
|
+
|
|
254
|
+
const [
|
|
255
|
+
maxLeasesPerTenantStr, maxItemsPerLeaseStr, minLeaseDurationStr,
|
|
256
|
+
maxPendingLeasesPerTenantStr, pendingTimeoutStr,
|
|
257
|
+
...allowedAddresses
|
|
258
|
+
] = args;
|
|
259
|
+
|
|
260
|
+
for (const addr of allowedAddresses) {
|
|
261
|
+
validateAddress(addr, 'allowed address');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const msg = {
|
|
265
|
+
typeUrl: '/liftedinit.billing.v1.MsgUpdateParams',
|
|
266
|
+
value: MsgUpdateParams.fromPartial({
|
|
267
|
+
authority: senderAddress,
|
|
268
|
+
params: {
|
|
269
|
+
maxLeasesPerTenant: parseBigInt(maxLeasesPerTenantStr, 'max-leases-per-tenant'),
|
|
270
|
+
maxItemsPerLease: parseBigInt(maxItemsPerLeaseStr, 'max-items-per-lease'),
|
|
271
|
+
minLeaseDuration: parseBigInt(minLeaseDurationStr, 'min-lease-duration'),
|
|
272
|
+
maxPendingLeasesPerTenant: parseBigInt(maxPendingLeasesPerTenantStr, 'max-pending-leases-per-tenant'),
|
|
273
|
+
pendingTimeout: parseBigInt(pendingTimeoutStr, 'pending-timeout'),
|
|
274
|
+
allowedList: allowedAddresses,
|
|
275
|
+
},
|
|
276
|
+
}),
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const result = await client.signAndBroadcast(senderAddress, [msg], 'auto');
|
|
280
|
+
return buildTxResult('billing', 'update-params', result, waitForConfirmation);
|
|
281
|
+
}
|
|
282
|
+
|
|
265
283
|
default:
|
|
266
|
-
|
|
267
|
-
ManifestMCPErrorCode.UNSUPPORTED_TX,
|
|
268
|
-
`Unsupported billing transaction subcommand: ${subcommand}`,
|
|
269
|
-
{ availableSubcommands: ['fund-credit', 'create-lease', 'close-lease', 'withdraw'] }
|
|
270
|
-
);
|
|
284
|
+
throwUnsupportedSubcommand('tx', 'billing', subcommand);
|
|
271
285
|
}
|
|
272
286
|
}
|