@manifest-network/manifest-mcp-browser 0.1.0

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.
Files changed (156) hide show
  1. package/.claude/settings.local.json +17 -0
  2. package/.github/workflows/ci.yml +37 -0
  3. package/.github/workflows/publish.yml +51 -0
  4. package/CLAUDE.md +104 -0
  5. package/LICENSE +21 -0
  6. package/README.md +298 -0
  7. package/dist/browser.d.ts.map +1 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/client.d.ts +44 -0
  10. package/dist/client.d.ts.map +1 -0
  11. package/dist/client.js +131 -0
  12. package/dist/client.js.map +1 -0
  13. package/dist/config.d.ts +21 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +98 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/config.test.d.ts +2 -0
  18. package/dist/config.test.d.ts.map +1 -0
  19. package/dist/config.test.js +123 -0
  20. package/dist/config.test.js.map +1 -0
  21. package/dist/cosmos.d.ts +11 -0
  22. package/dist/cosmos.d.ts.map +1 -0
  23. package/dist/cosmos.js +112 -0
  24. package/dist/cosmos.js.map +1 -0
  25. package/dist/index.d.ts +70 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +382 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/modules.d.ts +30 -0
  30. package/dist/modules.d.ts.map +1 -0
  31. package/dist/modules.js +221 -0
  32. package/dist/modules.js.map +1 -0
  33. package/dist/modules.test.d.ts +2 -0
  34. package/dist/modules.test.d.ts.map +1 -0
  35. package/dist/modules.test.js +100 -0
  36. package/dist/modules.test.js.map +1 -0
  37. package/dist/queries/auth.d.ts +6 -0
  38. package/dist/queries/auth.d.ts.map +1 -0
  39. package/dist/queries/auth.js +93 -0
  40. package/dist/queries/auth.js.map +1 -0
  41. package/dist/queries/bank.d.ts +6 -0
  42. package/dist/queries/bank.d.ts.map +1 -0
  43. package/dist/queries/bank.js +83 -0
  44. package/dist/queries/bank.js.map +1 -0
  45. package/dist/queries/billing.d.ts +6 -0
  46. package/dist/queries/billing.d.ts.map +1 -0
  47. package/dist/queries/billing.js +115 -0
  48. package/dist/queries/billing.js.map +1 -0
  49. package/dist/queries/distribution.d.ts +6 -0
  50. package/dist/queries/distribution.d.ts.map +1 -0
  51. package/dist/queries/distribution.js +102 -0
  52. package/dist/queries/distribution.js.map +1 -0
  53. package/dist/queries/gov.d.ts +6 -0
  54. package/dist/queries/gov.d.ts.map +1 -0
  55. package/dist/queries/gov.js +92 -0
  56. package/dist/queries/gov.js.map +1 -0
  57. package/dist/queries/index.d.ts +8 -0
  58. package/dist/queries/index.d.ts.map +1 -0
  59. package/dist/queries/index.js +8 -0
  60. package/dist/queries/index.js.map +1 -0
  61. package/dist/queries/manifest.d.ts +10 -0
  62. package/dist/queries/manifest.d.ts.map +1 -0
  63. package/dist/queries/manifest.js +14 -0
  64. package/dist/queries/manifest.js.map +1 -0
  65. package/dist/queries/staking.d.ts +6 -0
  66. package/dist/queries/staking.d.ts.map +1 -0
  67. package/dist/queries/staking.js +141 -0
  68. package/dist/queries/staking.js.map +1 -0
  69. package/dist/queries/utils.d.ts +22 -0
  70. package/dist/queries/utils.d.ts.map +1 -0
  71. package/dist/queries/utils.js +32 -0
  72. package/dist/queries/utils.js.map +1 -0
  73. package/dist/queries/utils.test.d.ts +2 -0
  74. package/dist/queries/utils.test.d.ts.map +1 -0
  75. package/dist/queries/utils.test.js +57 -0
  76. package/dist/queries/utils.test.js.map +1 -0
  77. package/dist/transactions/bank.d.ts +7 -0
  78. package/dist/transactions/bank.d.ts.map +1 -0
  79. package/dist/transactions/bank.js +76 -0
  80. package/dist/transactions/bank.js.map +1 -0
  81. package/dist/transactions/billing.d.ts +7 -0
  82. package/dist/transactions/billing.d.ts.map +1 -0
  83. package/dist/transactions/billing.js +108 -0
  84. package/dist/transactions/billing.js.map +1 -0
  85. package/dist/transactions/distribution.d.ts +7 -0
  86. package/dist/transactions/distribution.d.ts.map +1 -0
  87. package/dist/transactions/distribution.js +63 -0
  88. package/dist/transactions/distribution.js.map +1 -0
  89. package/dist/transactions/gov.d.ts +7 -0
  90. package/dist/transactions/gov.d.ts.map +1 -0
  91. package/dist/transactions/gov.js +132 -0
  92. package/dist/transactions/gov.js.map +1 -0
  93. package/dist/transactions/index.d.ts +8 -0
  94. package/dist/transactions/index.d.ts.map +1 -0
  95. package/dist/transactions/index.js +8 -0
  96. package/dist/transactions/index.js.map +1 -0
  97. package/dist/transactions/manifest.d.ts +7 -0
  98. package/dist/transactions/manifest.d.ts.map +1 -0
  99. package/dist/transactions/manifest.js +58 -0
  100. package/dist/transactions/manifest.js.map +1 -0
  101. package/dist/transactions/staking.d.ts +7 -0
  102. package/dist/transactions/staking.d.ts.map +1 -0
  103. package/dist/transactions/staking.js +72 -0
  104. package/dist/transactions/staking.js.map +1 -0
  105. package/dist/transactions/utils.d.ts +40 -0
  106. package/dist/transactions/utils.d.ts.map +1 -0
  107. package/dist/transactions/utils.js +114 -0
  108. package/dist/transactions/utils.js.map +1 -0
  109. package/dist/transactions/utils.test.d.ts +2 -0
  110. package/dist/transactions/utils.test.d.ts.map +1 -0
  111. package/dist/transactions/utils.test.js +121 -0
  112. package/dist/transactions/utils.test.js.map +1 -0
  113. package/dist/types.d.ts +110 -0
  114. package/dist/types.d.ts.map +1 -0
  115. package/dist/types.js +55 -0
  116. package/dist/types.js.map +1 -0
  117. package/dist/wallet/index.d.ts +3 -0
  118. package/dist/wallet/index.d.ts.map +1 -0
  119. package/dist/wallet/index.js +2 -0
  120. package/dist/wallet/index.js.map +1 -0
  121. package/dist/wallet/keplr.d.ts.map +1 -0
  122. package/dist/wallet/keplr.js.map +1 -0
  123. package/dist/wallet/mnemonic.d.ts +40 -0
  124. package/dist/wallet/mnemonic.d.ts.map +1 -0
  125. package/dist/wallet/mnemonic.js +87 -0
  126. package/dist/wallet/mnemonic.js.map +1 -0
  127. package/package.json +40 -0
  128. package/src/client.ts +178 -0
  129. package/src/config.test.ts +143 -0
  130. package/src/config.ts +122 -0
  131. package/src/cosmos.ts +196 -0
  132. package/src/index.ts +484 -0
  133. package/src/modules.test.ts +127 -0
  134. package/src/modules.ts +278 -0
  135. package/src/queries/auth.ts +136 -0
  136. package/src/queries/bank.ts +117 -0
  137. package/src/queries/billing.ts +164 -0
  138. package/src/queries/distribution.ts +138 -0
  139. package/src/queries/gov.ts +128 -0
  140. package/src/queries/index.ts +7 -0
  141. package/src/queries/staking.ts +190 -0
  142. package/src/queries/utils.test.ts +61 -0
  143. package/src/queries/utils.ts +38 -0
  144. package/src/transactions/bank.ts +110 -0
  145. package/src/transactions/billing.ts +160 -0
  146. package/src/transactions/distribution.ts +98 -0
  147. package/src/transactions/gov.ts +185 -0
  148. package/src/transactions/index.ts +7 -0
  149. package/src/transactions/manifest.ts +89 -0
  150. package/src/transactions/staking.ts +107 -0
  151. package/src/transactions/utils.test.ts +129 -0
  152. package/src/transactions/utils.ts +156 -0
  153. package/src/types.ts +152 -0
  154. package/src/wallet/index.ts +2 -0
  155. package/src/wallet/mnemonic.ts +122 -0
  156. package/tsconfig.json +23 -0
