@hivemind-os/collective-mcp-server 0.2.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.
- package/.turbo/turbo-build.log +14 -0
- package/dist/index.d.ts +493 -0
- package/dist/index.js +2129 -0
- package/dist/index.js.map +1 -0
- package/package.json +31 -0
- package/src/context.ts +58 -0
- package/src/encryption.ts +25 -0
- package/src/index.ts +41 -0
- package/src/resources/agent.ts +77 -0
- package/src/resources/capabilities.ts +24 -0
- package/src/resources/index.ts +70 -0
- package/src/resources/task.ts +58 -0
- package/src/resources/wallet.ts +32 -0
- package/src/tools/analytics.ts +122 -0
- package/src/tools/balance.ts +36 -0
- package/src/tools/deactivate.ts +33 -0
- package/src/tools/discover.ts +256 -0
- package/src/tools/dispute.ts +135 -0
- package/src/tools/execute-async.ts +39 -0
- package/src/tools/execute.ts +418 -0
- package/src/tools/index.ts +152 -0
- package/src/tools/indexer-client.ts +163 -0
- package/src/tools/marketplace-accept-bid.ts +43 -0
- package/src/tools/marketplace-bid.ts +56 -0
- package/src/tools/marketplace-browse.ts +66 -0
- package/src/tools/marketplace-post.ts +96 -0
- package/src/tools/metering.ts +214 -0
- package/src/tools/multi-execute.ts +218 -0
- package/src/tools/policy-update.ts +94 -0
- package/src/tools/register.ts +78 -0
- package/src/tools/relay-registry.ts +95 -0
- package/src/tools/stake.ts +103 -0
- package/src/tools/task-history.ts +86 -0
- package/src/tools/task-status.ts +66 -0
- package/tests/analytics.test.ts +41 -0
- package/tests/auth-errors.test.ts +85 -0
- package/tests/balance.test.ts +32 -0
- package/tests/context.test.ts +112 -0
- package/tests/discover.test.ts +207 -0
- package/tests/dispute.test.ts +140 -0
- package/tests/execute.test.ts +150 -0
- package/tests/marketplace.test.ts +117 -0
- package/tests/metering.test.ts +173 -0
- package/tests/multi-execute.test.ts +123 -0
- package/tests/relay-registry.test.ts +71 -0
- package/tests/stake.test.ts +90 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +10 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { createMeteredResultEnvelope, serializeMeteredResultEnvelope, UsageMeter } from '@hivemind-os/collective-core';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { PaymentRail, PaymentScheme, TaskStatus, type AgentCard } from '@hivemind-os/collective-types';
|
|
5
|
+
|
|
6
|
+
import { runMeshMeteredExecute, runMeshVerifyResult } from '../src/tools/metering.js';
|
|
7
|
+
|
|
8
|
+
function createAgent(): AgentCard {
|
|
9
|
+
return {
|
|
10
|
+
id: 'agent-1',
|
|
11
|
+
owner: 'owner',
|
|
12
|
+
did: 'did:mesh:provider' as AgentCard['did'],
|
|
13
|
+
name: 'Provider',
|
|
14
|
+
description: 'Test provider',
|
|
15
|
+
active: true,
|
|
16
|
+
version: 1,
|
|
17
|
+
registeredAt: Date.now(),
|
|
18
|
+
updatedAt: Date.now(),
|
|
19
|
+
endpoint: 'mesh://agent/provider',
|
|
20
|
+
capabilities: [
|
|
21
|
+
{
|
|
22
|
+
name: 'echo',
|
|
23
|
+
description: 'Echo capability',
|
|
24
|
+
version: '1.0.0',
|
|
25
|
+
pricing: {
|
|
26
|
+
rail: PaymentRail.SUI_ESCROW,
|
|
27
|
+
amount: 5n,
|
|
28
|
+
currency: 'MIST',
|
|
29
|
+
},
|
|
30
|
+
executionMode: 'async',
|
|
31
|
+
paymentRails: [PaymentRail.SUI_ESCROW],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createMeteredBlob(result: string) {
|
|
38
|
+
const resultBytes = new TextEncoder().encode(result);
|
|
39
|
+
const meter = new UsageMeter({ taskId: 'task-1', maxPrice: 10n, unitPrice: 2n });
|
|
40
|
+
meter.recordUnit(resultBytes);
|
|
41
|
+
return serializeMeteredResultEnvelope(createMeteredResultEnvelope(resultBytes, meter.getProof(), resultBytes.length));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function createContext(agent: AgentCard) {
|
|
45
|
+
const resultBlob = createMeteredBlob('verified-result');
|
|
46
|
+
return {
|
|
47
|
+
keypair: {} as never,
|
|
48
|
+
blobStore: {
|
|
49
|
+
store: vi.fn(async () => ({ blobId: 'blob-in' })),
|
|
50
|
+
fetch: vi.fn(async () => resultBlob),
|
|
51
|
+
},
|
|
52
|
+
taskClient: {
|
|
53
|
+
postMeteredTask: vi.fn(async () => ({ taskId: 'task-1' })),
|
|
54
|
+
getTask: vi.fn(async () => ({
|
|
55
|
+
id: 'task-1',
|
|
56
|
+
requester: '0xrequester',
|
|
57
|
+
provider: '0xprovider',
|
|
58
|
+
capability: 'echo',
|
|
59
|
+
category: 'general',
|
|
60
|
+
inputBlobId: 'blob-in',
|
|
61
|
+
resultBlobId: 'blob-out',
|
|
62
|
+
price: 2n,
|
|
63
|
+
paymentScheme: PaymentScheme.UPTO,
|
|
64
|
+
maxPrice: 10n,
|
|
65
|
+
meteredUnits: 1,
|
|
66
|
+
unitPrice: 2n,
|
|
67
|
+
verificationHash: new UsageMeter({ taskId: 'task-1', maxPrice: 10n, unitPrice: 2n }).getVerificationHash(),
|
|
68
|
+
status: TaskStatus.COMPLETED,
|
|
69
|
+
disputeWindowMs: 1,
|
|
70
|
+
createdAt: 1,
|
|
71
|
+
expiresAt: 2,
|
|
72
|
+
agreementHash: 'metered:echo',
|
|
73
|
+
})),
|
|
74
|
+
releaseMeteredPayment: vi.fn(async () => undefined),
|
|
75
|
+
},
|
|
76
|
+
agentCache: {
|
|
77
|
+
searchByCapability: vi.fn(() => [agent]),
|
|
78
|
+
getAgentByDID: vi.fn((did: string) => (did === agent.did ? agent : undefined)),
|
|
79
|
+
upsertAgent: vi.fn(),
|
|
80
|
+
},
|
|
81
|
+
registryClient: {
|
|
82
|
+
discoverByCapability: vi.fn(async () => []),
|
|
83
|
+
getAgentCardByOwner: vi.fn(async () => null),
|
|
84
|
+
},
|
|
85
|
+
spendingPolicy: {
|
|
86
|
+
evaluate: vi.fn(() => ({ approved: true })),
|
|
87
|
+
record: vi.fn(),
|
|
88
|
+
},
|
|
89
|
+
relayAuthProvider: undefined,
|
|
90
|
+
x402Client: undefined,
|
|
91
|
+
logger: {
|
|
92
|
+
warn: vi.fn(),
|
|
93
|
+
},
|
|
94
|
+
blob: resultBlob,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
describe('metering tools', () => {
|
|
99
|
+
it('executes a metered task and verifies the result', async () => {
|
|
100
|
+
const agent = createAgent();
|
|
101
|
+
const context = createContext(agent);
|
|
102
|
+
const resultBytes = new TextEncoder().encode('verified-result');
|
|
103
|
+
const meter = new UsageMeter({ taskId: 'task-1', maxPrice: 10n, unitPrice: 2n });
|
|
104
|
+
meter.recordUnit(resultBytes);
|
|
105
|
+
(context.taskClient.getTask as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
106
|
+
id: 'task-1',
|
|
107
|
+
requester: '0xrequester',
|
|
108
|
+
provider: '0xprovider',
|
|
109
|
+
capability: 'echo',
|
|
110
|
+
category: 'general',
|
|
111
|
+
inputBlobId: 'blob-in',
|
|
112
|
+
resultBlobId: 'blob-out',
|
|
113
|
+
price: 2n,
|
|
114
|
+
paymentScheme: PaymentScheme.UPTO,
|
|
115
|
+
maxPrice: 10n,
|
|
116
|
+
meteredUnits: 1,
|
|
117
|
+
unitPrice: 2n,
|
|
118
|
+
verificationHash: meter.getVerificationHash(),
|
|
119
|
+
status: TaskStatus.COMPLETED,
|
|
120
|
+
disputeWindowMs: 1,
|
|
121
|
+
createdAt: 1,
|
|
122
|
+
expiresAt: 2,
|
|
123
|
+
agreementHash: 'metered:echo',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const result = await runMeshMeteredExecute({
|
|
127
|
+
capability: 'echo',
|
|
128
|
+
input: 'hello',
|
|
129
|
+
max_price_mist: 10,
|
|
130
|
+
unit_price_mist: 2,
|
|
131
|
+
}, context as never);
|
|
132
|
+
|
|
133
|
+
expect(result.task_id).toBe('task-1');
|
|
134
|
+
expect(result.verified).toBe(true);
|
|
135
|
+
expect(result.result).toBe('verified-result');
|
|
136
|
+
expect(context.taskClient.postMeteredTask).toHaveBeenCalledOnce();
|
|
137
|
+
expect(context.taskClient.releaseMeteredPayment).toHaveBeenCalledOnce();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('verifies stored metered results', async () => {
|
|
141
|
+
const agent = createAgent();
|
|
142
|
+
const context = createContext(agent);
|
|
143
|
+
const resultBytes = new TextEncoder().encode('verified-result');
|
|
144
|
+
const meter = new UsageMeter({ taskId: 'task-1', maxPrice: 10n, unitPrice: 2n });
|
|
145
|
+
meter.recordUnit(resultBytes);
|
|
146
|
+
(context.taskClient.getTask as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
147
|
+
id: 'task-1',
|
|
148
|
+
requester: '0xrequester',
|
|
149
|
+
provider: '0xprovider',
|
|
150
|
+
capability: 'echo',
|
|
151
|
+
category: 'general',
|
|
152
|
+
inputBlobId: 'blob-in',
|
|
153
|
+
resultBlobId: 'blob-out',
|
|
154
|
+
price: 2n,
|
|
155
|
+
paymentScheme: PaymentScheme.UPTO,
|
|
156
|
+
maxPrice: 10n,
|
|
157
|
+
meteredUnits: 1,
|
|
158
|
+
unitPrice: 2n,
|
|
159
|
+
verificationHash: meter.getVerificationHash(),
|
|
160
|
+
status: TaskStatus.COMPLETED,
|
|
161
|
+
disputeWindowMs: 1,
|
|
162
|
+
createdAt: 1,
|
|
163
|
+
expiresAt: 2,
|
|
164
|
+
agreementHash: 'metered:echo',
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const result = await runMeshVerifyResult({ task_id: 'task-1' }, context as never);
|
|
168
|
+
|
|
169
|
+
expect(result.verified).toBe(true);
|
|
170
|
+
expect(result.result).toBe('verified-result');
|
|
171
|
+
expect(result.metered_units).toBe(1);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { PaymentRail, ProviderSelectionStrategy, type AgentCard } from '@hivemind-os/collective-types';
|
|
4
|
+
|
|
5
|
+
const runMeshExecuteMock = vi.fn();
|
|
6
|
+
const discoverAgentsByCapabilityMock = vi.fn();
|
|
7
|
+
|
|
8
|
+
vi.mock('../src/tools/discover.js', async (importOriginal) => {
|
|
9
|
+
const actual = await importOriginal<typeof import('../src/tools/discover.js')>();
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
discoverAgentsByCapability: (...args: unknown[]) => discoverAgentsByCapabilityMock(...args),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
vi.mock('../src/tools/execute.js', async (importOriginal) => {
|
|
17
|
+
const actual = await importOriginal<typeof import('../src/tools/execute.js')>();
|
|
18
|
+
return {
|
|
19
|
+
...actual,
|
|
20
|
+
runMeshExecute: (...args: unknown[]) => runMeshExecuteMock(...args),
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
import type { MeshToolContext } from '../src/context.js';
|
|
25
|
+
import { runMeshMultiExecute } from '../src/tools/multi-execute.js';
|
|
26
|
+
|
|
27
|
+
function createAgent(overrides: Partial<AgentCard> = {}): AgentCard {
|
|
28
|
+
return {
|
|
29
|
+
id: 'agent-1',
|
|
30
|
+
owner: 'owner-1',
|
|
31
|
+
did: 'did:mesh:agent-1' as AgentCard['did'],
|
|
32
|
+
name: 'Agent 1',
|
|
33
|
+
description: 'Test agent',
|
|
34
|
+
capabilities: [
|
|
35
|
+
{
|
|
36
|
+
name: 'echo',
|
|
37
|
+
description: 'Echo',
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
pricing: {
|
|
40
|
+
rail: PaymentRail.SUI_ESCROW,
|
|
41
|
+
amount: 5n,
|
|
42
|
+
currency: 'MIST',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
active: true,
|
|
47
|
+
version: 1,
|
|
48
|
+
registeredAt: 1_000,
|
|
49
|
+
updatedAt: 1_000,
|
|
50
|
+
...overrides,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createContext(): MeshToolContext {
|
|
55
|
+
return {
|
|
56
|
+
did: 'did:mesh:test' as MeshToolContext['did'],
|
|
57
|
+
keypair: {} as MeshToolContext['keypair'],
|
|
58
|
+
suiClient: {} as MeshToolContext['suiClient'],
|
|
59
|
+
registryClient: {
|
|
60
|
+
discoverByCapability: vi.fn().mockResolvedValue([]),
|
|
61
|
+
getAgentCard: vi.fn(),
|
|
62
|
+
} as unknown as MeshToolContext['registryClient'],
|
|
63
|
+
taskClient: {} as MeshToolContext['taskClient'],
|
|
64
|
+
agentCache: {
|
|
65
|
+
searchByCapability: vi.fn().mockReturnValue([]),
|
|
66
|
+
getAgentByDID: vi.fn(),
|
|
67
|
+
getAllActive: vi.fn().mockReturnValue([]),
|
|
68
|
+
upsertAgent: vi.fn(),
|
|
69
|
+
removeAgent: vi.fn(),
|
|
70
|
+
} as unknown as MeshToolContext['agentCache'],
|
|
71
|
+
blobStore: {} as MeshToolContext['blobStore'],
|
|
72
|
+
spendingPolicy: {
|
|
73
|
+
evaluate: vi.fn(() => ({ approved: true })),
|
|
74
|
+
record: vi.fn(),
|
|
75
|
+
} as unknown as MeshToolContext['spendingPolicy'],
|
|
76
|
+
networkConfig: {
|
|
77
|
+
rpcUrl: 'http://127.0.0.1:9000',
|
|
78
|
+
faucetUrl: 'http://127.0.0.1:9123',
|
|
79
|
+
packageId: '0x1',
|
|
80
|
+
registryId: '0x2',
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
describe('runMeshMultiExecute', () => {
|
|
86
|
+
it('selects multiple providers and aggregates the first successful result', async () => {
|
|
87
|
+
runMeshExecuteMock.mockImplementation(async (params: { provider_did?: string }) => ({
|
|
88
|
+
task_id: `task-${params.provider_did}`,
|
|
89
|
+
result: params.provider_did === 'did:mesh:agent-1' ? 'winner' : 'runner-up',
|
|
90
|
+
provider_did: params.provider_did ?? 'unknown',
|
|
91
|
+
price_mist: params.provider_did === 'did:mesh:agent-1' ? '5' : '7',
|
|
92
|
+
status: 'COMPLETED',
|
|
93
|
+
execution_mode: 'sync',
|
|
94
|
+
payment_rail: PaymentRail.SUI_ESCROW,
|
|
95
|
+
}));
|
|
96
|
+
const agents = [
|
|
97
|
+
createAgent(),
|
|
98
|
+
createAgent({ id: 'agent-2', did: 'did:mesh:agent-2' as AgentCard['did'], totalTasksCompleted: 10, capabilities: [{
|
|
99
|
+
name: 'echo',
|
|
100
|
+
description: 'Echo',
|
|
101
|
+
version: '1.0.0',
|
|
102
|
+
pricing: { rail: PaymentRail.SUI_ESCROW, amount: 7n, currency: 'MIST' },
|
|
103
|
+
}] }),
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
discoverAgentsByCapabilityMock.mockResolvedValueOnce({
|
|
107
|
+
agents,
|
|
108
|
+
source: 'cache',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const result = await runMeshMultiExecute({
|
|
112
|
+
capability: 'echo',
|
|
113
|
+
input: { message: 'hello' },
|
|
114
|
+
fanOutCount: 2,
|
|
115
|
+
strategy: ProviderSelectionStrategy.CHEAPEST,
|
|
116
|
+
}, createContext());
|
|
117
|
+
|
|
118
|
+
expect(result.providers).toHaveLength(2);
|
|
119
|
+
expect(result.aggregated_result).toBe('winner');
|
|
120
|
+
expect(result.total_cost_mist).toBe('12');
|
|
121
|
+
expect(runMeshExecuteMock).toHaveBeenCalledTimes(2);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type { MeshToolContext } from '../src/context.js';
|
|
4
|
+
import { runMeshRelayRegistry } from '../src/tools/relay-registry.js';
|
|
5
|
+
|
|
6
|
+
function createContext(overrides: Partial<MeshToolContext> = {}): MeshToolContext {
|
|
7
|
+
return {
|
|
8
|
+
did: 'did:mesh:test' as MeshToolContext['did'],
|
|
9
|
+
keypair: {
|
|
10
|
+
getPublicKey: () => ({
|
|
11
|
+
toSuiAddress: () => '0xabc',
|
|
12
|
+
}),
|
|
13
|
+
} as MeshToolContext['keypair'],
|
|
14
|
+
suiClient: {
|
|
15
|
+
getBalance: vi.fn(),
|
|
16
|
+
queryEvents: vi.fn(),
|
|
17
|
+
} as unknown as MeshToolContext['suiClient'],
|
|
18
|
+
registryClient: {} as MeshToolContext['registryClient'],
|
|
19
|
+
taskClient: {} as MeshToolContext['taskClient'],
|
|
20
|
+
agentCache: {} as MeshToolContext['agentCache'],
|
|
21
|
+
blobStore: {} as MeshToolContext['blobStore'],
|
|
22
|
+
spendingPolicy: {} as MeshToolContext['spendingPolicy'],
|
|
23
|
+
networkConfig: {
|
|
24
|
+
rpcUrl: 'http://127.0.0.1:9000',
|
|
25
|
+
faucetUrl: 'http://127.0.0.1:9123',
|
|
26
|
+
packageId: '0x1',
|
|
27
|
+
registryId: '0x2',
|
|
28
|
+
},
|
|
29
|
+
relayRegistryClient: {
|
|
30
|
+
listRelays: vi.fn(),
|
|
31
|
+
registerRelay: vi.fn(),
|
|
32
|
+
} as unknown as MeshToolContext['relayRegistryClient'],
|
|
33
|
+
...overrides,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe('runMeshRelayRegistry', () => {
|
|
38
|
+
it('lists relays via the relay registry client', async () => {
|
|
39
|
+
const context = createContext();
|
|
40
|
+
vi.mocked(context.relayRegistryClient?.listRelays as never).mockResolvedValue([{ id: '0xrelay' }]);
|
|
41
|
+
|
|
42
|
+
const result = await runMeshRelayRegistry({ action: 'list' }, context);
|
|
43
|
+
|
|
44
|
+
expect(context.relayRegistryClient?.listRelays).toHaveBeenCalled();
|
|
45
|
+
expect(result).toMatchObject({ action: 'list', count: 1 });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('registers a relay via the relay registry client', async () => {
|
|
49
|
+
const context = createContext();
|
|
50
|
+
vi.mocked(context.relayRegistryClient?.registerRelay as never).mockResolvedValue({ relayId: '0xrelay', txDigest: '0xtx' });
|
|
51
|
+
|
|
52
|
+
const result = await runMeshRelayRegistry({
|
|
53
|
+
action: 'register',
|
|
54
|
+
endpoint: 'wss://relay.mesh.example/ws',
|
|
55
|
+
stake_id: '0x123',
|
|
56
|
+
region: 'us-east',
|
|
57
|
+
routing_fee_bps: 50,
|
|
58
|
+
capabilities: ['routing', 'streaming'],
|
|
59
|
+
}, context);
|
|
60
|
+
|
|
61
|
+
expect(context.relayRegistryClient?.registerRelay).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
|
+
endpoint: 'wss://relay.mesh.example/ws',
|
|
63
|
+
stakeId: '0x123',
|
|
64
|
+
region: 'us-east',
|
|
65
|
+
routingFeeBps: 50,
|
|
66
|
+
capabilities: ['routing', 'streaming'],
|
|
67
|
+
signer: context.keypair,
|
|
68
|
+
}));
|
|
69
|
+
expect(result).toMatchObject({ action: 'register', relay_id: '0xrelay', tx_digest: '0xtx' });
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type { MeshToolContext } from '../src/context.js';
|
|
4
|
+
import { runMeshStake } from '../src/tools/stake.js';
|
|
5
|
+
|
|
6
|
+
function createContext(overrides: Partial<MeshToolContext> = {}): MeshToolContext {
|
|
7
|
+
return {
|
|
8
|
+
did: 'did:mesh:test' as MeshToolContext['did'],
|
|
9
|
+
keypair: {
|
|
10
|
+
getPublicKey: () => ({
|
|
11
|
+
toSuiAddress: () => '0xabc',
|
|
12
|
+
}),
|
|
13
|
+
} as MeshToolContext['keypair'],
|
|
14
|
+
suiClient: {
|
|
15
|
+
getBalance: vi.fn(),
|
|
16
|
+
queryEvents: vi.fn(),
|
|
17
|
+
} as unknown as MeshToolContext['suiClient'],
|
|
18
|
+
registryClient: {} as MeshToolContext['registryClient'],
|
|
19
|
+
taskClient: {} as MeshToolContext['taskClient'],
|
|
20
|
+
agentCache: {} as MeshToolContext['agentCache'],
|
|
21
|
+
blobStore: {} as MeshToolContext['blobStore'],
|
|
22
|
+
spendingPolicy: {} as MeshToolContext['spendingPolicy'],
|
|
23
|
+
networkConfig: {
|
|
24
|
+
rpcUrl: 'http://127.0.0.1:9000',
|
|
25
|
+
faucetUrl: 'http://127.0.0.1:9123',
|
|
26
|
+
packageId: '0x1',
|
|
27
|
+
registryId: '0x2',
|
|
28
|
+
},
|
|
29
|
+
stakingClient: {
|
|
30
|
+
depositStake: vi.fn(),
|
|
31
|
+
getStakeByOwner: vi.fn(),
|
|
32
|
+
startDeactivation: vi.fn(),
|
|
33
|
+
withdrawStake: vi.fn(),
|
|
34
|
+
} as unknown as MeshToolContext['stakingClient'],
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe('runMeshStake', () => {
|
|
40
|
+
it('deposits stake through the staking client', async () => {
|
|
41
|
+
const context = createContext();
|
|
42
|
+
vi.mocked(context.stakingClient?.depositStake as never).mockResolvedValue({ stakeId: '0xstake', txDigest: '0xtx' });
|
|
43
|
+
|
|
44
|
+
const result = await runMeshStake({ action: 'deposit', amount_sui: '10', stake_type: 'agent' }, context);
|
|
45
|
+
|
|
46
|
+
expect(context.stakingClient?.depositStake).toHaveBeenCalledWith({
|
|
47
|
+
amountMist: 10_000_000_000n,
|
|
48
|
+
stakeType: 'agent',
|
|
49
|
+
signer: context.keypair,
|
|
50
|
+
});
|
|
51
|
+
expect(result).toMatchObject({ action: 'deposit', stake_id: '0xstake', tx_digest: '0xtx' });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('returns the current stake status', async () => {
|
|
55
|
+
const context = createContext();
|
|
56
|
+
vi.mocked(context.stakingClient?.getStakeByOwner as never).mockResolvedValue({
|
|
57
|
+
id: '0xstake',
|
|
58
|
+
owner: '0xabc',
|
|
59
|
+
stakeType: 'agent',
|
|
60
|
+
balanceMist: 10_000_000_000n,
|
|
61
|
+
stakedAt: 1,
|
|
62
|
+
deactivatedAt: 0,
|
|
63
|
+
slashedAmount: 0n,
|
|
64
|
+
isActive: true,
|
|
65
|
+
meetsMinium: true,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const result = await runMeshStake({ action: 'status' }, context);
|
|
69
|
+
|
|
70
|
+
expect(result).toMatchObject({ action: 'status', staked: true });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('starts deactivation before withdrawing', async () => {
|
|
74
|
+
const context = createContext();
|
|
75
|
+
vi.mocked(context.stakingClient?.getStakeByOwner as never).mockResolvedValue({
|
|
76
|
+
id: '0xstake',
|
|
77
|
+
owner: '0xabc',
|
|
78
|
+
stakeType: 'agent',
|
|
79
|
+
balanceMist: 10_000_000_000n,
|
|
80
|
+
stakedAt: 1,
|
|
81
|
+
deactivatedAt: 0,
|
|
82
|
+
slashedAmount: 0n,
|
|
83
|
+
});
|
|
84
|
+
vi.mocked(context.stakingClient?.startDeactivation as never).mockResolvedValue({ cooldownEndsAt: 1234, txDigest: '0xtx' });
|
|
85
|
+
|
|
86
|
+
const result = await runMeshStake({ action: 'withdraw' }, context);
|
|
87
|
+
|
|
88
|
+
expect(result).toMatchObject({ action: 'deactivation_started', cooldown_ends_at: 1234 });
|
|
89
|
+
});
|
|
90
|
+
});
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED