quorum-eliza-plugin 0.2.0 → 0.3.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/dist/actions/createMultisig.d.ts +2 -13
- package/dist/actions/createMultisig.js +5 -5
- package/dist/actions/createProposal.d.ts +2 -13
- package/dist/actions/createProposal.js +8 -8
- package/dist/actions/joinMultisig.d.ts +2 -13
- package/dist/actions/joinMultisig.js +6 -6
- package/dist/actions/listProposals.d.ts +2 -13
- package/dist/actions/listProposals.js +6 -6
- package/dist/actions/signProposal.d.ts +2 -13
- package/dist/actions/signProposal.js +10 -10
- package/dist/index.d.ts +10 -28
- package/dist/index.js +7 -6
- package/dist/providers/multisigInfo.d.ts +2 -5
- package/dist/services/quorum.d.ts +21 -2
- package/dist/services/quorum.js +81 -20
- package/dist/types.d.ts +67 -0
- package/dist/types.js +5 -0
- package/package.json +6 -2
- package/src/actions/createMultisig.ts +13 -13
- package/src/actions/createProposal.ts +16 -16
- package/src/actions/joinMultisig.ts +14 -14
- package/src/actions/listProposals.ts +14 -14
- package/src/actions/signProposal.ts +18 -18
- package/src/index.ts +31 -8
- package/src/providers/multisigInfo.ts +3 -2
- package/src/services/quorum.ts +96 -20
- package/src/types.ts +82 -0
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
description: string;
|
|
4
|
-
similes: string[];
|
|
5
|
-
examples: {
|
|
6
|
-
user: string;
|
|
7
|
-
content: {
|
|
8
|
-
text: string;
|
|
9
|
-
};
|
|
10
|
-
}[][];
|
|
11
|
-
validate: (runtime: any, message: any) => Promise<any>;
|
|
12
|
-
handler: (runtime: any, message: any, state: any, options: Record<string, unknown>, callback?: any) => Promise<any>;
|
|
13
|
-
};
|
|
1
|
+
import type { Action } from '../types.js';
|
|
2
|
+
export declare const createMultisigAction: Action;
|
|
@@ -11,11 +11,11 @@ export const createMultisigAction = {
|
|
|
11
11
|
],
|
|
12
12
|
examples: [
|
|
13
13
|
[
|
|
14
|
-
{
|
|
15
|
-
{
|
|
14
|
+
{ name: '{{user1}}', content: { text: 'Create a 2-of-3 Bitcoin multisig called "Team Treasury"' } },
|
|
15
|
+
{ name: '{{agent}}', content: { text: 'Created multisig "Team Treasury" (2-of-3). Invite code: abc123. Share this with other signers to join.' } },
|
|
16
16
|
],
|
|
17
17
|
],
|
|
18
|
-
validate: async (runtime, message) => {
|
|
18
|
+
validate: async (runtime, message, state) => {
|
|
19
19
|
const text = message.content?.text?.toLowerCase() || '';
|
|
20
20
|
return text.includes('create') && (text.includes('multisig') || text.includes('wallet') || text.includes('treasury'));
|
|
21
21
|
},
|
|
@@ -50,11 +50,11 @@ export const createMultisigAction = {
|
|
|
50
50
|
**Join Link:** https://quorumclaw.com/join/${result.inviteCode}
|
|
51
51
|
|
|
52
52
|
Share this with other signers to join the wallet.`;
|
|
53
|
-
callback?.({ text: response });
|
|
53
|
+
await callback?.({ text: response });
|
|
54
54
|
return true;
|
|
55
55
|
}
|
|
56
56
|
catch (err) {
|
|
57
|
-
callback?.({ text: `❌ Failed to create multisig: ${err.message}` });
|
|
57
|
+
await callback?.({ text: `❌ Failed to create multisig: ${err.message}` });
|
|
58
58
|
return false;
|
|
59
59
|
}
|
|
60
60
|
},
|
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
description: string;
|
|
4
|
-
similes: string[];
|
|
5
|
-
examples: {
|
|
6
|
-
user: string;
|
|
7
|
-
content: {
|
|
8
|
-
text: string;
|
|
9
|
-
};
|
|
10
|
-
}[][];
|
|
11
|
-
validate: (runtime: any, message: any) => Promise<any>;
|
|
12
|
-
handler: (runtime: any, message: any, state: any, options: Record<string, unknown>, callback?: any) => Promise<any>;
|
|
13
|
-
};
|
|
1
|
+
import type { Action } from '../types.js';
|
|
2
|
+
export declare const createProposalAction: Action;
|
|
@@ -11,11 +11,11 @@ export const createProposalAction = {
|
|
|
11
11
|
],
|
|
12
12
|
examples: [
|
|
13
13
|
[
|
|
14
|
-
{
|
|
15
|
-
{
|
|
14
|
+
{ name: '{{user1}}', content: { text: 'Send 5000 sats to bc1q... from our treasury' } },
|
|
15
|
+
{ name: '{{agent}}', content: { text: 'Created proposal! ID: abc123. Waiting for 2 more signatures.' } },
|
|
16
16
|
],
|
|
17
17
|
],
|
|
18
|
-
validate: async (runtime, message) => {
|
|
18
|
+
validate: async (runtime, message, state) => {
|
|
19
19
|
const text = message.content?.text?.toLowerCase() || '';
|
|
20
20
|
return (text.includes('send') || text.includes('propose') || text.includes('transfer')) &&
|
|
21
21
|
(text.includes('multisig') || text.includes('treasury') || text.includes('proposal') || text.includes('sats'));
|
|
@@ -26,7 +26,7 @@ export const createProposalAction = {
|
|
|
26
26
|
// Parse amount
|
|
27
27
|
const amountMatch = text.match(/(\d+(?:,\d+)?)\s*(?:sats?|satoshis?)/i);
|
|
28
28
|
if (!amountMatch) {
|
|
29
|
-
callback?.({ text: '❌ Please specify an amount in sats. Example: "Send 5000 sats to bc1q..."' });
|
|
29
|
+
await callback?.({ text: '❌ Please specify an amount in sats. Example: "Send 5000 sats to bc1q..."' });
|
|
30
30
|
return false;
|
|
31
31
|
}
|
|
32
32
|
const amount = parseInt(amountMatch[1].replace(/,/g, ''));
|
|
@@ -35,14 +35,14 @@ export const createProposalAction = {
|
|
|
35
35
|
text.match(/(tb1[a-z0-9]{39,87})/i) || // Testnet
|
|
36
36
|
text.match(/(0x[a-fA-F0-9]{40})/i); // EVM
|
|
37
37
|
if (!addressMatch) {
|
|
38
|
-
callback?.({ text: '❌ Please provide a recipient address. Example: "Send 5000 sats to bc1q..."' });
|
|
38
|
+
await callback?.({ text: '❌ Please provide a recipient address. Example: "Send 5000 sats to bc1q..."' });
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
41
|
const recipient = addressMatch[1];
|
|
42
42
|
// Get multisigs
|
|
43
43
|
const multisigs = await quorumService.listMultisigs();
|
|
44
44
|
if (multisigs.length === 0) {
|
|
45
|
-
callback?.({ text: '❌ You are not part of any multisigs. Create or join one first.' });
|
|
45
|
+
await callback?.({ text: '❌ You are not part of any multisigs. Create or join one first.' });
|
|
46
46
|
return false;
|
|
47
47
|
}
|
|
48
48
|
// Use first multisig or parse from message
|
|
@@ -57,7 +57,7 @@ export const createProposalAction = {
|
|
|
57
57
|
amount,
|
|
58
58
|
note,
|
|
59
59
|
});
|
|
60
|
-
callback?.({
|
|
60
|
+
await callback?.({
|
|
61
61
|
text: `✅ **Proposal Created**
|
|
62
62
|
|
|
63
63
|
**ID:** \`${proposal.id}\`
|
|
@@ -72,7 +72,7 @@ https://quorumclaw.com/p/${proposal.id}`
|
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
74
74
|
catch (err) {
|
|
75
|
-
callback?.({ text: `❌ Failed to create proposal: ${err.message}` });
|
|
75
|
+
await callback?.({ text: `❌ Failed to create proposal: ${err.message}` });
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
78
|
},
|
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
description: string;
|
|
4
|
-
similes: string[];
|
|
5
|
-
examples: {
|
|
6
|
-
user: string;
|
|
7
|
-
content: {
|
|
8
|
-
text: string;
|
|
9
|
-
};
|
|
10
|
-
}[][];
|
|
11
|
-
validate: (runtime: any, message: any) => Promise<any>;
|
|
12
|
-
handler: (runtime: any, message: any, state: any, options: Record<string, unknown>, callback?: any) => Promise<any>;
|
|
13
|
-
};
|
|
1
|
+
import type { Action } from '../types.js';
|
|
2
|
+
export declare const joinMultisigAction: Action;
|
|
@@ -10,11 +10,11 @@ export const joinMultisigAction = {
|
|
|
10
10
|
],
|
|
11
11
|
examples: [
|
|
12
12
|
[
|
|
13
|
-
{
|
|
14
|
-
{
|
|
13
|
+
{ name: '{{user1}}', content: { text: 'Join multisig with code abc123' } },
|
|
14
|
+
{ name: '{{agent}}', content: { text: 'Joined multisig "Team Treasury"! Address: bc1p...' } },
|
|
15
15
|
],
|
|
16
16
|
],
|
|
17
|
-
validate: async (runtime, message) => {
|
|
17
|
+
validate: async (runtime, message, state) => {
|
|
18
18
|
const text = message.content?.text?.toLowerCase() || '';
|
|
19
19
|
return text.includes('join') && (text.includes('multisig') || text.includes('wallet') || text.includes('code'));
|
|
20
20
|
},
|
|
@@ -25,7 +25,7 @@ export const joinMultisigAction = {
|
|
|
25
25
|
const codeMatch = text.match(/(?:code|invite)?\s*([a-f0-9]{8})/i) ||
|
|
26
26
|
text.match(/join\/([a-f0-9]{8})/i);
|
|
27
27
|
if (!codeMatch) {
|
|
28
|
-
callback?.({ text: '❌ Please provide an invite code. Example: "Join multisig with code abc12345"' });
|
|
28
|
+
await callback?.({ text: '❌ Please provide an invite code. Example: "Join multisig with code abc12345"' });
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
const inviteCode = codeMatch[1];
|
|
@@ -38,11 +38,11 @@ export const joinMultisigAction = {
|
|
|
38
38
|
**Signers:** ${multisig.agents.map(a => a.name).join(', ')}
|
|
39
39
|
|
|
40
40
|
The wallet is ready to receive funds.`;
|
|
41
|
-
callback?.({ text: response });
|
|
41
|
+
await callback?.({ text: response });
|
|
42
42
|
return true;
|
|
43
43
|
}
|
|
44
44
|
catch (err) {
|
|
45
|
-
callback?.({ text: `❌ Failed to join multisig: ${err.message}` });
|
|
45
|
+
await callback?.({ text: `❌ Failed to join multisig: ${err.message}` });
|
|
46
46
|
return false;
|
|
47
47
|
}
|
|
48
48
|
},
|
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
description: string;
|
|
4
|
-
similes: string[];
|
|
5
|
-
examples: {
|
|
6
|
-
user: string;
|
|
7
|
-
content: {
|
|
8
|
-
text: string;
|
|
9
|
-
};
|
|
10
|
-
}[][];
|
|
11
|
-
validate: (runtime: any, message: any) => Promise<any>;
|
|
12
|
-
handler: (runtime: any, message: any, state: any, options: Record<string, unknown>, callback?: any) => Promise<any>;
|
|
13
|
-
};
|
|
1
|
+
import type { Action } from '../types.js';
|
|
2
|
+
export declare const listProposalsAction: Action;
|
|
@@ -11,11 +11,11 @@ export const listProposalsAction = {
|
|
|
11
11
|
],
|
|
12
12
|
examples: [
|
|
13
13
|
[
|
|
14
|
-
{
|
|
15
|
-
{
|
|
14
|
+
{ name: '{{user1}}', content: { text: 'Show pending proposals' } },
|
|
15
|
+
{ name: '{{agent}}', content: { text: 'You have 2 pending proposals:\n- 5000 sats to bc1q... (1/2 sigs)\n- 10000 sats to bc1p... (0/3 sigs)' } },
|
|
16
16
|
],
|
|
17
17
|
],
|
|
18
|
-
validate: async (runtime, message) => {
|
|
18
|
+
validate: async (runtime, message, state) => {
|
|
19
19
|
const text = message.content?.text?.toLowerCase() || '';
|
|
20
20
|
return (text.includes('list') || text.includes('show') || text.includes('pending') || text.includes('check')) &&
|
|
21
21
|
(text.includes('proposal') || text.includes('transaction') || text.includes('signing'));
|
|
@@ -24,7 +24,7 @@ export const listProposalsAction = {
|
|
|
24
24
|
try {
|
|
25
25
|
const proposals = await quorumService.listPendingProposals();
|
|
26
26
|
if (proposals.length === 0) {
|
|
27
|
-
callback?.({ text: '✅ No pending proposals. All caught up!' });
|
|
27
|
+
await callback?.({ text: '✅ No pending proposals. All caught up!' });
|
|
28
28
|
return true;
|
|
29
29
|
}
|
|
30
30
|
const list = proposals.map(p => {
|
|
@@ -34,13 +34,13 @@ export const listProposalsAction = {
|
|
|
34
34
|
return `• **${amount.toLocaleString()} sats** → ${shortRecipient}
|
|
35
35
|
ID: \`${p.id.slice(0, 8)}...\` | Sigs: ${p.signatures.length}/? | ${p.note || 'No note'}`;
|
|
36
36
|
}).join('\n\n');
|
|
37
|
-
callback?.({
|
|
37
|
+
await callback?.({
|
|
38
38
|
text: `📋 **Pending Proposals (${proposals.length})**\n\n${list}\n\nSay "sign proposal <id>" to approve.`
|
|
39
39
|
});
|
|
40
40
|
return true;
|
|
41
41
|
}
|
|
42
42
|
catch (err) {
|
|
43
|
-
callback?.({ text: `❌ Failed to list proposals: ${err.message}` });
|
|
43
|
+
await callback?.({ text: `❌ Failed to list proposals: ${err.message}` });
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
46
|
},
|
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
description: string;
|
|
4
|
-
similes: string[];
|
|
5
|
-
examples: {
|
|
6
|
-
user: string;
|
|
7
|
-
content: {
|
|
8
|
-
text: string;
|
|
9
|
-
};
|
|
10
|
-
}[][];
|
|
11
|
-
validate: (runtime: any, message: any) => Promise<any>;
|
|
12
|
-
handler: (runtime: any, message: any, state: any, options: Record<string, unknown>, callback?: any) => Promise<any>;
|
|
13
|
-
};
|
|
1
|
+
import type { Action } from '../types.js';
|
|
2
|
+
export declare const signProposalAction: Action;
|
|
@@ -11,11 +11,11 @@ export const signProposalAction = {
|
|
|
11
11
|
],
|
|
12
12
|
examples: [
|
|
13
13
|
[
|
|
14
|
-
{
|
|
15
|
-
{
|
|
14
|
+
{ name: '{{user1}}', content: { text: 'Sign proposal abc123' } },
|
|
15
|
+
{ name: '{{agent}}', content: { text: 'Signed! 2/3 signatures collected. Waiting for one more signer.' } },
|
|
16
16
|
],
|
|
17
17
|
],
|
|
18
|
-
validate: async (runtime, message) => {
|
|
18
|
+
validate: async (runtime, message, state) => {
|
|
19
19
|
const text = message.content?.text?.toLowerCase() || '';
|
|
20
20
|
return (text.includes('sign') || text.includes('approve')) &&
|
|
21
21
|
(text.includes('proposal') || text.includes('transaction') || text.includes('tx'));
|
|
@@ -30,42 +30,42 @@ export const signProposalAction = {
|
|
|
30
30
|
// Try to find pending proposals
|
|
31
31
|
const pending = await quorumService.listPendingProposals();
|
|
32
32
|
if (pending.length === 0) {
|
|
33
|
-
callback?.({ text: '❌ No pending proposals found. Provide a proposal ID or create a new proposal.' });
|
|
33
|
+
await callback?.({ text: '❌ No pending proposals found. Provide a proposal ID or create a new proposal.' });
|
|
34
34
|
return false;
|
|
35
35
|
}
|
|
36
36
|
if (pending.length === 1) {
|
|
37
37
|
// Auto-sign the only pending proposal
|
|
38
38
|
const result = await quorumService.signProposal(pending[0].id);
|
|
39
39
|
if (result.txid) {
|
|
40
|
-
callback?.({ text: `✅ Signed and broadcast! txid: ${result.txid}\n\nhttps://mempool.space/tx/${result.txid}` });
|
|
40
|
+
await callback?.({ text: `✅ Signed and broadcast! txid: ${result.txid}\n\nhttps://mempool.space/tx/${result.txid}` });
|
|
41
41
|
}
|
|
42
42
|
else {
|
|
43
|
-
callback?.({ text: `✅ Signed! Proposal status: ${result.status}. Waiting for more signatures.` });
|
|
43
|
+
await callback?.({ text: `✅ Signed! Proposal status: ${result.status}. Waiting for more signatures.` });
|
|
44
44
|
}
|
|
45
45
|
return true;
|
|
46
46
|
}
|
|
47
47
|
// List pending proposals
|
|
48
48
|
const list = pending.map(p => `- \`${p.id.slice(0, 8)}...\`: ${p.outputs.map(o => `${o.amount} sats`).join(', ')} (${p.signatures.length} sigs)`).join('\n');
|
|
49
|
-
callback?.({ text: `Multiple pending proposals. Please specify which one:\n\n${list}` });
|
|
49
|
+
await callback?.({ text: `Multiple pending proposals. Please specify which one:\n\n${list}` });
|
|
50
50
|
return false;
|
|
51
51
|
}
|
|
52
52
|
const proposalId = idMatch[1];
|
|
53
53
|
const result = await quorumService.signProposal(proposalId);
|
|
54
54
|
if (result.txid) {
|
|
55
|
-
callback?.({
|
|
55
|
+
await callback?.({
|
|
56
56
|
text: `✅ **Threshold met! Transaction broadcast.**\n\n**txid:** \`${result.txid}\`\n\nhttps://mempool.space/tx/${result.txid}`
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
else {
|
|
60
60
|
const proposal = await quorumService.getProposal(proposalId);
|
|
61
|
-
callback?.({
|
|
61
|
+
await callback?.({
|
|
62
62
|
text: `✅ Signed! ${proposal.signatures.length}/${proposal.sighashes.length + 1} signatures collected. Waiting for more signers.`
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
return true;
|
|
66
66
|
}
|
|
67
67
|
catch (err) {
|
|
68
|
-
callback?.({ text: `❌ Failed to sign: ${err.message}` });
|
|
68
|
+
await callback?.({ text: `❌ Failed to sign: ${err.message}` });
|
|
69
69
|
return false;
|
|
70
70
|
}
|
|
71
71
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -3,33 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Enables any Eliza agent to participate in multi-agent wallets via Quorum.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
description: string;
|
|
9
|
-
init(runtime: any): Promise<void>;
|
|
10
|
-
actions: {
|
|
11
|
-
name: string;
|
|
12
|
-
description: string;
|
|
13
|
-
similes: string[];
|
|
14
|
-
examples: {
|
|
15
|
-
user: string;
|
|
16
|
-
content: {
|
|
17
|
-
text: string;
|
|
18
|
-
};
|
|
19
|
-
}[][];
|
|
20
|
-
validate: (runtime: any, message: any) => Promise<any>;
|
|
21
|
-
handler: (runtime: any, message: any, state: any, options: Record<string, unknown>, callback?: any) => Promise<any>;
|
|
22
|
-
}[];
|
|
23
|
-
providers: {
|
|
24
|
-
name: string;
|
|
25
|
-
description: string;
|
|
26
|
-
get: (runtime: any, message: any, state?: any) => Promise<any>;
|
|
27
|
-
}[];
|
|
28
|
-
};
|
|
6
|
+
import type { Plugin } from './types.js';
|
|
7
|
+
export declare const quorumPlugin: Plugin;
|
|
29
8
|
export default quorumPlugin;
|
|
9
|
+
export type { IAgentRuntime, Plugin, Action, Provider, Memory, State, Content, Handler, Validator, HandlerCallback, } from './types.js';
|
|
30
10
|
export { quorumService } from './services/quorum.js';
|
|
31
|
-
export
|
|
32
|
-
export
|
|
33
|
-
export
|
|
34
|
-
export
|
|
35
|
-
export
|
|
11
|
+
export type { QuorumAgent, QuorumMultisig, QuorumProposal, QuorumConfig } from './services/quorum.js';
|
|
12
|
+
export { createMultisigAction } from './actions/createMultisig.js';
|
|
13
|
+
export { joinMultisigAction } from './actions/joinMultisig.js';
|
|
14
|
+
export { signProposalAction } from './actions/signProposal.js';
|
|
15
|
+
export { listProposalsAction } from './actions/listProposals.js';
|
|
16
|
+
export { createProposalAction } from './actions/createProposal.js';
|
|
17
|
+
export { multisigProvider } from './providers/multisigInfo.js';
|
package/dist/index.js
CHANGED
|
@@ -27,10 +27,11 @@ export const quorumPlugin = {
|
|
|
27
27
|
providers: [multisigProvider],
|
|
28
28
|
};
|
|
29
29
|
export default quorumPlugin;
|
|
30
|
-
// Re-export
|
|
30
|
+
// Re-export service and actions
|
|
31
31
|
export { quorumService } from './services/quorum.js';
|
|
32
|
-
export
|
|
33
|
-
export
|
|
34
|
-
export
|
|
35
|
-
export
|
|
36
|
-
export
|
|
32
|
+
export { createMultisigAction } from './actions/createMultisig.js';
|
|
33
|
+
export { joinMultisigAction } from './actions/joinMultisig.js';
|
|
34
|
+
export { signProposalAction } from './actions/signProposal.js';
|
|
35
|
+
export { listProposalsAction } from './actions/listProposals.js';
|
|
36
|
+
export { createProposalAction } from './actions/createProposal.js';
|
|
37
|
+
export { multisigProvider } from './providers/multisigInfo.js';
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages connection to Quorum API and handles signing operations.
|
|
5
5
|
*/
|
|
6
|
+
import type { IAgentRuntime } from '../types.js';
|
|
6
7
|
export interface QuorumAgent {
|
|
7
8
|
id: string;
|
|
8
9
|
name: string;
|
|
@@ -35,12 +36,25 @@ export interface QuorumProposal {
|
|
|
35
36
|
note?: string;
|
|
36
37
|
createdAt: string;
|
|
37
38
|
}
|
|
39
|
+
export interface QuorumConfig {
|
|
40
|
+
privateKey?: string;
|
|
41
|
+
apiUrl?: string;
|
|
42
|
+
agentName?: string;
|
|
43
|
+
}
|
|
38
44
|
declare class QuorumService {
|
|
39
45
|
private agentId;
|
|
46
|
+
private agentName;
|
|
40
47
|
private publicKey;
|
|
41
48
|
private privateKey;
|
|
49
|
+
private apiUrl;
|
|
50
|
+
private initialized;
|
|
42
51
|
get capabilityDescription(): string;
|
|
43
|
-
|
|
52
|
+
isInitialized(): boolean;
|
|
53
|
+
initialize(runtime: IAgentRuntime): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Initialize with explicit config (useful for testing)
|
|
56
|
+
*/
|
|
57
|
+
initializeWithConfig(config: QuorumConfig): Promise<void>;
|
|
44
58
|
register(name: string): Promise<QuorumAgent>;
|
|
45
59
|
createMultisig(params: {
|
|
46
60
|
name: string;
|
|
@@ -51,7 +65,7 @@ declare class QuorumService {
|
|
|
51
65
|
multisig: QuorumMultisig;
|
|
52
66
|
inviteCode: string;
|
|
53
67
|
}>;
|
|
54
|
-
joinMultisig(inviteCode: string): Promise<QuorumMultisig>;
|
|
68
|
+
joinMultisig(inviteCode: string, agentName?: string): Promise<QuorumMultisig>;
|
|
55
69
|
listMultisigs(): Promise<QuorumMultisig[]>;
|
|
56
70
|
listPendingProposals(): Promise<QuorumProposal[]>;
|
|
57
71
|
getProposal(proposalId: string): Promise<QuorumProposal>;
|
|
@@ -68,6 +82,11 @@ declare class QuorumService {
|
|
|
68
82
|
}): Promise<QuorumProposal>;
|
|
69
83
|
getAgentId(): string | null;
|
|
70
84
|
getPublicKey(): string | null;
|
|
85
|
+
getApiUrl(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Reset service state (useful for testing)
|
|
88
|
+
*/
|
|
89
|
+
reset(): void;
|
|
71
90
|
}
|
|
72
91
|
export declare const quorumService: QuorumService;
|
|
73
92
|
export default quorumService;
|
package/dist/services/quorum.js
CHANGED
|
@@ -8,11 +8,17 @@ import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
|
|
|
8
8
|
const QUORUM_API = process.env.QUORUM_API_URL || 'https://quorumclaw.com';
|
|
9
9
|
class QuorumService {
|
|
10
10
|
agentId = null;
|
|
11
|
+
agentName = null;
|
|
11
12
|
publicKey = null;
|
|
12
13
|
privateKey = null;
|
|
14
|
+
apiUrl = QUORUM_API;
|
|
15
|
+
initialized = false;
|
|
13
16
|
get capabilityDescription() {
|
|
14
17
|
return 'Multi-agent wallet coordination via Quorum';
|
|
15
18
|
}
|
|
19
|
+
isInitialized() {
|
|
20
|
+
return this.initialized && this.agentId !== null;
|
|
21
|
+
}
|
|
16
22
|
async initialize(runtime) {
|
|
17
23
|
// Try to get private key from runtime settings
|
|
18
24
|
const privateKeyHex = runtime.getSetting?.('QUORUM_PRIVATE_KEY') ||
|
|
@@ -22,75 +28,116 @@ class QuorumService {
|
|
|
22
28
|
console.warn('[Quorum] No private key configured. Set QUORUM_PRIVATE_KEY or WALLET_PRIVATE_KEY.');
|
|
23
29
|
return;
|
|
24
30
|
}
|
|
31
|
+
// Get API URL override if set
|
|
32
|
+
const apiUrlOverride = runtime.getSetting?.('QUORUM_API_URL') || process.env.QUORUM_API_URL;
|
|
33
|
+
if (apiUrlOverride) {
|
|
34
|
+
this.apiUrl = apiUrlOverride;
|
|
35
|
+
}
|
|
25
36
|
try {
|
|
26
37
|
const keyHex = String(privateKeyHex).replace('0x', '');
|
|
27
38
|
this.privateKey = hexToBytes(keyHex);
|
|
28
39
|
this.publicKey = bytesToHex(schnorr.getPublicKey(this.privateKey));
|
|
29
40
|
// Register with Quorum
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
const agentName = runtime.character?.name || 'Eliza Agent';
|
|
42
|
+
await this.register(agentName);
|
|
43
|
+
this.initialized = true;
|
|
44
|
+
console.log(`[Quorum] Initialized. Agent ID: ${this.agentId}, Public Key: ${this.publicKey?.slice(0, 16)}...`);
|
|
32
45
|
}
|
|
33
46
|
catch (err) {
|
|
34
47
|
console.error('[Quorum] Failed to initialize:', err);
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Initialize with explicit config (useful for testing)
|
|
53
|
+
*/
|
|
54
|
+
async initializeWithConfig(config) {
|
|
55
|
+
if (!config.privateKey) {
|
|
56
|
+
throw new Error('Private key is required');
|
|
35
57
|
}
|
|
58
|
+
if (config.apiUrl) {
|
|
59
|
+
this.apiUrl = config.apiUrl;
|
|
60
|
+
}
|
|
61
|
+
const keyHex = config.privateKey.replace('0x', '');
|
|
62
|
+
this.privateKey = hexToBytes(keyHex);
|
|
63
|
+
this.publicKey = bytesToHex(schnorr.getPublicKey(this.privateKey));
|
|
64
|
+
await this.register(config.agentName || 'Test Agent');
|
|
65
|
+
this.initialized = true;
|
|
36
66
|
}
|
|
37
67
|
async register(name) {
|
|
38
68
|
if (!this.publicKey)
|
|
39
69
|
throw new Error('No public key available');
|
|
40
|
-
const res = await fetch(`${
|
|
70
|
+
const res = await fetch(`${this.apiUrl}/v1/agents`, {
|
|
41
71
|
method: 'POST',
|
|
42
72
|
headers: { 'Content-Type': 'application/json' },
|
|
43
73
|
body: JSON.stringify({
|
|
44
74
|
name,
|
|
45
75
|
publicKey: this.publicKey,
|
|
46
|
-
provider: 'eliza',
|
|
76
|
+
provider: 'custom', // 'eliza' not in allowed enum, use 'custom'
|
|
77
|
+
metadata: { framework: 'eliza' }, // Store framework info in metadata
|
|
47
78
|
}),
|
|
48
79
|
});
|
|
49
80
|
const json = await res.json();
|
|
50
81
|
if (!json.success)
|
|
51
82
|
throw new Error(json.error?.message || 'Registration failed');
|
|
52
83
|
this.agentId = json.data.id;
|
|
84
|
+
this.agentName = name;
|
|
53
85
|
return json.data;
|
|
54
86
|
}
|
|
55
87
|
async createMultisig(params) {
|
|
56
88
|
if (!this.agentId)
|
|
57
89
|
throw new Error('Not registered with Quorum');
|
|
58
|
-
const res = await fetch(`${
|
|
90
|
+
const res = await fetch(`${this.apiUrl}/v1/invites`, {
|
|
59
91
|
method: 'POST',
|
|
60
92
|
headers: { 'Content-Type': 'application/json' },
|
|
61
93
|
body: JSON.stringify({
|
|
62
94
|
name: params.name,
|
|
63
95
|
chainId: params.chainId,
|
|
64
96
|
threshold: params.threshold,
|
|
65
|
-
|
|
66
|
-
creatorAgentId: this.agentId,
|
|
97
|
+
totalSigners: params.totalSigners,
|
|
67
98
|
}),
|
|
68
99
|
});
|
|
69
100
|
const json = await res.json();
|
|
70
101
|
if (!json.success)
|
|
71
102
|
throw new Error(json.error?.message || 'Create failed');
|
|
72
103
|
return {
|
|
73
|
-
multisig: json.data
|
|
74
|
-
inviteCode: json.data.
|
|
104
|
+
multisig: json.data, // Invite data until multisig is finalized
|
|
105
|
+
inviteCode: json.data.inviteId || json.data.id,
|
|
75
106
|
};
|
|
76
107
|
}
|
|
77
|
-
async joinMultisig(inviteCode) {
|
|
78
|
-
if (!this.
|
|
79
|
-
throw new Error('Not
|
|
80
|
-
const res = await fetch(`${
|
|
108
|
+
async joinMultisig(inviteCode, agentName) {
|
|
109
|
+
if (!this.publicKey)
|
|
110
|
+
throw new Error('Not initialized');
|
|
111
|
+
const res = await fetch(`${this.apiUrl}/v1/invites/${inviteCode}/join`, {
|
|
81
112
|
method: 'POST',
|
|
82
113
|
headers: { 'Content-Type': 'application/json' },
|
|
83
|
-
body: JSON.stringify({
|
|
114
|
+
body: JSON.stringify({
|
|
115
|
+
name: agentName || this.agentName || 'Agent',
|
|
116
|
+
publicKey: this.publicKey,
|
|
117
|
+
}),
|
|
84
118
|
});
|
|
85
119
|
const json = await res.json();
|
|
86
120
|
if (!json.success)
|
|
87
121
|
throw new Error(json.error?.message || 'Join failed');
|
|
88
|
-
|
|
122
|
+
// API returns invite data directly; convert to multisig format
|
|
123
|
+
const data = json.data;
|
|
124
|
+
return {
|
|
125
|
+
id: data.multisigId || data.id,
|
|
126
|
+
name: data.name,
|
|
127
|
+
address: data.address || 'pending',
|
|
128
|
+
chainId: data.chainId,
|
|
129
|
+
threshold: data.threshold,
|
|
130
|
+
agents: data.slots.filter((s) => s.publicKey).map((s) => ({
|
|
131
|
+
id: s.sessionId,
|
|
132
|
+
name: s.name,
|
|
133
|
+
publicKey: s.publicKey,
|
|
134
|
+
})),
|
|
135
|
+
};
|
|
89
136
|
}
|
|
90
137
|
async listMultisigs() {
|
|
91
138
|
if (!this.agentId)
|
|
92
139
|
return [];
|
|
93
|
-
const res = await fetch(`${
|
|
140
|
+
const res = await fetch(`${this.apiUrl}/v1/agents/${this.agentId}/multisigs`);
|
|
94
141
|
const json = await res.json();
|
|
95
142
|
return json.success ? json.data : [];
|
|
96
143
|
}
|
|
@@ -98,7 +145,7 @@ class QuorumService {
|
|
|
98
145
|
const multisigs = await this.listMultisigs();
|
|
99
146
|
const proposals = [];
|
|
100
147
|
for (const ms of multisigs) {
|
|
101
|
-
const res = await fetch(`${
|
|
148
|
+
const res = await fetch(`${this.apiUrl}/v1/proposals?multisigId=${ms.id}&status=pending`);
|
|
102
149
|
const json = await res.json();
|
|
103
150
|
if (json.success) {
|
|
104
151
|
proposals.push(...json.data);
|
|
@@ -107,7 +154,7 @@ class QuorumService {
|
|
|
107
154
|
return proposals;
|
|
108
155
|
}
|
|
109
156
|
async getProposal(proposalId) {
|
|
110
|
-
const res = await fetch(`${
|
|
157
|
+
const res = await fetch(`${this.apiUrl}/v1/proposals/${proposalId}`);
|
|
111
158
|
const json = await res.json();
|
|
112
159
|
if (!json.success)
|
|
113
160
|
throw new Error(json.error?.message || 'Proposal not found');
|
|
@@ -130,7 +177,7 @@ class QuorumService {
|
|
|
130
177
|
for (const sh of proposal.sighashes) {
|
|
131
178
|
const sighashBytes = hexToBytes(sh.sighash);
|
|
132
179
|
const signature = schnorr.sign(sighashBytes, this.privateKey);
|
|
133
|
-
const res = await fetch(`${
|
|
180
|
+
const res = await fetch(`${this.apiUrl}/v1/proposals/${proposalId}/sign`, {
|
|
134
181
|
method: 'POST',
|
|
135
182
|
headers: { 'Content-Type': 'application/json' },
|
|
136
183
|
body: JSON.stringify({
|
|
@@ -153,7 +200,7 @@ class QuorumService {
|
|
|
153
200
|
return { success: true, status: 'pending' };
|
|
154
201
|
}
|
|
155
202
|
async createProposal(params) {
|
|
156
|
-
const res = await fetch(`${
|
|
203
|
+
const res = await fetch(`${this.apiUrl}/v1/proposals`, {
|
|
157
204
|
method: 'POST',
|
|
158
205
|
headers: { 'Content-Type': 'application/json' },
|
|
159
206
|
body: JSON.stringify({
|
|
@@ -174,6 +221,20 @@ class QuorumService {
|
|
|
174
221
|
getPublicKey() {
|
|
175
222
|
return this.publicKey;
|
|
176
223
|
}
|
|
224
|
+
getApiUrl() {
|
|
225
|
+
return this.apiUrl;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Reset service state (useful for testing)
|
|
229
|
+
*/
|
|
230
|
+
reset() {
|
|
231
|
+
this.agentId = null;
|
|
232
|
+
this.agentName = null;
|
|
233
|
+
this.publicKey = null;
|
|
234
|
+
this.privateKey = null;
|
|
235
|
+
this.initialized = false;
|
|
236
|
+
this.apiUrl = QUORUM_API;
|
|
237
|
+
}
|
|
177
238
|
}
|
|
178
239
|
export const quorumService = new QuorumService();
|
|
179
240
|
export default quorumService;
|