@andrewkimjoseph/celina-sdk 0.2.11 → 0.3.1

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 (78) hide show
  1. package/README.md +3 -0
  2. package/build/abis/self-registry.d.ts +194 -0
  3. package/build/abis/self-registry.js +120 -0
  4. package/build/abis/self-registry.js.map +1 -0
  5. package/build/analytics/amplitude.d.ts +5 -0
  6. package/build/analytics/amplitude.js +56 -0
  7. package/build/analytics/amplitude.js.map +1 -0
  8. package/build/analytics/config.d.ts +7 -0
  9. package/build/analytics/config.js +30 -0
  10. package/build/analytics/config.js.map +1 -0
  11. package/build/analytics/mcp-tool-events.d.ts +5 -0
  12. package/build/analytics/mcp-tool-events.js +55 -0
  13. package/build/analytics/mcp-tool-events.js.map +1 -0
  14. package/build/analytics/wrap-service.d.ts +5 -0
  15. package/build/analytics/wrap-service.js +36 -0
  16. package/build/analytics/wrap-service.js.map +1 -0
  17. package/build/clients/carbon-rest.d.ts +17 -0
  18. package/build/clients/carbon-rest.js +59 -0
  19. package/build/clients/carbon-rest.js.map +1 -0
  20. package/build/clients/carbon-sdk.d.ts +31 -0
  21. package/build/clients/carbon-sdk.js +48 -0
  22. package/build/clients/carbon-sdk.js.map +1 -0
  23. package/build/clients/self-api.d.ts +82 -0
  24. package/build/clients/self-api.js +242 -0
  25. package/build/clients/self-api.js.map +1 -0
  26. package/build/config/carbon.d.ts +12 -0
  27. package/build/config/carbon.js +13 -0
  28. package/build/config/carbon.js.map +1 -0
  29. package/build/config/sdk-config.d.ts +14 -0
  30. package/build/config/sdk-config.js +16 -0
  31. package/build/config/sdk-config.js.map +1 -1
  32. package/build/config/self.d.ts +22 -0
  33. package/build/config/self.js +27 -0
  34. package/build/config/self.js.map +1 -0
  35. package/build/index.d.ts +16 -0
  36. package/build/index.js +27 -13
  37. package/build/index.js.map +1 -1
  38. package/build/services/carbon.service.d.ts +68 -0
  39. package/build/services/carbon.service.js +189 -0
  40. package/build/services/carbon.service.js.map +1 -0
  41. package/build/services/self-session-store.d.ts +19 -0
  42. package/build/services/self-session-store.js +28 -0
  43. package/build/services/self-session-store.js.map +1 -0
  44. package/build/services/self.service.d.ts +241 -0
  45. package/build/services/self.service.js +692 -0
  46. package/build/services/self.service.js.map +1 -0
  47. package/build/types/carbon.d.ts +31 -0
  48. package/build/types/carbon.js +2 -0
  49. package/build/types/carbon.js.map +1 -0
  50. package/build/utils/carbon-prepared-flow.d.ts +11 -0
  51. package/build/utils/carbon-prepared-flow.js +25 -0
  52. package/build/utils/carbon-prepared-flow.js.map +1 -0
  53. package/build/utils/carbon-rest-adapter.d.ts +8 -0
  54. package/build/utils/carbon-rest-adapter.js +72 -0
  55. package/build/utils/carbon-rest-adapter.js.map +1 -0
  56. package/build/utils/self-format.d.ts +28 -0
  57. package/build/utils/self-format.js +79 -0
  58. package/build/utils/self-format.js.map +1 -0
  59. package/build/utils/self-signing.d.ts +4 -0
  60. package/build/utils/self-signing.js +38 -0
  61. package/build/utils/self-signing.js.map +1 -0
  62. package/package.json +16 -2
  63. package/tests/README.md +72 -0
  64. package/tests/catalog/domains/blockchain.ts +91 -0
  65. package/tests/catalog/domains/carbon.ts +409 -0
  66. package/tests/catalog/domains/chain-ext.ts +219 -0
  67. package/tests/catalog/domains/defi.ts +264 -0
  68. package/tests/catalog/domains/self.ts +220 -0
  69. package/tests/catalog/domains/token.ts +74 -0
  70. package/tests/catalog/domains/transaction.ts +111 -0
  71. package/tests/catalog/index.ts +7 -0
  72. package/tests/catalog/operations.ts +48 -0
  73. package/tests/catalog/types.ts +27 -0
  74. package/tests/fixtures/mainnet.ts +93 -0
  75. package/tests/helpers/assert.ts +30 -0
  76. package/tests/helpers/env.ts +38 -0
  77. package/tests/helpers/gating.ts +36 -0
  78. package/tests/testing-entry.ts +22 -0
@@ -0,0 +1,409 @@
1
+ import type { OperationSpec } from "../types.js";
2
+ import { assertHasKeys } from "../../helpers/assert.js";
3
+
4
+ const CARBON_WALLET = "0x0000000000000000000000000000000000000001" as const;
5
+ const CELO = "0x471EcE3750Da237a93B120cEadFa0b8eA6E3E25";
6
+ const USDC = "0xcebA9300f2b948710d2653dd7D87747AdA2aA3b";
7
+
8
+ function carbonRead(
9
+ id: string,
10
+ tool: string,
11
+ invoke: OperationSpec["sdk"]["invoke"],
12
+ args: () => Record<string, unknown>,
13
+ keys: string[],
14
+ ): OperationSpec {
15
+ return {
16
+ id,
17
+ domain: "carbon",
18
+ layer: "read",
19
+ sdk: { invoke },
20
+ mcp: { tool, arguments: args },
21
+ assert: (result) => assertHasKeys(result, keys),
22
+ };
23
+ }
24
+
25
+ function carbonPrepare(
26
+ id: string,
27
+ tool: string,
28
+ invoke: OperationSpec["sdk"]["invoke"],
29
+ args: () => Record<string, unknown>,
30
+ ): OperationSpec {
31
+ return {
32
+ id,
33
+ domain: "carbon",
34
+ layer: "prepare",
35
+ sdk: { invoke },
36
+ mcp: { tool, arguments: args },
37
+ assert: (result) => assertHasKeys(result, ["status", "warnings"]),
38
+ skip: () =>
39
+ "Carbon prepare tools require valid strategy params; run manually with funded wallet",
40
+ };
41
+ }
42
+
43
+ export const carbonOperations: OperationSpec[] = [
44
+ carbonRead(
45
+ "carbon.getStrategies",
46
+ "get_carbon_strategies",
47
+ (c) => c.carbon.getStrategies(CARBON_WALLET),
48
+ () => ({ wallet_address: CARBON_WALLET }),
49
+ ["status", "warnings"],
50
+ ),
51
+ {
52
+ ...carbonRead(
53
+ "carbon.getStrategy",
54
+ "get_carbon_strategy",
55
+ (c) => c.carbon.getStrategy("1"),
56
+ () => ({ strategy_id: "1" }),
57
+ ["status", "warnings"],
58
+ ),
59
+ skip: () =>
60
+ "Requires an existing Carbon strategy id on Celo (set CELINA_CARBON_STRATEGY_ID)",
61
+ },
62
+ {
63
+ ...carbonRead(
64
+ "carbon.getTradeQuote",
65
+ "get_carbon_trade_quote",
66
+ (c) =>
67
+ c.carbon.getTradeQuote({
68
+ source_token: CELO,
69
+ target_token: USDC,
70
+ amount: 1,
71
+ is_trade_by_target: false,
72
+ }),
73
+ () => ({
74
+ source_token: CELO,
75
+ target_token: USDC,
76
+ amount: 1,
77
+ is_trade_by_target: false,
78
+ }),
79
+ ["status", "warnings"],
80
+ ),
81
+ skip: () =>
82
+ "Carbon get_trade_quote on Celo may fail upstream (ENS); run manually when API is healthy",
83
+ },
84
+ carbonRead(
85
+ "carbon.explorePair",
86
+ "explore_carbon_pair",
87
+ (c) => c.carbon.explorePair({ base_token: CELO, quote_token: USDC }),
88
+ () => ({ base_token: CELO, quote_token: USDC }),
89
+ ["status", "chain"],
90
+ ),
91
+ carbonRead(
92
+ "carbon.resolveToken",
93
+ "resolve_carbon_token",
94
+ (c) => c.carbon.resolveToken("USDC"),
95
+ () => ({ token: "USDC" }),
96
+ ["status", "warnings"],
97
+ ),
98
+ carbonRead(
99
+ "carbon.getActivity",
100
+ "get_carbon_activity",
101
+ (c) => c.carbon.getActivity({ wallet_address: CARBON_WALLET }),
102
+ () => ({ wallet_address: CARBON_WALLET }),
103
+ ["status", "warnings"],
104
+ ),
105
+ {
106
+ ...carbonRead(
107
+ "carbon.findOpportunities",
108
+ "find_carbon_opportunities",
109
+ (c) => c.carbon.findOpportunities({ base_token: CELO, quote_token: USDC }),
110
+ () => ({ base_token: CELO, quote_token: USDC }),
111
+ ["status", "warnings"],
112
+ ),
113
+ skip: () =>
114
+ "Carbon find_opportunities may require market data on Celo; run manually when API returns opportunities",
115
+ },
116
+ carbonRead(
117
+ "carbon.getProtocolStats",
118
+ "get_carbon_protocol_stats",
119
+ (c) => c.carbon.getProtocolStats({ period_days: 7 }),
120
+ () => ({ period_days: 7 }),
121
+ ["status", "chain"],
122
+ ),
123
+ {
124
+ ...carbonRead(
125
+ "carbon.getPriceHistory",
126
+ "get_carbon_price_history",
127
+ (c) =>
128
+ c.carbon.getPriceHistory({
129
+ base_token: CELO,
130
+ quote_token: USDC,
131
+ period_days: 7,
132
+ }),
133
+ () => ({ base_token: CELO, quote_token: USDC, period_days: 7 }),
134
+ ["status", "warnings"],
135
+ ),
136
+ skip: () =>
137
+ "Carbon get_price_history may return 400 for some Celo pairs; run manually when API is healthy",
138
+ },
139
+ {
140
+ ...carbonRead(
141
+ "carbon.simulateStrategy",
142
+ "simulate_carbon_strategy",
143
+ (c) =>
144
+ c.carbon.simulateStrategy({
145
+ base_token: CELO,
146
+ quote_token: USDC,
147
+ days: 7,
148
+ buy_price_low: 0.1,
149
+ buy_price_high: 0.2,
150
+ buy_budget: 10,
151
+ sell_price_low: 0.3,
152
+ sell_price_high: 0.4,
153
+ sell_budget: 5,
154
+ }),
155
+ () => ({
156
+ base_token: CELO,
157
+ quote_token: USDC,
158
+ days: 7,
159
+ buy_price_low: 0.1,
160
+ buy_price_high: 0.2,
161
+ buy_budget: 10,
162
+ sell_price_low: 0.3,
163
+ sell_price_high: 0.4,
164
+ sell_budget: 5,
165
+ }),
166
+ ["status", "warnings"],
167
+ ),
168
+ skip: () =>
169
+ "Carbon simulate_strategy may return 400 upstream on Celo; run manually when API is healthy",
170
+ },
171
+ carbonRead(
172
+ "carbon.help",
173
+ "carbon_help",
174
+ (c) => c.carbon.help("create_limit_order"),
175
+ () => ({ topic: "create_limit_order" }),
176
+ ["status"],
177
+ ),
178
+ carbonRead(
179
+ "carbon.learn",
180
+ "carbon_learn",
181
+ (c) => c.carbon.learn("recurring_strategy"),
182
+ () => ({ topic: "recurring_strategy" }),
183
+ ["status"],
184
+ ),
185
+ carbonPrepare(
186
+ "carbon.prepareLimitOrder",
187
+ "prepare_carbon_limit_order",
188
+ (c) =>
189
+ c.carbon.prepareLimitOrder({
190
+ wallet_address: CARBON_WALLET,
191
+ base_token: CELO,
192
+ quote_token: USDC,
193
+ direction: "buy",
194
+ price: 0.5,
195
+ budget: 10,
196
+ }),
197
+ () => ({
198
+ wallet_address: CARBON_WALLET,
199
+ base_token: CELO,
200
+ quote_token: USDC,
201
+ direction: "buy",
202
+ price: 0.5,
203
+ budget: 10,
204
+ }),
205
+ ),
206
+ carbonPrepare(
207
+ "carbon.prepareRangeOrder",
208
+ "prepare_carbon_range_order",
209
+ (c) =>
210
+ c.carbon.prepareRangeOrder({
211
+ wallet_address: CARBON_WALLET,
212
+ base_token: CELO,
213
+ quote_token: USDC,
214
+ direction: "buy",
215
+ price_low: 0.4,
216
+ price_high: 0.6,
217
+ budget: 10,
218
+ }),
219
+ () => ({
220
+ wallet_address: CARBON_WALLET,
221
+ base_token: CELO,
222
+ quote_token: USDC,
223
+ direction: "buy",
224
+ price_low: 0.4,
225
+ price_high: 0.6,
226
+ budget: 10,
227
+ }),
228
+ ),
229
+ carbonPrepare(
230
+ "carbon.prepareRecurringStrategy",
231
+ "prepare_carbon_recurring_strategy",
232
+ (c) =>
233
+ c.carbon.prepareRecurringStrategy({
234
+ wallet_address: CARBON_WALLET,
235
+ base_token: CELO,
236
+ quote_token: USDC,
237
+ buy_price_low: 0.4,
238
+ buy_price_high: 0.5,
239
+ buy_budget: 10,
240
+ sell_price_low: 0.6,
241
+ sell_price_high: 0.7,
242
+ sell_budget: 5,
243
+ }),
244
+ () => ({
245
+ wallet_address: CARBON_WALLET,
246
+ base_token: CELO,
247
+ quote_token: USDC,
248
+ buy_price_low: 0.4,
249
+ buy_price_high: 0.5,
250
+ buy_budget: 10,
251
+ sell_price_low: 0.6,
252
+ sell_price_high: 0.7,
253
+ sell_budget: 5,
254
+ }),
255
+ ),
256
+ carbonPrepare(
257
+ "carbon.prepareConcentratedStrategy",
258
+ "prepare_carbon_concentrated_strategy",
259
+ (c) =>
260
+ c.carbon.prepareConcentratedStrategy({
261
+ wallet_address: CARBON_WALLET,
262
+ base_token: CELO,
263
+ quote_token: USDC,
264
+ spread_percentage: 1,
265
+ buy_budget: 10,
266
+ sell_budget: 5,
267
+ }),
268
+ () => ({
269
+ wallet_address: CARBON_WALLET,
270
+ base_token: CELO,
271
+ quote_token: USDC,
272
+ spread_percentage: 1,
273
+ buy_budget: 10,
274
+ sell_budget: 5,
275
+ }),
276
+ ),
277
+ carbonPrepare(
278
+ "carbon.prepareFullRangeStrategy",
279
+ "prepare_carbon_full_range_strategy",
280
+ (c) =>
281
+ c.carbon.prepareFullRangeStrategy({
282
+ wallet_address: CARBON_WALLET,
283
+ base_token: CELO,
284
+ quote_token: USDC,
285
+ spread_percentage: 5,
286
+ buy_budget: 10,
287
+ sell_budget: 5,
288
+ }),
289
+ () => ({
290
+ wallet_address: CARBON_WALLET,
291
+ base_token: CELO,
292
+ quote_token: USDC,
293
+ spread_percentage: 5,
294
+ buy_budget: 10,
295
+ sell_budget: 5,
296
+ }),
297
+ ),
298
+ carbonPrepare(
299
+ "carbon.prepareRepriceStrategy",
300
+ "prepare_carbon_reprice_strategy",
301
+ (c) =>
302
+ c.carbon.prepareRepriceStrategy({
303
+ wallet_address: CARBON_WALLET,
304
+ strategy_id: "1",
305
+ buy_price_low: 0.4,
306
+ buy_price_high: 0.5,
307
+ }),
308
+ () => ({
309
+ wallet_address: CARBON_WALLET,
310
+ strategy_id: "1",
311
+ buy_price_low: 0.4,
312
+ buy_price_high: 0.5,
313
+ }),
314
+ ),
315
+ carbonPrepare(
316
+ "carbon.prepareEditStrategy",
317
+ "prepare_carbon_edit_strategy",
318
+ (c) =>
319
+ c.carbon.prepareEditStrategy({
320
+ wallet_address: CARBON_WALLET,
321
+ strategy_id: "1",
322
+ buy_budget: 10,
323
+ }),
324
+ () => ({
325
+ wallet_address: CARBON_WALLET,
326
+ strategy_id: "1",
327
+ buy_budget: 10,
328
+ }),
329
+ ),
330
+ carbonPrepare(
331
+ "carbon.prepareDepositBudget",
332
+ "prepare_carbon_deposit_budget",
333
+ (c) =>
334
+ c.carbon.prepareDepositBudget({
335
+ wallet_address: CARBON_WALLET,
336
+ strategy_id: "1",
337
+ buy_budget: 5,
338
+ }),
339
+ () => ({
340
+ wallet_address: CARBON_WALLET,
341
+ strategy_id: "1",
342
+ buy_budget: 5,
343
+ }),
344
+ ),
345
+ carbonPrepare(
346
+ "carbon.prepareWithdrawBudget",
347
+ "prepare_carbon_withdraw_budget",
348
+ (c) =>
349
+ c.carbon.prepareWithdrawBudget({
350
+ wallet_address: CARBON_WALLET,
351
+ strategy_id: "1",
352
+ buy_budget: 1,
353
+ }),
354
+ () => ({
355
+ wallet_address: CARBON_WALLET,
356
+ strategy_id: "1",
357
+ buy_budget: 1,
358
+ }),
359
+ ),
360
+ carbonPrepare(
361
+ "carbon.preparePauseStrategy",
362
+ "prepare_carbon_pause_strategy",
363
+ (c) =>
364
+ c.carbon.preparePauseStrategy({
365
+ wallet_address: CARBON_WALLET,
366
+ strategy_id: "1",
367
+ }),
368
+ () => ({ wallet_address: CARBON_WALLET, strategy_id: "1" }),
369
+ ),
370
+ carbonPrepare(
371
+ "carbon.prepareResumeStrategy",
372
+ "prepare_carbon_resume_strategy",
373
+ (c) =>
374
+ c.carbon.prepareResumeStrategy({
375
+ wallet_address: CARBON_WALLET,
376
+ strategy_id: "1",
377
+ }),
378
+ () => ({ wallet_address: CARBON_WALLET, strategy_id: "1" }),
379
+ ),
380
+ carbonPrepare(
381
+ "carbon.prepareDeleteStrategy",
382
+ "prepare_carbon_delete_strategy",
383
+ (c) =>
384
+ c.carbon.prepareDeleteStrategy({
385
+ wallet_address: CARBON_WALLET,
386
+ strategy_id: "1",
387
+ }),
388
+ () => ({ wallet_address: CARBON_WALLET, strategy_id: "1" }),
389
+ ),
390
+ carbonPrepare(
391
+ "carbon.prepareTrade",
392
+ "prepare_carbon_trade",
393
+ (c) =>
394
+ c.carbon.prepareTrade({
395
+ wallet_address: CARBON_WALLET,
396
+ source_token: CELO,
397
+ target_token: USDC,
398
+ amount: "1",
399
+ min_return: "0",
400
+ }),
401
+ () => ({
402
+ wallet_address: CARBON_WALLET,
403
+ source_token: CELO,
404
+ target_token: USDC,
405
+ amount: "1",
406
+ min_return: "0",
407
+ }),
408
+ ),
409
+ ];
@@ -0,0 +1,219 @@
1
+ import { expect } from "vitest";
2
+ import type { OperationSpec } from "../types.js";
3
+ import { assertArray, assertHasKeys } from "../../helpers/assert.js";
4
+
5
+ export const governanceOperations: OperationSpec[] = [
6
+ {
7
+ id: "governance.getGovernanceProposals",
8
+ domain: "governance",
9
+ layer: "read",
10
+ sdk: {
11
+ invoke: (client) =>
12
+ client.governance.getGovernanceProposals({ page: 1, pageSize: 5 }),
13
+ },
14
+ mcp: {
15
+ tool: "get_governance_proposals",
16
+ arguments: () => ({ page: 1, pageSize: 5 }),
17
+ },
18
+ assert: (result) => {
19
+ const obj = assertHasKeys(result, ["proposals", "pagination"]);
20
+ expect(Array.isArray(obj.proposals)).toBe(true);
21
+ },
22
+ },
23
+ {
24
+ id: "governance.getProposalDetails",
25
+ domain: "governance",
26
+ layer: "read",
27
+ sdk: {
28
+ invoke: (client, fx) =>
29
+ client.governance.getProposalDetails(fx.proposalId),
30
+ },
31
+ mcp: {
32
+ tool: "get_proposal_details",
33
+ arguments: (fx) => ({ proposalId: fx.proposalId }),
34
+ },
35
+ assert: (result) => {
36
+ assertHasKeys(result, ["proposal"]);
37
+ },
38
+ },
39
+ ];
40
+
41
+ export const stakingOperations: OperationSpec[] = [
42
+ {
43
+ id: "staking.getStakingBalances",
44
+ domain: "staking",
45
+ layer: "read",
46
+ sdk: {
47
+ invoke: (client, fx) => client.staking.getStakingBalances(fx.wallet),
48
+ },
49
+ mcp: {
50
+ tool: "get_staking_balances",
51
+ arguments: (fx) => ({ address: fx.wallet }),
52
+ },
53
+ assert: (result) => {
54
+ assertHasKeys(result, ["address", "groups"]);
55
+ },
56
+ },
57
+ {
58
+ id: "staking.getActivatableStakes",
59
+ domain: "staking",
60
+ layer: "read",
61
+ sdk: {
62
+ invoke: (client, fx) => client.staking.getActivatableStakes(fx.wallet),
63
+ },
64
+ mcp: {
65
+ tool: "get_activatable_stakes",
66
+ arguments: (fx) => ({ address: fx.wallet }),
67
+ },
68
+ assert: (result) => {
69
+ assertHasKeys(result, ["activatableGroups"]);
70
+ },
71
+ },
72
+ {
73
+ id: "staking.getValidatorGroups",
74
+ domain: "staking",
75
+ layer: "read",
76
+ sdk: {
77
+ invoke: (client) =>
78
+ client.staking.getValidatorGroups({ page: 1, pageSize: 5 }),
79
+ },
80
+ mcp: {
81
+ tool: "get_validator_groups",
82
+ arguments: () => ({ page: 1, pageSize: 5 }),
83
+ },
84
+ assert: (result) => {
85
+ const obj = assertHasKeys(result, ["groups"]);
86
+ assertArray(obj.groups);
87
+ },
88
+ },
89
+ {
90
+ id: "staking.getValidatorGroupDetails",
91
+ domain: "staking",
92
+ layer: "read",
93
+ sdk: {
94
+ invoke: (client, fx) =>
95
+ client.staking.getValidatorGroupDetails(fx.validatorGroup),
96
+ },
97
+ mcp: {
98
+ tool: "get_validator_group_details",
99
+ arguments: (fx) => ({ groupAddress: fx.validatorGroup }),
100
+ },
101
+ assert: (result) => {
102
+ assertHasKeys(result, ["address", "name"]);
103
+ },
104
+ },
105
+ {
106
+ id: "staking.getTotalStakingInfo",
107
+ domain: "staking",
108
+ layer: "read",
109
+ sdk: {
110
+ invoke: (client) => client.staking.getTotalStakingInfo(),
111
+ },
112
+ mcp: {
113
+ tool: "get_total_staking_info",
114
+ arguments: () => ({}),
115
+ },
116
+ assert: (result) => {
117
+ assertHasKeys(result, ["totalVotes"]);
118
+ },
119
+ },
120
+ ];
121
+
122
+ export const nftOperations: OperationSpec[] = [
123
+ {
124
+ id: "nft.getNftInfo",
125
+ domain: "nft",
126
+ layer: "read",
127
+ sdk: {
128
+ invoke: (client, fx) =>
129
+ client.nft.getNftInfo(fx.saidContract, fx.saidTokenId),
130
+ },
131
+ mcp: {
132
+ tool: "get_nft_info",
133
+ arguments: (fx) => ({
134
+ contractAddress: fx.saidContract,
135
+ tokenId: fx.saidTokenId,
136
+ }),
137
+ },
138
+ assert: (result) => {
139
+ assertHasKeys(result, ["contractAddress", "tokenId"]);
140
+ },
141
+ },
142
+ {
143
+ id: "nft.getNftBalance",
144
+ domain: "nft",
145
+ layer: "read",
146
+ sdk: {
147
+ invoke: (client, fx) =>
148
+ client.nft.getNftBalance(fx.saidContract, fx.saidOwner),
149
+ },
150
+ mcp: {
151
+ tool: "get_nft_balance",
152
+ arguments: (fx) => ({
153
+ contractAddress: fx.saidContract,
154
+ address: fx.saidOwner,
155
+ }),
156
+ },
157
+ assert: (result) => {
158
+ assertHasKeys(result, ["balance"]);
159
+ },
160
+ },
161
+ ];
162
+
163
+ export const contractOperations: OperationSpec[] = [
164
+ {
165
+ id: "contract.callFunction",
166
+ domain: "contract",
167
+ layer: "read",
168
+ sdk: {
169
+ invoke: (client, fx) =>
170
+ client.contract.callFunction({
171
+ contractAddress: fx.usdm,
172
+ abi: fx.erc20SymbolAbi,
173
+ functionName: "symbol",
174
+ functionArgs: [],
175
+ }),
176
+ },
177
+ mcp: {
178
+ tool: "call_contract_function",
179
+ arguments: (fx) => ({
180
+ contractAddress: fx.usdm,
181
+ abi: fx.erc20SymbolAbi,
182
+ functionName: "symbol",
183
+ functionArgs: [],
184
+ }),
185
+ },
186
+ assert: (result) => {
187
+ assertHasKeys(result, ["result"]);
188
+ },
189
+ },
190
+ {
191
+ id: "contract.estimateGas",
192
+ domain: "contract",
193
+ layer: "read",
194
+ requiresEnv: ["CELO_PRIVATE_KEY"],
195
+ sdk: {
196
+ invoke: (client, fx) =>
197
+ client.contract.estimateGas({
198
+ contractAddress: fx.usdm,
199
+ abi: fx.erc20SymbolAbi,
200
+ functionName: "symbol",
201
+ functionArgs: [],
202
+ fromAddress: fx.signerAddress ?? fx.wallet,
203
+ }),
204
+ },
205
+ mcp: {
206
+ tool: "estimate_contract_gas",
207
+ arguments: (fx) => ({
208
+ contractAddress: fx.usdm,
209
+ abi: fx.erc20SymbolAbi,
210
+ functionName: "symbol",
211
+ functionArgs: [],
212
+ fromAddress: fx.signerAddress ?? fx.wallet,
213
+ }),
214
+ },
215
+ assert: (result) => {
216
+ assertHasKeys(result, ["gasEstimate"]);
217
+ },
218
+ },
219
+ ];