@@ -0,0 +1,138 @@
1
+ import { ManifestQueryClient } from '../client.js';
2
+ import { ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
3
+ import { parseBigInt, defaultPagination } from './utils.js';
4
+
5
+ /**
6
+ * Route distribution query to manifestjs query client
7
+ */
8
+ export async function routeDistributionQuery(
9
+ queryClient: ManifestQueryClient,
10
+ subcommand: string,
11
+ args: string[]
12
+ ): Promise<Record<string, unknown>> {
13
+ const distribution = queryClient.cosmos.distribution.v1beta1;
14
+
15
+ switch (subcommand) {
16
+ case 'rewards': {
17
+ if (args.length < 1) {
18
+ throw new ManifestMCPError(
19
+ ManifestMCPErrorCode.QUERY_FAILED,
20
+ 'rewards requires delegator-address argument'
21
+ );
22
+ }
23
+ const [delegatorAddress] = args;
24
+ const validatorAddress = args[1];
25
+
26
+ if (validatorAddress) {
27
+ // Get rewards from specific validator
28
+ const result = await distribution.delegationRewards({
29
+ delegatorAddress,
30
+ validatorAddress,
31
+ });
32
+ return { rewards: result.rewards };
33
+ } else {
34
+ // Get rewards from all validators
35
+ const result = await distribution.delegationTotalRewards({ delegatorAddress });
36
+ return {
37
+ rewards: result.rewards,
38
+ total: result.total,
39
+ };
40
+ }
41
+ }
42
+
43
+ case 'commission': {
44
+ if (args.length < 1) {
45
+ throw new ManifestMCPError(
46
+ ManifestMCPErrorCode.QUERY_FAILED,
47
+ 'commission requires validator-address argument'
48
+ );
49
+ }
50
+ const [validatorAddress] = args;
51
+ const result = await distribution.validatorCommission({ validatorAddress });
52
+ return { commission: result.commission };
53
+ }
54
+
55
+ case 'community-pool': {
56
+ const result = await distribution.communityPool({});
57
+ return { pool: result.pool };
58
+ }
59
+
60
+ case 'params': {
61
+ const result = await distribution.params({});
62
+ return { params: result.params };
63
+ }
64
+
65
+ case 'validator-outstanding-rewards': {
66
+ if (args.length < 1) {
67
+ throw new ManifestMCPError(
68
+ ManifestMCPErrorCode.QUERY_FAILED,
69
+ 'validator-outstanding-rewards requires validator-address argument'
70
+ );
71
+ }
72
+ const [validatorAddress] = args;
73
+ const result = await distribution.validatorOutstandingRewards({ validatorAddress });
74
+ return { rewards: result.rewards };
75
+ }
76
+
77
+ case 'slashes': {
78
+ if (args.length < 1) {
79
+ throw new ManifestMCPError(
80
+ ManifestMCPErrorCode.QUERY_FAILED,
81
+ 'slashes requires validator-address argument'
82
+ );
83
+ }
84
+ const [validatorAddress] = args;
85
+ const startingHeight = args[1] ? parseBigInt(args[1], 'starting-height') : BigInt(0);
86
+ const endingHeight = args[2] ? parseBigInt(args[2], 'ending-height') : BigInt(Number.MAX_SAFE_INTEGER);
87
+ const result = await distribution.validatorSlashes({
88
+ validatorAddress,
89
+ startingHeight,
90
+ endingHeight,
91
+ pagination: defaultPagination,
92
+ });
93
+ return { slashes: result.slashes, pagination: result.pagination };
94
+ }
95
+
96
+ case 'delegator-validators': {
97
+ if (args.length < 1) {
98
+ throw new ManifestMCPError(
99
+ ManifestMCPErrorCode.QUERY_FAILED,
100
+ 'delegator-validators requires delegator-address argument'
101
+ );
102
+ }
103
+ const [delegatorAddress] = args;
104
+ const result = await distribution.delegatorValidators({ delegatorAddress });
105
+ return { validators: result.validators };
106
+ }
107
+
108
+ case 'delegator-withdraw-address': {
109
+ if (args.length < 1) {
110
+ throw new ManifestMCPError(
111
+ ManifestMCPErrorCode.QUERY_FAILED,
112
+ 'delegator-withdraw-address requires delegator-address argument'
113
+ );
114
+ }
115
+ const [delegatorAddress] = args;
116
+ const result = await distribution.delegatorWithdrawAddress({ delegatorAddress });
117
+ return { withdrawAddress: result.withdrawAddress };
118
+ }
119
+
120
+ default:
121
+ throw new ManifestMCPError(
122
+ ManifestMCPErrorCode.UNSUPPORTED_QUERY,
123
+ `Unsupported distribution query subcommand: ${subcommand}`,
124
+ {
125
+ availableSubcommands: [
126
+ 'rewards',
127
+ 'commission',
128
+ 'community-pool',
129
+ 'params',
130
+ 'validator-outstanding-rewards',
131
+ 'slashes',
132
+ 'delegator-validators',
133
+ 'delegator-withdraw-address',
134
+ ],
135
+ }
136
+ );
137
+ }
138
+ }
@@ -0,0 +1,128 @@
1
+ import { ManifestQueryClient } from '../client.js';
2
+ import { ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
3
+ import { parseBigInt, parseInt, defaultPagination } from './utils.js';
4
+
5
+ /**
6
+ * Route gov query to manifestjs query client
7
+ */
8
+ export async function routeGovQuery(
9
+ queryClient: ManifestQueryClient,
10
+ subcommand: string,
11
+ args: string[]
12
+ ): Promise<Record<string, unknown>> {
13
+ const gov = queryClient.cosmos.gov.v1;
14
+
15
+ switch (subcommand) {
16
+ case 'proposal': {
17
+ if (args.length < 1) {
18
+ throw new ManifestMCPError(
19
+ ManifestMCPErrorCode.QUERY_FAILED,
20
+ 'proposal requires proposal-id argument'
21
+ );
22
+ }
23
+ const proposalId = parseBigInt(args[0], 'proposal-id');
24
+ const result = await gov.proposal({ proposalId });
25
+ return { proposal: result.proposal };
26
+ }
27
+
28
+ case 'proposals': {
29
+ // Parse optional status filter
30
+ const proposalStatus = args[0] ? parseInt(args[0], 'status') : 0;
31
+ const voter = args[1] || '';
32
+ const depositor = args[2] || '';
33
+ const result = await gov.proposals({ proposalStatus, voter, depositor, pagination: defaultPagination });
34
+ return { proposals: result.proposals, pagination: result.pagination };
35
+ }
36
+
37
+ case 'vote': {
38
+ if (args.length < 2) {
39
+ throw new ManifestMCPError(
40
+ ManifestMCPErrorCode.QUERY_FAILED,
41
+ 'vote requires proposal-id and voter-address arguments'
42
+ );
43
+ }
44
+ const proposalId = parseBigInt(args[0], 'proposal-id');
45
+ const voter = args[1];
46
+ const result = await gov.vote({ proposalId, voter });
47
+ return { vote: result.vote };
48
+ }
49
+
50
+ case 'votes': {
51
+ if (args.length < 1) {
52
+ throw new ManifestMCPError(
53
+ ManifestMCPErrorCode.QUERY_FAILED,
54
+ 'votes requires proposal-id argument'
55
+ );
56
+ }
57
+ const proposalId = parseBigInt(args[0], 'proposal-id');
58
+ const result = await gov.votes({ proposalId, pagination: defaultPagination });
59
+ return { votes: result.votes, pagination: result.pagination };
60
+ }
61
+
62
+ case 'deposit': {
63
+ if (args.length < 2) {
64
+ throw new ManifestMCPError(
65
+ ManifestMCPErrorCode.QUERY_FAILED,
66
+ 'deposit requires proposal-id and depositor-address arguments'
67
+ );
68
+ }
69
+ const proposalId = parseBigInt(args[0], 'proposal-id');
70
+ const depositor = args[1];
71
+ const result = await gov.deposit({ proposalId, depositor });
72
+ return { deposit: result.deposit };
73
+ }
74
+
75
+ case 'deposits': {
76
+ if (args.length < 1) {
77
+ throw new ManifestMCPError(
78
+ ManifestMCPErrorCode.QUERY_FAILED,
79
+ 'deposits requires proposal-id argument'
80
+ );
81
+ }
82
+ const proposalId = parseBigInt(args[0], 'proposal-id');
83
+ const result = await gov.deposits({ proposalId, pagination: defaultPagination });
84
+ return { deposits: result.deposits, pagination: result.pagination };
85
+ }
86
+
87
+ case 'tally': {
88
+ if (args.length < 1) {
89
+ throw new ManifestMCPError(
90
+ ManifestMCPErrorCode.QUERY_FAILED,
91
+ 'tally requires proposal-id argument'
92
+ );
93
+ }
94
+ const proposalId = parseBigInt(args[0], 'proposal-id');
95
+ const result = await gov.tallyResult({ proposalId });
96
+ return { tally: result.tally };
97
+ }
98
+
99
+ case 'params': {
100
+ const paramsType = args[0] || 'tallying';
101
+ const result = await gov.params({ paramsType });
102
+ return {
103
+ votingParams: result.votingParams,
104
+ depositParams: result.depositParams,
105
+ tallyParams: result.tallyParams,
106
+ params: result.params,
107
+ };
108
+ }
109
+
110
+ default:
111
+ throw new ManifestMCPError(
112
+ ManifestMCPErrorCode.UNSUPPORTED_QUERY,
113
+ `Unsupported gov query subcommand: ${subcommand}`,
114
+ {
115
+ availableSubcommands: [
116
+ 'proposal',
117
+ 'proposals',
118
+ 'vote',
119
+ 'votes',
120
+ 'deposit',
121
+ 'deposits',
122
+ 'tally',
123
+ 'params',
124
+ ],
125
+ }
126
+ );
127
+ }
128
+ }
@@ -0,0 +1,7 @@
1
+ export { parseBigInt, parseInt, defaultPagination, DEFAULT_PAGE_LIMIT } from './utils.js';
2
+ export { routeBankQuery } from './bank.js';
3
+ export { routeStakingQuery } from './staking.js';
4
+ export { routeDistributionQuery } from './distribution.js';
5
+ export { routeGovQuery } from './gov.js';
6
+ export { routeAuthQuery } from './auth.js';
7
+ export { routeBillingQuery } from './billing.js';
@@ -0,0 +1,190 @@
1
+ import { ManifestQueryClient } from '../client.js';
2
+ import { ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
3
+ import { parseBigInt, defaultPagination } from './utils.js';
4
+
5
+ /**
6
+ * Route staking query to manifestjs query client
7
+ */
8
+ export async function routeStakingQuery(
9
+ queryClient: ManifestQueryClient,
10
+ subcommand: string,
11
+ args: string[]
12
+ ): Promise<Record<string, unknown>> {
13
+ const staking = queryClient.cosmos.staking.v1beta1;
14
+
15
+ switch (subcommand) {
16
+ case 'delegation': {
17
+ if (args.length < 2) {
18
+ throw new ManifestMCPError(
19
+ ManifestMCPErrorCode.QUERY_FAILED,
20
+ 'delegation requires delegator-address and validator-address arguments'
21
+ );
22
+ }
23
+ const [delegatorAddr, validatorAddr] = args;
24
+ const result = await staking.delegation({
25
+ delegatorAddr,
26
+ validatorAddr,
27
+ });
28
+ return { delegationResponse: result.delegationResponse };
29
+ }
30
+
31
+ case 'delegations': {
32
+ if (args.length < 1) {
33
+ throw new ManifestMCPError(
34
+ ManifestMCPErrorCode.QUERY_FAILED,
35
+ 'delegations requires delegator-address argument'
36
+ );
37
+ }
38
+ const [delegatorAddr] = args;
39
+ const result = await staking.delegatorDelegations({ delegatorAddr, pagination: defaultPagination });
40
+ return {
41
+ delegationResponses: result.delegationResponses,
42
+ pagination: result.pagination,
43
+ };
44
+ }
45
+
46
+ case 'unbonding-delegation': {
47
+ if (args.length < 2) {
48
+ throw new ManifestMCPError(
49
+ ManifestMCPErrorCode.QUERY_FAILED,
50
+ 'unbonding-delegation requires delegator-address and validator-address arguments'
51
+ );
52
+ }
53
+ const [delegatorAddr, validatorAddr] = args;
54
+ const result = await staking.unbondingDelegation({
55
+ delegatorAddr,
56
+ validatorAddr,
57
+ });
58
+ return { unbond: result.unbond };
59
+ }
60
+
61
+ case 'unbonding-delegations': {
62
+ if (args.length < 1) {
63
+ throw new ManifestMCPError(
64
+ ManifestMCPErrorCode.QUERY_FAILED,
65
+ 'unbonding-delegations requires delegator-address argument'
66
+ );
67
+ }
68
+ const [delegatorAddr] = args;
69
+ const result = await staking.delegatorUnbondingDelegations({ delegatorAddr, pagination: defaultPagination });
70
+ return {
71
+ unbondingResponses: result.unbondingResponses,
72
+ pagination: result.pagination,
73
+ };
74
+ }
75
+
76
+ case 'redelegations': {
77
+ if (args.length < 1) {
78
+ throw new ManifestMCPError(
79
+ ManifestMCPErrorCode.QUERY_FAILED,
80
+ 'redelegations requires delegator-address argument'
81
+ );
82
+ }
83
+ const [delegatorAddr] = args;
84
+ const srcValidatorAddr = args[1] || '';
85
+ const dstValidatorAddr = args[2] || '';
86
+ const result = await staking.redelegations({
87
+ delegatorAddr,
88
+ srcValidatorAddr,
89
+ dstValidatorAddr,
90
+ pagination: defaultPagination,
91
+ });
92
+ return {
93
+ redelegationResponses: result.redelegationResponses,
94
+ pagination: result.pagination,
95
+ };
96
+ }
97
+
98
+ case 'validator': {
99
+ if (args.length < 1) {
100
+ throw new ManifestMCPError(
101
+ ManifestMCPErrorCode.QUERY_FAILED,
102
+ 'validator requires validator-address argument'
103
+ );
104
+ }
105
+ const [validatorAddr] = args;
106
+ const result = await staking.validator({ validatorAddr });
107
+ return { validator: result.validator };
108
+ }
109
+
110
+ case 'validators': {
111
+ const status = args[0] || '';
112
+ const result = await staking.validators({ status, pagination: defaultPagination });
113
+ return { validators: result.validators, pagination: result.pagination };
114
+ }
115
+
116
+ case 'validator-delegations': {
117
+ if (args.length < 1) {
118
+ throw new ManifestMCPError(
119
+ ManifestMCPErrorCode.QUERY_FAILED,
120
+ 'validator-delegations requires validator-address argument'
121
+ );
122
+ }
123
+ const [validatorAddr] = args;
124
+ const result = await staking.validatorDelegations({ validatorAddr, pagination: defaultPagination });
125
+ return {
126
+ delegationResponses: result.delegationResponses,
127
+ pagination: result.pagination,
128
+ };
129
+ }
130
+
131
+ case 'validator-unbonding-delegations': {
132
+ if (args.length < 1) {
133
+ throw new ManifestMCPError(
134
+ ManifestMCPErrorCode.QUERY_FAILED,
135
+ 'validator-unbonding-delegations requires validator-address argument'
136
+ );
137
+ }
138
+ const [validatorAddr] = args;
139
+ const result = await staking.validatorUnbondingDelegations({ validatorAddr, pagination: defaultPagination });
140
+ return {
141
+ unbondingResponses: result.unbondingResponses,
142
+ pagination: result.pagination,
143
+ };
144
+ }
145
+
146
+ case 'pool': {
147
+ const result = await staking.pool({});
148
+ return { pool: result.pool };
149
+ }
150
+
151
+ case 'params': {
152
+ const result = await staking.params({});
153
+ return { params: result.params };
154
+ }
155
+
156
+ case 'historical-info': {
157
+ if (args.length < 1) {
158
+ throw new ManifestMCPError(
159
+ ManifestMCPErrorCode.QUERY_FAILED,
160
+ 'historical-info requires height argument'
161
+ );
162
+ }
163
+ const height = parseBigInt(args[0], 'height');
164
+ const result = await staking.historicalInfo({ height });
165
+ return { hist: result.hist };
166
+ }
167
+
168
+ default:
169
+ throw new ManifestMCPError(
170
+ ManifestMCPErrorCode.UNSUPPORTED_QUERY,
171
+ `Unsupported staking query subcommand: ${subcommand}`,
172
+ {
173
+ availableSubcommands: [
174
+ 'delegation',
175
+ 'delegations',
176
+ 'unbonding-delegation',
177
+ 'unbonding-delegations',
178
+ 'redelegations',
179
+ 'validator',
180
+ 'validators',
181
+ 'validator-delegations',
182
+ 'validator-unbonding-delegations',
183
+ 'pool',
184
+ 'params',
185
+ 'historical-info',
186
+ ],
187
+ }
188
+ );
189
+ }
190
+ }
@@ -0,0 +1,61 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { parseBigInt, parseInt } from './utils.js';
3
+ import { ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
4
+
5
+ describe('parseBigInt', () => {
6
+ it('should parse valid integer strings', () => {
7
+ expect(parseBigInt('0', 'height')).toBe(BigInt(0));
8
+ expect(parseBigInt('123', 'height')).toBe(BigInt(123));
9
+ expect(parseBigInt('9999999999999999999', 'height')).toBe(BigInt('9999999999999999999'));
10
+ });
11
+
12
+ it('should throw ManifestMCPError for invalid integers', () => {
13
+ expect(() => parseBigInt('abc', 'height')).toThrow(ManifestMCPError);
14
+ expect(() => parseBigInt('12.34', 'height')).toThrow(ManifestMCPError);
15
+ });
16
+
17
+ it('should throw ManifestMCPError for empty string', () => {
18
+ // Empty string should be rejected for security (prevents accidental 0 values)
19
+ expect(() => parseBigInt('', 'height')).toThrow(ManifestMCPError);
20
+ expect(() => parseBigInt(' ', 'height')).toThrow(ManifestMCPError);
21
+ });
22
+
23
+ it('should have correct error code', () => {
24
+ try {
25
+ parseBigInt('invalid', 'height');
26
+ } catch (error) {
27
+ expect(error).toBeInstanceOf(ManifestMCPError);
28
+ expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.QUERY_FAILED);
29
+ }
30
+ });
31
+
32
+ it('should include field name in error message', () => {
33
+ try {
34
+ parseBigInt('invalid', 'block-height');
35
+ } catch (error) {
36
+ expect((error as ManifestMCPError).message).toContain('block-height');
37
+ }
38
+ });
39
+ });
40
+
41
+ describe('parseInt', () => {
42
+ it('should parse valid integer strings', () => {
43
+ expect(parseInt('0', 'status')).toBe(0);
44
+ expect(parseInt('123', 'status')).toBe(123);
45
+ expect(parseInt('-5', 'status')).toBe(-5);
46
+ });
47
+
48
+ it('should throw ManifestMCPError for invalid integers', () => {
49
+ expect(() => parseInt('', 'status')).toThrow(ManifestMCPError);
50
+ expect(() => parseInt('abc', 'status')).toThrow(ManifestMCPError);
51
+ });
52
+
53
+ it('should have correct error code', () => {
54
+ try {
55
+ parseInt('invalid', 'status');
56
+ } catch (error) {
57
+ expect(error).toBeInstanceOf(ManifestMCPError);
58
+ expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.QUERY_FAILED);
59
+ }
60
+ });
61
+ });
@@ -0,0 +1,38 @@
1
+ import { ManifestMCPError, ManifestMCPErrorCode } from '../types.js';
2
+ import { parseBigIntWithCode } from '../transactions/utils.js';
3
+
4
+ /** Default page size limit for paginated queries to prevent resource exhaustion */
5
+ export const DEFAULT_PAGE_LIMIT = BigInt(100);
6
+
7
+ /**
8
+ * Default pagination configuration for queries
9
+ * Uses Cosmos SDK pagination format
10
+ */
11
+ export const defaultPagination = {
12
+ key: new Uint8Array(),
13
+ offset: BigInt(0),
14
+ limit: DEFAULT_PAGE_LIMIT,
15
+ countTotal: false,
16
+ reverse: false,
17
+ };
18
+
19
+ /**
20
+ * Safely parse a string to BigInt with proper error handling (for queries)
21
+ */
22
+ export function parseBigInt(value: string, fieldName: string): bigint {
23
+ return parseBigIntWithCode(value, fieldName, ManifestMCPErrorCode.QUERY_FAILED);
24
+ }
25
+
26
+ /**
27
+ * Safely parse a string to integer with proper error handling
28
+ */
29
+ export function parseInt(value: string, fieldName: string): number {
30
+ const parsed = Number.parseInt(value, 10);
31
+ if (Number.isNaN(parsed)) {
32
+ throw new ManifestMCPError(
33
+ ManifestMCPErrorCode.QUERY_FAILED,
34
+ `Invalid ${fieldName}: "${value}". Expected a valid integer.`
35
+ );
36
+ }
37
+ return parsed;
38
+ }
@@ -0,0 +1,110 @@
1
+ import { SigningStargateClient } from '@cosmjs/stargate';
2
+ import { cosmos } from '@manifest-network/manifestjs';
3
+ import { ManifestMCPError, ManifestMCPErrorCode, CosmosTxResult, ManifestMCPConfig } from '../types.js';
4
+ import { parseAmount, buildTxResult, validateAddress, validateMemo, validateArgsLength } from './utils.js';
5
+
6
+ const { MsgSend, MsgMultiSend } = cosmos.bank.v1beta1;
7
+
8
+ /**
9
+ * Route bank transaction to appropriate handler
10
+ */
11
+ export async function routeBankTransaction(
12
+ client: SigningStargateClient,
13
+ senderAddress: string,
14
+ subcommand: string,
15
+ args: string[],
16
+ _config: ManifestMCPConfig,
17
+ waitForConfirmation: boolean
18
+ ): Promise<CosmosTxResult> {
19
+ validateArgsLength(args, 'bank transaction');
20
+
21
+ switch (subcommand) {
22
+ case 'send': {
23
+ if (args.length < 2) {
24
+ throw new ManifestMCPError(
25
+ ManifestMCPErrorCode.TX_FAILED,
26
+ 'send requires recipient-address and amount arguments'
27
+ );
28
+ }
29
+
30
+ const [recipientAddress, amountStr] = args;
31
+ validateAddress(recipientAddress, 'recipient address');
32
+ const { amount, denom } = parseAmount(amountStr);
33
+
34
+ // Extract optional memo from args
35
+ let memo = '';
36
+ const memoIndex = args.indexOf('--memo');
37
+ if (memoIndex !== -1 && args[memoIndex + 1]) {
38
+ memo = args[memoIndex + 1];
39
+ validateMemo(memo);
40
+ }
41
+
42
+ const msg = {
43
+ typeUrl: '/cosmos.bank.v1beta1.MsgSend',
44
+ value: MsgSend.fromPartial({
45
+ fromAddress: senderAddress,
46
+ toAddress: recipientAddress,
47
+ amount: [{ denom, amount }],
48
+ }),
49
+ };
50
+
51
+ const result = await client.signAndBroadcast(senderAddress, [msg], 'auto', memo);
52
+ return buildTxResult('bank', 'send', result, waitForConfirmation);
53
+ }
54
+
55
+ case 'multi-send': {
56
+ if (args.length < 2) {
57
+ throw new ManifestMCPError(
58
+ ManifestMCPErrorCode.TX_FAILED,
59
+ 'multi-send requires at least one recipient:amount pair'
60
+ );
61
+ }
62
+
63
+ // Parse format: multi-send recipient1:amount1 recipient2:amount2 ...
64
+ const outputs = args.map((arg) => {
65
+ const [address, amountStr] = arg.split(':');
66
+ if (!address || !amountStr) {
67
+ throw new ManifestMCPError(
68
+ ManifestMCPErrorCode.TX_FAILED,
69
+ `Invalid multi-send format: ${arg}. Expected format: address:amount`
70
+ );
71
+ }
72
+ validateAddress(address, 'recipient address');
73
+ const { amount, denom } = parseAmount(amountStr);
74
+ return { address, coins: [{ denom, amount }] };
75
+ });
76
+
77
+ // Calculate total input
78
+ const totalByDenom = new Map<string, bigint>();
79
+ for (const output of outputs) {
80
+ for (const coin of output.coins) {
81
+ const current = totalByDenom.get(coin.denom) || BigInt(0);
82
+ totalByDenom.set(coin.denom, current + BigInt(coin.amount));
83
+ }
84
+ }
85
+
86
+ const inputCoins = Array.from(totalByDenom.entries()).map(([denom, amount]) => ({
87
+ denom,
88
+ amount: amount.toString(),
89
+ }));
90
+
91
+ const msg = {
92
+ typeUrl: '/cosmos.bank.v1beta1.MsgMultiSend',
93
+ value: MsgMultiSend.fromPartial({
94
+ inputs: [{ address: senderAddress, coins: inputCoins }],
95
+ outputs,
96
+ }),
97
+ };
98
+
99
+ const result = await client.signAndBroadcast(senderAddress, [msg], 'auto');
100
+ return buildTxResult('bank', 'multi-send', result, waitForConfirmation);
101
+ }
102
+
103
+ default:
104
+ throw new ManifestMCPError(
105
+ ManifestMCPErrorCode.UNSUPPORTED_TX,
106
+ `Unsupported bank transaction subcommand: ${subcommand}`,
107
+ { availableSubcommands: ['send', 'multi-send'] }
108
+ );
109
+ }
110
+ }