@hashgraphonline/standards-sdk 0.0.157-canary.2 → 0.0.157-canary.4
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/cjs/hcs-10/base-client.d.ts +1 -1
- package/dist/cjs/hcs-10/base-client.d.ts.map +1 -1
- package/dist/cjs/hcs-10/sdk.d.ts +1 -1
- package/dist/cjs/hcs-10/sdk.d.ts.map +1 -1
- package/dist/cjs/hcs-11/agent-builder.d.ts +2 -0
- package/dist/cjs/hcs-11/agent-builder.d.ts.map +1 -1
- package/dist/cjs/hcs-11/client.d.ts +2 -0
- package/dist/cjs/hcs-11/client.d.ts.map +1 -1
- package/dist/cjs/hcs-11/types.d.ts +4 -2
- package/dist/cjs/hcs-11/types.d.ts.map +1 -1
- package/dist/cjs/hcs-15/index.d.ts +3 -0
- package/dist/cjs/hcs-15/index.d.ts.map +1 -0
- package/dist/cjs/hcs-15/petal-manager.d.ts +27 -0
- package/dist/cjs/hcs-15/petal-manager.d.ts.map +1 -0
- package/dist/cjs/hcs-15/types.d.ts +41 -0
- package/dist/cjs/hcs-15/types.d.ts.map +1 -0
- package/dist/cjs/hcs-16/flora-account-manager.d.ts.map +1 -1
- package/dist/cjs/hcs-16/types.d.ts +3 -5
- package/dist/cjs/hcs-16/types.d.ts.map +1 -1
- package/dist/cjs/hcs-18/discovery.d.ts +1 -0
- package/dist/cjs/hcs-18/discovery.d.ts.map +1 -1
- package/dist/cjs/hcs-18/types.d.ts +1 -0
- package/dist/cjs/hcs-18/types.d.ts.map +1 -1
- package/dist/cjs/hcs-20/sdk.d.ts.map +1 -1
- package/dist/cjs/hcs-7/evm-bridge.d.ts.map +1 -1
- package/dist/cjs/hcs-7/redis-cache.d.ts.map +1 -1
- package/dist/cjs/hcs-7/wasm-bridge.d.ts.map +1 -1
- package/dist/cjs/{index-xZmk-HBD.cjs → index-CJsmyij2.cjs} +12 -12
- package/dist/cjs/index-CJsmyij2.cjs.map +1 -0
- package/dist/cjs/{index-CyAbgH2f-Cv8mxAhS.cjs → index-CyAbgH2f-Dn5WQtPx.cjs} +2 -2
- package/dist/cjs/{index-CyAbgH2f-Cv8mxAhS.cjs.map → index-CyAbgH2f-Dn5WQtPx.cjs.map} +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/services/types.d.ts +1 -1
- package/dist/cjs/services/types.d.ts.map +1 -1
- package/dist/cjs/standards-sdk.cjs +1 -1
- package/dist/cjs/{standards-sdk.es45-BxAtDqsy-ELd4REyl.cjs → standards-sdk.es45-BxAtDqsy-CiMtsDbD.cjs} +2 -2
- package/dist/cjs/{standards-sdk.es45-BxAtDqsy-ELd4REyl.cjs.map → standards-sdk.es45-BxAtDqsy-CiMtsDbD.cjs.map} +1 -1
- package/dist/cjs/{standards-sdk.es46-BI8ACeLM-DRmcgoN0.cjs → standards-sdk.es46-BI8ACeLM-DFYgO-fP.cjs} +2 -2
- package/dist/cjs/{standards-sdk.es46-BI8ACeLM-DRmcgoN0.cjs.map → standards-sdk.es46-BI8ACeLM-DFYgO-fP.cjs.map} +1 -1
- package/dist/cjs/{standards-sdk.es47-DbkY3FlD-DfMpZygD.cjs → standards-sdk.es47-DbkY3FlD-2qTWs2BD.cjs} +2 -2
- package/dist/cjs/{standards-sdk.es47-DbkY3FlD-DfMpZygD.cjs.map → standards-sdk.es47-DbkY3FlD-2qTWs2BD.cjs.map} +1 -1
- package/dist/cjs/{standards-sdk.es48-DzT9Qc3F-CmCkJl3x.cjs → standards-sdk.es48-DzT9Qc3F-Byz0fQnW.cjs} +2 -2
- package/dist/cjs/{standards-sdk.es48-DzT9Qc3F-CmCkJl3x.cjs.map → standards-sdk.es48-DzT9Qc3F-Byz0fQnW.cjs.map} +1 -1
- package/dist/cjs/utils/logger.d.ts.map +1 -1
- package/dist/es/hcs-10/base-client.d.ts +1 -1
- package/dist/es/hcs-10/base-client.d.ts.map +1 -1
- package/dist/es/hcs-10/sdk.d.ts +1 -1
- package/dist/es/hcs-10/sdk.d.ts.map +1 -1
- package/dist/es/hcs-11/agent-builder.d.ts +2 -0
- package/dist/es/hcs-11/agent-builder.d.ts.map +1 -1
- package/dist/es/hcs-11/client.d.ts +2 -0
- package/dist/es/hcs-11/client.d.ts.map +1 -1
- package/dist/es/hcs-11/types.d.ts +4 -2
- package/dist/es/hcs-11/types.d.ts.map +1 -1
- package/dist/es/hcs-15/index.d.ts +3 -0
- package/dist/es/hcs-15/index.d.ts.map +1 -0
- package/dist/es/hcs-15/petal-manager.d.ts +27 -0
- package/dist/es/hcs-15/petal-manager.d.ts.map +1 -0
- package/dist/es/hcs-15/types.d.ts +41 -0
- package/dist/es/hcs-15/types.d.ts.map +1 -0
- package/dist/es/hcs-16/flora-account-manager.d.ts.map +1 -1
- package/dist/es/hcs-16/types.d.ts +3 -5
- package/dist/es/hcs-16/types.d.ts.map +1 -1
- package/dist/es/hcs-18/discovery.d.ts +1 -0
- package/dist/es/hcs-18/discovery.d.ts.map +1 -1
- package/dist/es/hcs-18/types.d.ts +1 -0
- package/dist/es/hcs-18/types.d.ts.map +1 -1
- package/dist/es/hcs-20/sdk.d.ts.map +1 -1
- package/dist/es/hcs-7/evm-bridge.d.ts.map +1 -1
- package/dist/es/hcs-7/redis-cache.d.ts.map +1 -1
- package/dist/es/hcs-7/wasm-bridge.d.ts.map +1 -1
- package/dist/es/index.d.ts +1 -1
- package/dist/es/services/types.d.ts +1 -1
- package/dist/es/services/types.d.ts.map +1 -1
- package/dist/es/standards-sdk.es.js +19 -22
- package/dist/es/standards-sdk.es.js.map +1 -1
- package/dist/es/standards-sdk.es10.js +1 -1
- package/dist/es/standards-sdk.es11.js +10 -2
- package/dist/es/standards-sdk.es11.js.map +1 -1
- package/dist/es/standards-sdk.es12.js +1 -1
- package/dist/es/standards-sdk.es13.js +1 -1
- package/dist/es/standards-sdk.es13.js.map +1 -1
- package/dist/es/standards-sdk.es14.js +1 -1
- package/dist/es/standards-sdk.es15.js +39 -9
- package/dist/es/standards-sdk.es15.js.map +1 -1
- package/dist/es/standards-sdk.es16.js +1 -0
- package/dist/es/standards-sdk.es16.js.map +1 -1
- package/dist/es/standards-sdk.es18.js +1 -1
- package/dist/es/standards-sdk.es19.js +1 -1
- package/dist/es/standards-sdk.es2.js +1 -1
- package/dist/es/standards-sdk.es20.js +2 -2
- package/dist/es/standards-sdk.es23.js +2 -2
- package/dist/es/standards-sdk.es25.js +4 -2
- package/dist/es/standards-sdk.es25.js.map +1 -1
- package/dist/es/standards-sdk.es26.js +2 -2
- package/dist/es/standards-sdk.es27.js +152 -6
- package/dist/es/standards-sdk.es27.js.map +1 -1
- package/dist/es/standards-sdk.es28.js +26 -189
- package/dist/es/standards-sdk.es28.js.map +1 -1
- package/dist/es/standards-sdk.es29.js +446 -26
- package/dist/es/standards-sdk.es29.js.map +1 -1
- package/dist/es/standards-sdk.es3.js +1 -1
- package/dist/es/standards-sdk.es3.js.map +1 -1
- package/dist/es/standards-sdk.es30.js +6 -342
- package/dist/es/standards-sdk.es30.js.map +1 -1
- package/dist/es/standards-sdk.es31.js +202 -6
- package/dist/es/standards-sdk.es31.js.map +1 -1
- package/dist/es/standards-sdk.es32.js +34 -202
- package/dist/es/standards-sdk.es32.js.map +1 -1
- package/dist/es/standards-sdk.es33.js +529 -34
- package/dist/es/standards-sdk.es33.js.map +1 -1
- package/dist/es/standards-sdk.es34.js +87 -501
- package/dist/es/standards-sdk.es34.js.map +1 -1
- package/dist/es/standards-sdk.es35.js +19 -98
- package/dist/es/standards-sdk.es35.js.map +1 -1
- package/dist/es/standards-sdk.es36.js +156 -18
- package/dist/es/standards-sdk.es36.js.map +1 -1
- package/dist/es/standards-sdk.es37.js +146 -150
- package/dist/es/standards-sdk.es37.js.map +1 -1
- package/dist/es/standards-sdk.es38.js +561 -134
- package/dist/es/standards-sdk.es38.js.map +1 -1
- package/dist/es/standards-sdk.es39.js +562 -543
- package/dist/es/standards-sdk.es39.js.map +1 -1
- package/dist/es/standards-sdk.es4.js +6 -4
- package/dist/es/standards-sdk.es4.js.map +1 -1
- package/dist/es/standards-sdk.es40.js +4 -601
- package/dist/es/standards-sdk.es40.js.map +1 -1
- package/dist/es/standards-sdk.es41.js +415 -4
- package/dist/es/standards-sdk.es41.js.map +1 -1
- package/dist/es/standards-sdk.es42.js +1536 -389
- package/dist/es/standards-sdk.es42.js.map +1 -1
- package/dist/es/standards-sdk.es43.js +133 -1541
- package/dist/es/standards-sdk.es43.js.map +1 -1
- package/dist/es/standards-sdk.es44.js +7 -155
- package/dist/es/standards-sdk.es44.js.map +1 -1
- package/dist/es/standards-sdk.es45.js +2 -7
- package/dist/es/standards-sdk.es45.js.map +1 -1
- package/dist/es/standards-sdk.es46.js +5 -5
- package/dist/es/standards-sdk.es48.js +1 -1
- package/dist/es/standards-sdk.es49.js +1 -1
- package/dist/es/standards-sdk.es5.js +4 -6
- package/dist/es/standards-sdk.es5.js.map +1 -1
- package/dist/es/standards-sdk.es50.js +1 -1
- package/dist/es/standards-sdk.es51.js +1 -1
- package/dist/es/standards-sdk.es52.js +1 -1
- package/dist/es/standards-sdk.es54.js +7135 -2
- package/dist/es/standards-sdk.es54.js.map +1 -1
- package/dist/es/standards-sdk.es55.js +7134 -41
- package/dist/es/standards-sdk.es55.js.map +1 -1
- package/dist/es/standards-sdk.es56.js +37 -37
- package/dist/es/standards-sdk.es56.js.map +1 -1
- package/dist/es/standards-sdk.es57.js +37 -37
- package/dist/es/standards-sdk.es57.js.map +1 -1
- package/dist/es/standards-sdk.es58.js +78 -72
- package/dist/es/standards-sdk.es58.js.map +1 -1
- package/dist/es/standards-sdk.es59.js +41 -7134
- package/dist/es/standards-sdk.es59.js.map +1 -1
- package/dist/es/standards-sdk.es6.js.map +1 -1
- package/dist/es/standards-sdk.es7.js +28 -22
- package/dist/es/standards-sdk.es7.js.map +1 -1
- package/dist/es/standards-sdk.es8.js +5 -5
- package/dist/es/utils/logger.d.ts.map +1 -1
- package/package.json +37 -35
- package/dist/cjs/hcs-21/index.d.ts +0 -4
- package/dist/cjs/hcs-21/index.d.ts.map +0 -1
- package/dist/cjs/hcs-21/petal-account-manager.d.ts +0 -52
- package/dist/cjs/hcs-21/petal-account-manager.d.ts.map +0 -1
- package/dist/cjs/hcs-21/types.d.ts +0 -44
- package/dist/cjs/hcs-21/types.d.ts.map +0 -1
- package/dist/cjs/index-xZmk-HBD.cjs.map +0 -1
- package/dist/es/hcs-21/index.d.ts +0 -4
- package/dist/es/hcs-21/index.d.ts.map +0 -1
- package/dist/es/hcs-21/petal-account-manager.d.ts +0 -52
- package/dist/es/hcs-21/petal-account-manager.d.ts.map +0 -1
- package/dist/es/hcs-21/types.d.ts +0 -44
- package/dist/es/hcs-21/types.d.ts.map +0 -1
- package/dist/es/standards-sdk.es60.js +0 -7144
- package/dist/es/standards-sdk.es60.js.map +0 -1
|
@@ -1,39 +1,534 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import { PublicKey, TopicMessageSubmitTransaction } from "@hashgraph/sdk";
|
|
2
|
+
import { Logger } from "./standards-sdk.es34.js";
|
|
3
|
+
import { DiscoveryState, DiscoveryError, DiscoveryErrorCodes, DiscoveryOperation } from "./standards-sdk.es32.js";
|
|
4
|
+
import { FloraAccountManager } from "./standards-sdk.es29.js";
|
|
5
|
+
class FloraDiscovery {
|
|
6
|
+
// Track proposals being processed
|
|
7
|
+
constructor(config, baseClient, client, logger) {
|
|
8
|
+
this.state = DiscoveryState.IDLE;
|
|
9
|
+
this.lastSequenceNumber = 0;
|
|
10
|
+
this.announcements = /* @__PURE__ */ new Map();
|
|
11
|
+
this.proposals = /* @__PURE__ */ new Map();
|
|
12
|
+
this.formations = /* @__PURE__ */ new Map();
|
|
13
|
+
this.floraCreationInProgress = /* @__PURE__ */ new Set();
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.mirrorNode = baseClient.mirrorNode;
|
|
16
|
+
this.logger = logger || new Logger({ module: "FloraDiscovery" });
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.eventEmitter = config.onDiscoveryEvent;
|
|
19
|
+
if (client) {
|
|
20
|
+
this.floraClient = new FloraAccountManager(
|
|
21
|
+
client,
|
|
22
|
+
baseClient.network,
|
|
23
|
+
this.logger
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start discovery service
|
|
29
|
+
*/
|
|
30
|
+
async startDiscovery() {
|
|
31
|
+
if (this.state !== DiscoveryState.IDLE) {
|
|
32
|
+
throw new DiscoveryError(
|
|
33
|
+
"Discovery already started",
|
|
34
|
+
DiscoveryErrorCodes.ALREADY_IN_DISCOVERY
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
this.logger.info("Starting Flora discovery");
|
|
38
|
+
await this.syncDiscoveryTopic();
|
|
39
|
+
this.state = DiscoveryState.ANNOUNCED;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Announce Petal availability
|
|
43
|
+
*/
|
|
44
|
+
async announceAvailability(validFor = 1e4) {
|
|
45
|
+
if (!this.client) {
|
|
46
|
+
throw new DiscoveryError(
|
|
47
|
+
"Client required for announcements",
|
|
48
|
+
DiscoveryErrorCodes.INVALID_STATE
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const message = {
|
|
52
|
+
p: "hcs-18",
|
|
53
|
+
op: DiscoveryOperation.ANNOUNCE,
|
|
54
|
+
data: {
|
|
55
|
+
account: this.config.accountId,
|
|
56
|
+
petal: {
|
|
57
|
+
name: this.config.petalName,
|
|
58
|
+
priority: this.config.priority
|
|
59
|
+
},
|
|
60
|
+
capabilities: this.config.capabilities,
|
|
61
|
+
valid_for: validFor
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const sequenceNumber = await this.sendDiscoveryMessage(message);
|
|
65
|
+
this.myAnnouncementSeq = sequenceNumber;
|
|
66
|
+
this.state = DiscoveryState.ANNOUNCED;
|
|
67
|
+
this.emitEvent({
|
|
68
|
+
type: "announcement_received",
|
|
69
|
+
sequenceNumber,
|
|
70
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
71
|
+
data: message.data
|
|
72
|
+
});
|
|
73
|
+
return sequenceNumber;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Propose Flora formation
|
|
77
|
+
*/
|
|
78
|
+
async proposeFloraFormation(memberAccounts, config) {
|
|
79
|
+
if (!this.client) {
|
|
80
|
+
throw new DiscoveryError(
|
|
81
|
+
"Client required for proposals",
|
|
82
|
+
DiscoveryErrorCodes.INVALID_STATE
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const members = memberAccounts.map((account) => {
|
|
86
|
+
const announcement = Array.from(this.announcements.values()).find(
|
|
87
|
+
(a) => a.account === account
|
|
88
|
+
);
|
|
89
|
+
return {
|
|
90
|
+
account,
|
|
91
|
+
announce_seq: announcement?.sequenceNumber,
|
|
92
|
+
priority: announcement?.data.petal.priority || 500
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
const proposeData = {
|
|
96
|
+
proposer: this.config.accountId,
|
|
97
|
+
members,
|
|
98
|
+
config
|
|
99
|
+
};
|
|
100
|
+
const message = {
|
|
101
|
+
p: "hcs-18",
|
|
102
|
+
op: DiscoveryOperation.PROPOSE,
|
|
103
|
+
data: proposeData
|
|
104
|
+
};
|
|
105
|
+
const sequenceNumber = await this.sendDiscoveryMessage(message);
|
|
106
|
+
this.state = DiscoveryState.PROPOSING;
|
|
107
|
+
this.emitEvent({
|
|
108
|
+
type: "proposal_received",
|
|
109
|
+
sequenceNumber,
|
|
110
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
111
|
+
data: proposeData
|
|
112
|
+
});
|
|
113
|
+
return sequenceNumber;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Respond to Flora proposal
|
|
117
|
+
*/
|
|
118
|
+
async respondToProposal(proposalSeq, decision, reason) {
|
|
119
|
+
if (!this.client) {
|
|
120
|
+
throw new DiscoveryError(
|
|
121
|
+
"Client required for responses",
|
|
122
|
+
DiscoveryErrorCodes.INVALID_STATE
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
await this.syncDiscoveryTopic();
|
|
126
|
+
const proposal = this.proposals.get(proposalSeq);
|
|
127
|
+
if (!proposal) {
|
|
128
|
+
throw new DiscoveryError(
|
|
129
|
+
`Proposal ${proposalSeq} not found`,
|
|
130
|
+
DiscoveryErrorCodes.INVALID_MESSAGE
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
const responseData = {
|
|
134
|
+
responder: this.config.accountId,
|
|
135
|
+
proposal_seq: proposalSeq,
|
|
136
|
+
decision,
|
|
137
|
+
reason
|
|
138
|
+
};
|
|
139
|
+
const message = {
|
|
140
|
+
p: "hcs-18",
|
|
141
|
+
op: DiscoveryOperation.RESPOND,
|
|
142
|
+
data: responseData
|
|
143
|
+
};
|
|
144
|
+
await this.sendDiscoveryMessage(message);
|
|
145
|
+
this.emitEvent({
|
|
146
|
+
type: "response_received",
|
|
147
|
+
sequenceNumber: proposalSeq,
|
|
148
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
149
|
+
data: responseData
|
|
150
|
+
});
|
|
151
|
+
if (decision === "accept") {
|
|
152
|
+
this.state = DiscoveryState.FORMING;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Find compatible Petals for Flora formation
|
|
157
|
+
*/
|
|
158
|
+
findCompatiblePetals(filters = {}) {
|
|
159
|
+
const candidates = Array.from(this.announcements.values()).filter((announcement) => {
|
|
160
|
+
if (announcement.account === this.config.accountId) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
if (filters.protocols?.length) {
|
|
164
|
+
const hasCompatibleProtocol = filters.protocols.some(
|
|
165
|
+
(protocol) => announcement.data.capabilities.protocols.includes(protocol)
|
|
166
|
+
);
|
|
167
|
+
if (!hasCompatibleProtocol) return false;
|
|
168
|
+
}
|
|
169
|
+
if (filters.minPriority && announcement.data.petal.priority < filters.minPriority) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
return true;
|
|
173
|
+
}).sort((a, b) => b.data.petal.priority - a.data.petal.priority);
|
|
174
|
+
return filters.maxMembers ? candidates.slice(0, filters.maxMembers) : candidates;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get current discovery state
|
|
178
|
+
*/
|
|
179
|
+
getState() {
|
|
180
|
+
return this.state;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get tracked announcements
|
|
184
|
+
*/
|
|
185
|
+
getAnnouncements() {
|
|
186
|
+
return new Map(this.announcements);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get tracked proposals
|
|
190
|
+
*/
|
|
191
|
+
getProposals() {
|
|
192
|
+
return new Map(this.proposals);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get Flora formations
|
|
196
|
+
*/
|
|
197
|
+
getFormations() {
|
|
198
|
+
return new Map(this.formations);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Complete Flora formation (called by proposer)
|
|
202
|
+
*/
|
|
203
|
+
async completeFloraFormation(proposalSeq, floraAccountId, topics) {
|
|
204
|
+
if (!this.client) {
|
|
205
|
+
throw new DiscoveryError(
|
|
206
|
+
"Client required for completion",
|
|
207
|
+
DiscoveryErrorCodes.INVALID_STATE
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
const proposal = this.proposals.get(proposalSeq);
|
|
211
|
+
if (!proposal) {
|
|
212
|
+
throw new DiscoveryError(
|
|
213
|
+
`Proposal ${proposalSeq} not found`,
|
|
214
|
+
DiscoveryErrorCodes.INVALID_MESSAGE
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
const message = {
|
|
218
|
+
p: "hcs-18",
|
|
219
|
+
op: DiscoveryOperation.COMPLETE,
|
|
220
|
+
data: {
|
|
221
|
+
proposer: this.config.accountId,
|
|
222
|
+
proposal_seq: proposalSeq,
|
|
223
|
+
flora_account: floraAccountId,
|
|
224
|
+
topics
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
await this.sendDiscoveryMessage(message);
|
|
228
|
+
const formation = {
|
|
229
|
+
proposalSeq,
|
|
230
|
+
floraAccountId,
|
|
231
|
+
topics,
|
|
232
|
+
members: proposal.data.members.map((m) => ({
|
|
233
|
+
account: m.account,
|
|
234
|
+
priority: m.priority
|
|
235
|
+
})),
|
|
236
|
+
threshold: proposal.data.config.threshold,
|
|
237
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
238
|
+
};
|
|
239
|
+
this.formations.set(proposalSeq, formation);
|
|
240
|
+
this.state = DiscoveryState.ACTIVE;
|
|
241
|
+
this.emitEvent({
|
|
242
|
+
type: "formation_complete",
|
|
243
|
+
sequenceNumber: proposalSeq,
|
|
244
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
245
|
+
data: formation
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Withdraw from discovery
|
|
250
|
+
*/
|
|
251
|
+
async withdraw(reason) {
|
|
252
|
+
if (!this.client || !this.myAnnouncementSeq) {
|
|
253
|
+
throw new DiscoveryError(
|
|
254
|
+
"No active announcement to withdraw",
|
|
255
|
+
DiscoveryErrorCodes.INVALID_STATE
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
const message = {
|
|
259
|
+
p: "hcs-18",
|
|
260
|
+
op: DiscoveryOperation.WITHDRAW,
|
|
261
|
+
data: {
|
|
262
|
+
account: this.config.accountId,
|
|
263
|
+
announce_seq: this.myAnnouncementSeq,
|
|
264
|
+
reason
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
await this.sendDiscoveryMessage(message);
|
|
268
|
+
this.state = DiscoveryState.WITHDRAWN;
|
|
269
|
+
this.emitEvent({
|
|
270
|
+
type: "withdrawal_received",
|
|
271
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
272
|
+
data: message.data
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Sync discovery topic and process messages
|
|
277
|
+
*/
|
|
278
|
+
async syncDiscoveryTopic() {
|
|
279
|
+
try {
|
|
280
|
+
const messages = await this.mirrorNode.getTopicMessages(
|
|
281
|
+
this.config.discoveryTopicId.toString(),
|
|
282
|
+
{
|
|
283
|
+
sequenceNumber: this.lastSequenceNumber + 1
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
for (const message of messages) {
|
|
287
|
+
try {
|
|
288
|
+
if (message.p !== "hcs-18") {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const discoveryMessage = message;
|
|
292
|
+
await this.processDiscoveryMessage(
|
|
293
|
+
discoveryMessage,
|
|
294
|
+
message.sequence_number
|
|
295
|
+
);
|
|
296
|
+
this.lastSequenceNumber = message.sequence_number;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
if (error instanceof DiscoveryError && error.code === DiscoveryErrorCodes.FLORA_CREATION_FAILED) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
this.logger.error("Failed to sync discovery topic", error);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Process discovered messages
|
|
309
|
+
*/
|
|
310
|
+
async processDiscoveryMessage(message, sequenceNumber) {
|
|
311
|
+
switch (message.op) {
|
|
312
|
+
case DiscoveryOperation.ANNOUNCE:
|
|
313
|
+
await this.handleAnnouncement(
|
|
314
|
+
message,
|
|
315
|
+
sequenceNumber
|
|
316
|
+
);
|
|
317
|
+
break;
|
|
318
|
+
case DiscoveryOperation.PROPOSE:
|
|
319
|
+
await this.handleProposal(message, sequenceNumber);
|
|
320
|
+
break;
|
|
321
|
+
case DiscoveryOperation.RESPOND:
|
|
322
|
+
await this.handleResponse(message, sequenceNumber);
|
|
323
|
+
break;
|
|
324
|
+
case DiscoveryOperation.COMPLETE:
|
|
325
|
+
await this.handleCompletion(message, sequenceNumber);
|
|
326
|
+
break;
|
|
327
|
+
case DiscoveryOperation.WITHDRAW:
|
|
328
|
+
await this.handleWithdrawal(message, sequenceNumber);
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Handle announcement message
|
|
334
|
+
*/
|
|
335
|
+
async handleAnnouncement(message, sequenceNumber) {
|
|
336
|
+
const announcement = {
|
|
337
|
+
account: message.data.account,
|
|
338
|
+
sequenceNumber,
|
|
339
|
+
consensusTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
340
|
+
data: message.data
|
|
341
|
+
};
|
|
342
|
+
this.announcements.set(sequenceNumber, announcement);
|
|
343
|
+
if (message.data.account === this.config.accountId) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
this.emitEvent({
|
|
347
|
+
type: "announcement_received",
|
|
348
|
+
sequenceNumber,
|
|
349
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
350
|
+
data: message.data
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Handle proposal message
|
|
355
|
+
*/
|
|
356
|
+
async handleProposal(message, sequenceNumber) {
|
|
357
|
+
const proposal = {
|
|
358
|
+
sequenceNumber,
|
|
359
|
+
consensusTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
360
|
+
proposer: message.data.proposer,
|
|
361
|
+
data: message.data,
|
|
362
|
+
responses: /* @__PURE__ */ new Map()
|
|
363
|
+
};
|
|
364
|
+
this.proposals.set(sequenceNumber, proposal);
|
|
365
|
+
if (this.config.autoAcceptFilter?.(proposal)) {
|
|
366
|
+
await this.respondToProposal(sequenceNumber, "accept");
|
|
367
|
+
}
|
|
368
|
+
const isIncluded = message.data.members.some(
|
|
369
|
+
(m) => m.account === this.config.accountId
|
|
370
|
+
);
|
|
371
|
+
if (isIncluded) {
|
|
372
|
+
this.emitEvent({
|
|
373
|
+
type: "proposal_received",
|
|
374
|
+
sequenceNumber,
|
|
375
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
376
|
+
data: message.data
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Handle response message
|
|
382
|
+
*/
|
|
383
|
+
async handleResponse(message, sequenceNumber) {
|
|
384
|
+
const proposal = this.proposals.get(message.data.proposal_seq);
|
|
385
|
+
if (proposal) {
|
|
386
|
+
proposal.responses.set(message.data.responder, message.data);
|
|
387
|
+
if (this.isProposalReady(proposal)) {
|
|
388
|
+
if (proposal.data.proposer === this.config.accountId && this.floraClient && !this.floraCreationInProgress.has(message.data.proposal_seq)) {
|
|
389
|
+
this.floraCreationInProgress.add(message.data.proposal_seq);
|
|
390
|
+
try {
|
|
391
|
+
await this.createFloraFromProposal(proposal);
|
|
392
|
+
} finally {
|
|
393
|
+
this.floraCreationInProgress.delete(message.data.proposal_seq);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
this.emitEvent({
|
|
399
|
+
type: "response_received",
|
|
400
|
+
sequenceNumber,
|
|
401
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
402
|
+
data: message.data
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Handle completion message
|
|
407
|
+
*/
|
|
408
|
+
async handleCompletion(message, sequenceNumber) {
|
|
409
|
+
const formation = {
|
|
410
|
+
proposalSeq: message.data.proposal_seq,
|
|
411
|
+
floraAccountId: message.data.flora_account,
|
|
412
|
+
topics: message.data.topics,
|
|
413
|
+
members: [],
|
|
414
|
+
threshold: 0,
|
|
415
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
416
|
+
};
|
|
417
|
+
if (this.isPartOfFormation(formation)) {
|
|
418
|
+
this.state = DiscoveryState.ACTIVE;
|
|
419
|
+
}
|
|
420
|
+
this.formations.set(message.data.proposal_seq, formation);
|
|
421
|
+
this.emitEvent({
|
|
422
|
+
type: "formation_complete",
|
|
423
|
+
sequenceNumber,
|
|
424
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
425
|
+
data: formation
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Handle withdrawal message
|
|
430
|
+
*/
|
|
431
|
+
async handleWithdrawal(message, sequenceNumber) {
|
|
432
|
+
this.announcements.delete(message.data.announce_seq);
|
|
433
|
+
this.emitEvent({
|
|
434
|
+
type: "withdrawal_received",
|
|
435
|
+
sequenceNumber,
|
|
436
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
437
|
+
data: message.data
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Check if proposal has enough responses
|
|
442
|
+
*/
|
|
443
|
+
isProposalReady(proposal) {
|
|
444
|
+
const acceptances = Array.from(proposal.responses.values()).filter(
|
|
445
|
+
(r) => r.decision === "accept"
|
|
446
|
+
);
|
|
447
|
+
const requiredResponses = proposal.data.members.length - 1;
|
|
448
|
+
return acceptances.length >= requiredResponses;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Check if we're part of a Flora formation
|
|
452
|
+
*/
|
|
453
|
+
isPartOfFormation(formation) {
|
|
454
|
+
return formation.members.some((m) => m.account === this.config.accountId);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Create Flora from accepted proposal
|
|
458
|
+
*/
|
|
459
|
+
async createFloraFromProposal(proposal) {
|
|
460
|
+
if (!this.floraClient) {
|
|
461
|
+
throw new DiscoveryError(
|
|
462
|
+
"Flora client not available",
|
|
463
|
+
DiscoveryErrorCodes.FLORA_CREATION_FAILED
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const memberPubKeys = await Promise.all(
|
|
468
|
+
proposal.data.members.map(async (m) => {
|
|
469
|
+
const accountInfo = await this.mirrorNode.requestAccount(m.account);
|
|
470
|
+
const privateKey = this.config.memberPrivateKeys?.get(m.account);
|
|
471
|
+
return {
|
|
472
|
+
accountId: m.account,
|
|
473
|
+
publicKey: PublicKey.fromString(accountInfo.key.key),
|
|
474
|
+
privateKey
|
|
475
|
+
// Include private key if available
|
|
476
|
+
};
|
|
477
|
+
})
|
|
478
|
+
);
|
|
479
|
+
if (!memberPubKeys[0].privateKey) {
|
|
480
|
+
throw new DiscoveryError(
|
|
481
|
+
"First member must have private key for Flora profile creation",
|
|
482
|
+
DiscoveryErrorCodes.FLORA_CREATION_FAILED
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
const floraResult = await this.floraClient.createFlora({
|
|
486
|
+
members: memberPubKeys,
|
|
487
|
+
threshold: proposal.data.config.threshold,
|
|
488
|
+
initialBalance: 10,
|
|
489
|
+
displayName: proposal.data.config.name
|
|
490
|
+
});
|
|
491
|
+
await this.completeFloraFormation(
|
|
492
|
+
proposal.sequenceNumber,
|
|
493
|
+
floraResult.floraAccountId.toString(),
|
|
494
|
+
{
|
|
495
|
+
communication: floraResult.topics.communication.toString(),
|
|
496
|
+
transaction: floraResult.topics.transaction.toString(),
|
|
497
|
+
state: floraResult.topics.state.toString()
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
} catch (error) {
|
|
501
|
+
this.logger.error("Failed to create Flora", { error: error instanceof Error ? error.message : error });
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Send message to discovery topic
|
|
507
|
+
*/
|
|
508
|
+
async sendDiscoveryMessage(message) {
|
|
509
|
+
if (!this.client) {
|
|
510
|
+
throw new DiscoveryError(
|
|
511
|
+
"Client required for sending messages",
|
|
512
|
+
DiscoveryErrorCodes.INVALID_STATE
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
const payload = JSON.stringify(message);
|
|
516
|
+
const transaction = new TopicMessageSubmitTransaction().setTopicId(this.config.discoveryTopicId).setMessage(payload);
|
|
517
|
+
const response = await transaction.execute(this.client);
|
|
518
|
+
const receipt = await response.getReceipt(this.client);
|
|
519
|
+
return receipt.topicSequenceNumber.toNumber();
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Emit discovery event
|
|
523
|
+
*/
|
|
524
|
+
emitEvent(event) {
|
|
525
|
+
if (this.eventEmitter) {
|
|
526
|
+
this.eventEmitter(event);
|
|
527
|
+
}
|
|
23
528
|
}
|
|
24
529
|
}
|
|
25
|
-
const DiscoveryErrorCodes = {
|
|
26
|
-
INVALID_MESSAGE: "INVALID_MESSAGE",
|
|
27
|
-
TIMEOUT: "TIMEOUT",
|
|
28
|
-
INSUFFICIENT_PETALS: "INSUFFICIENT_PETALS",
|
|
29
|
-
FLORA_CREATION_FAILED: "FLORA_CREATION_FAILED",
|
|
30
|
-
ALREADY_IN_DISCOVERY: "ALREADY_IN_DISCOVERY",
|
|
31
|
-
INVALID_STATE: "INVALID_STATE"
|
|
32
|
-
};
|
|
33
530
|
export {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
DiscoveryOperation,
|
|
37
|
-
DiscoveryState
|
|
531
|
+
FloraDiscovery,
|
|
532
|
+
FloraDiscovery as HCS18Discovery
|
|
38
533
|
};
|
|
39
534
|
//# sourceMappingURL=standards-sdk.es33.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standards-sdk.es33.js","sources":["../../src/hcs-18/types.ts"],"sourcesContent":["/**\n * HCS-18 Flora Discovery Protocol Types\n * Standard for Flora discovery and formation\n */\n\nimport { AccountId, TopicId, PublicKey } from '@hashgraph/sdk';\n\n/**\n * HCS-18 Operation types\n */\nexport enum DiscoveryOperation {\n ANNOUNCE = 'announce',\n PROPOSE = 'propose',\n RESPOND = 'respond',\n COMPLETE = 'complete',\n WITHDRAW = 'withdraw',\n}\n\n/**\n * Base HCS-18 message structure\n */\nexport interface DiscoveryMessage {\n p: 'hcs-18';\n op: DiscoveryOperation;\n data: any;\n}\n\n/**\n * Announce operation data\n */\nexport interface AnnounceData {\n account: string;\n petal: {\n name: string;\n priority: number;\n };\n capabilities: {\n protocols: string[];\n resources?: {\n compute?: 'high' | 'medium' | 'low';\n storage?: 'high' | 'medium' | 'low';\n bandwidth?: 'high' | 'medium' | 'low';\n };\n group_preferences?: {\n sizes?: number[];\n threshold_ratios?: number[];\n };\n };\n valid_for?: number;\n}\n\n/**\n * Propose operation data\n */\nexport interface ProposeData {\n proposer: string;\n members: Array<{\n account: string;\n announce_seq?: number;\n priority: number;\n status?: 'existing' | 'proposed';\n }>;\n config: {\n name: string;\n threshold: number;\n purpose?: string;\n reason?: string;\n };\n existing_flora?: string;\n}\n\n/**\n * Respond operation data\n */\nexport interface RespondData {\n responder: string;\n proposal_seq: number;\n decision: 'accept' | 'reject';\n reason?: string;\n accepted_seq?: number;\n}\n\n/**\n * Complete operation data\n */\nexport interface CompleteData {\n proposer: string;\n proposal_seq: number;\n flora_account: string;\n topics: {\n communication: string;\n transaction: string;\n state: string;\n };\n}\n\n/**\n * Withdraw operation data\n */\nexport interface WithdrawData {\n account: string;\n announce_seq: number;\n reason?: string;\n}\n\n/**\n * Typed message operations\n */\nexport interface AnnounceMessage extends DiscoveryMessage {\n op: DiscoveryOperation.ANNOUNCE;\n data: AnnounceData;\n}\n\nexport interface ProposeMessage extends DiscoveryMessage {\n op: DiscoveryOperation.PROPOSE;\n data: ProposeData;\n}\n\nexport interface RespondMessage extends DiscoveryMessage {\n op: DiscoveryOperation.RESPOND;\n data: RespondData;\n}\n\nexport interface CompleteMessage extends DiscoveryMessage {\n op: DiscoveryOperation.COMPLETE;\n data: CompleteData;\n}\n\nexport interface WithdrawMessage extends DiscoveryMessage {\n op: DiscoveryOperation.WITHDRAW;\n data: WithdrawData;\n}\n\n/**\n * Discovery phase states\n */\nexport enum DiscoveryState {\n IDLE = 'idle',\n ANNOUNCED = 'announced',\n PROPOSING = 'proposing',\n FORMING = 'forming',\n ACTIVE = 'active',\n WITHDRAWN = 'withdrawn',\n}\n\n/**\n * Tracked announcement with HCS metadata\n */\nexport interface TrackedAnnouncement {\n account: string;\n sequenceNumber: number;\n consensusTimestamp: string;\n data: AnnounceData;\n}\n\n/**\n * Tracked proposal with HCS metadata\n */\nexport interface TrackedProposal {\n sequenceNumber: number;\n consensusTimestamp: string;\n proposer: string;\n data: ProposeData;\n responses: Map<string, RespondData>;\n}\n\n/**\n * Flora formation result\n */\nexport interface FloraFormation {\n proposalSeq: number;\n floraAccountId: string;\n topics: {\n communication: string;\n transaction: string;\n state: string;\n };\n members: Array<{\n account: string;\n priority: number;\n }>;\n threshold: number;\n createdAt: Date;\n}\n\n/**\n * Discovery event types for monitoring\n */\nexport interface DiscoveryEvent {\n type:\n | 'announcement_received'\n | 'proposal_received'\n | 'response_received'\n | 'formation_complete'\n | 'withdrawal_received'\n | 'discovery_timeout';\n sequenceNumber?: number;\n timestamp: Date;\n data: any;\n}\n\n/**\n * Discovery configuration\n */\nexport interface DiscoveryConfig {\n discoveryTopicId: string | TopicId;\n accountId: string;\n petalName: string;\n priority: number;\n capabilities: {\n protocols: string[];\n resources?: AnnounceData['capabilities']['resources'];\n group_preferences?: AnnounceData['capabilities']['group_preferences'];\n };\n autoAcceptFilter?: (proposal: TrackedProposal) => boolean;\n onDiscoveryEvent?: (event: DiscoveryEvent) => void;\n}\n\n/**\n * HCS-18 Errors\n */\nexport class DiscoveryError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'DiscoveryError';\n }\n}\n\nexport const DiscoveryErrorCodes = {\n INVALID_MESSAGE: 'INVALID_MESSAGE',\n TIMEOUT: 'TIMEOUT',\n INSUFFICIENT_PETALS: 'INSUFFICIENT_PETALS',\n FLORA_CREATION_FAILED: 'FLORA_CREATION_FAILED',\n ALREADY_IN_DISCOVERY: 'ALREADY_IN_DISCOVERY',\n INVALID_STATE: 'INVALID_STATE',\n} as const;\n"],"names":["DiscoveryOperation","DiscoveryState"],"mappings":"AAUO,IAAK,uCAAAA,wBAAL;AACLA,sBAAA,UAAA,IAAW;AACXA,sBAAA,SAAA,IAAU;AACVA,sBAAA,SAAA,IAAU;AACVA,sBAAA,UAAA,IAAW;AACXA,sBAAA,UAAA,IAAW;AALD,SAAAA;AAAA,GAAA,sBAAA,CAAA,CAAA;AA8HL,IAAK,mCAAAC,oBAAL;AACLA,kBAAA,MAAA,IAAO;AACPA,kBAAA,WAAA,IAAY;AACZA,kBAAA,WAAA,IAAY;AACZA,kBAAA,SAAA,IAAU;AACVA,kBAAA,QAAA,IAAS;AACTA,kBAAA,WAAA,IAAY;AANF,SAAAA;AAAA,GAAA,kBAAA,CAAA,CAAA;AAqFL,MAAM,uBAAuB,MAAM;AAAA,EACxC,YACE,SACgB,MAChB;AACA,UAAM,OAAO;AAFG,SAAA,OAAA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,sBAAsB;AAAA,EACjC,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,eAAe;AACjB;"}
|
|
1
|
+
{"version":3,"file":"standards-sdk.es33.js","sources":["../../src/hcs-18/discovery.ts"],"sourcesContent":["import {\n TopicId,\n AccountId,\n Client,\n TopicMessageSubmitTransaction,\n} from '@hashgraph/sdk';\nimport { HCS10BaseClient } from '../hcs-10/base-client';\nimport { HederaMirrorNode } from '../services/mirror-node';\nimport { Logger } from '../utils/logger';\nimport type { NetworkType } from '../utils/types';\nimport {\n DiscoveryConfig,\n DiscoveryState,\n DiscoveryMessage,\n DiscoveryOperation,\n AnnounceMessage,\n ProposeMessage,\n RespondMessage,\n CompleteMessage,\n WithdrawMessage,\n TrackedAnnouncement,\n TrackedProposal,\n FloraFormation,\n DiscoveryEvent,\n DiscoveryError,\n DiscoveryErrorCodes,\n AnnounceData,\n ProposeData,\n RespondData,\n} from './types';\nimport { FloraAccountManager } from '../hcs-16/flora-account-manager';\nimport { PublicKey } from '@hashgraph/sdk';\n\n/**\n * HCS-18 Flora Discovery Service\n */\nexport class FloraDiscovery {\n private state: DiscoveryState = DiscoveryState.IDLE;\n private config: DiscoveryConfig;\n private mirrorNode: HederaMirrorNode;\n private logger: Logger;\n private client?: Client;\n private floraClient?: FloraAccountManager;\n\n private lastSequenceNumber = 0;\n private announcements = new Map<number, TrackedAnnouncement>();\n private proposals = new Map<number, TrackedProposal>();\n private formations = new Map<number, FloraFormation>();\n private myAnnouncementSeq?: number;\n private eventEmitter?: (event: DiscoveryEvent) => void;\n private floraCreationInProgress = new Set<number>(); // Track proposals being processed\n\n constructor(\n config: DiscoveryConfig,\n baseClient: HCS10BaseClient,\n client?: Client,\n logger?: Logger,\n ) {\n this.config = config;\n this.mirrorNode = baseClient.mirrorNode;\n this.logger = logger || new Logger({ module: 'FloraDiscovery' });\n this.client = client;\n this.eventEmitter = config.onDiscoveryEvent;\n\n if (client) {\n this.floraClient = new FloraAccountManager(\n client,\n baseClient.network as NetworkType,\n this.logger,\n );\n }\n }\n\n /**\n * Start discovery service\n */\n async startDiscovery(): Promise<void> {\n if (this.state !== DiscoveryState.IDLE) {\n throw new DiscoveryError(\n 'Discovery already started',\n DiscoveryErrorCodes.ALREADY_IN_DISCOVERY,\n );\n }\n\n this.logger.info('Starting Flora discovery');\n await this.syncDiscoveryTopic();\n this.state = DiscoveryState.ANNOUNCED;\n }\n\n /**\n * Announce Petal availability\n */\n async announceAvailability(validFor = 10000): Promise<number> {\n if (!this.client) {\n throw new DiscoveryError(\n 'Client required for announcements',\n DiscoveryErrorCodes.INVALID_STATE,\n );\n }\n\n const message: AnnounceMessage = {\n p: 'hcs-18',\n op: DiscoveryOperation.ANNOUNCE,\n data: {\n account: this.config.accountId,\n petal: {\n name: this.config.petalName,\n priority: this.config.priority,\n },\n capabilities: this.config.capabilities,\n valid_for: validFor,\n },\n };\n\n const sequenceNumber = await this.sendDiscoveryMessage(message);\n this.myAnnouncementSeq = sequenceNumber;\n this.state = DiscoveryState.ANNOUNCED;\n\n this.emitEvent({\n type: 'announcement_received',\n sequenceNumber,\n timestamp: new Date(),\n data: message.data,\n });\n\n return sequenceNumber;\n }\n\n /**\n * Propose Flora formation\n */\n async proposeFloraFormation(\n memberAccounts: string[],\n config: {\n name: string;\n threshold: number;\n purpose?: string;\n },\n ): Promise<number> {\n if (!this.client) {\n throw new DiscoveryError(\n 'Client required for proposals',\n DiscoveryErrorCodes.INVALID_STATE,\n );\n }\n\n const members = memberAccounts.map(account => {\n const announcement = Array.from(this.announcements.values()).find(\n a => a.account === account,\n );\n return {\n account,\n announce_seq: announcement?.sequenceNumber,\n priority: announcement?.data.petal.priority || 500,\n };\n });\n\n const proposeData: ProposeData = {\n proposer: this.config.accountId,\n members,\n config,\n };\n\n const message: ProposeMessage = {\n p: 'hcs-18',\n op: DiscoveryOperation.PROPOSE,\n data: proposeData,\n };\n\n const sequenceNumber = await this.sendDiscoveryMessage(message);\n this.state = DiscoveryState.PROPOSING;\n\n this.emitEvent({\n type: 'proposal_received',\n sequenceNumber,\n timestamp: new Date(),\n data: proposeData,\n });\n\n return sequenceNumber;\n }\n\n /**\n * Respond to Flora proposal\n */\n async respondToProposal(\n proposalSeq: number,\n decision: 'accept' | 'reject',\n reason?: string,\n ): Promise<void> {\n if (!this.client) {\n throw new DiscoveryError(\n 'Client required for responses',\n DiscoveryErrorCodes.INVALID_STATE,\n );\n }\n\n await this.syncDiscoveryTopic();\n\n const proposal = this.proposals.get(proposalSeq);\n if (!proposal) {\n throw new DiscoveryError(\n `Proposal ${proposalSeq} not found`,\n DiscoveryErrorCodes.INVALID_MESSAGE,\n );\n }\n\n const responseData: RespondData = {\n responder: this.config.accountId,\n proposal_seq: proposalSeq,\n decision,\n reason,\n };\n\n const message: RespondMessage = {\n p: 'hcs-18',\n op: DiscoveryOperation.RESPOND,\n data: responseData,\n };\n\n await this.sendDiscoveryMessage(message);\n\n this.emitEvent({\n type: 'response_received',\n sequenceNumber: proposalSeq,\n timestamp: new Date(),\n data: responseData,\n });\n\n if (decision === 'accept') {\n this.state = DiscoveryState.FORMING;\n }\n }\n\n /**\n * Find compatible Petals for Flora formation\n */\n findCompatiblePetals(\n filters: {\n protocols?: string[];\n minPriority?: number;\n maxMembers?: number;\n resourceRequirements?: {\n compute?: 'high' | 'medium' | 'low';\n storage?: 'high' | 'medium' | 'low';\n bandwidth?: 'high' | 'medium' | 'low';\n };\n } = {},\n ): TrackedAnnouncement[] {\n const candidates = Array.from(this.announcements.values())\n .filter(announcement => {\n if (announcement.account === this.config.accountId) {\n return false;\n }\n\n if (filters.protocols?.length) {\n const hasCompatibleProtocol = filters.protocols.some(protocol =>\n announcement.data.capabilities.protocols.includes(protocol),\n );\n if (!hasCompatibleProtocol) return false;\n }\n\n if (\n filters.minPriority &&\n announcement.data.petal.priority < filters.minPriority\n ) {\n return false;\n }\n\n return true;\n })\n .sort((a, b) => b.data.petal.priority - a.data.petal.priority);\n\n return filters.maxMembers\n ? candidates.slice(0, filters.maxMembers)\n : candidates;\n }\n\n /**\n * Get current discovery state\n */\n getState(): DiscoveryState {\n return this.state;\n }\n\n /**\n * Get tracked announcements\n */\n getAnnouncements(): Map<number, TrackedAnnouncement> {\n return new Map(this.announcements);\n }\n\n /**\n * Get tracked proposals\n */\n getProposals(): Map<number, TrackedProposal> {\n return new Map(this.proposals);\n }\n\n /**\n * Get Flora formations\n */\n getFormations(): Map<number, FloraFormation> {\n return new Map(this.formations);\n }\n\n /**\n * Complete Flora formation (called by proposer)\n */\n async completeFloraFormation(\n proposalSeq: number,\n floraAccountId: string,\n topics: {\n communication: string;\n transaction: string;\n state: string;\n },\n ): Promise<void> {\n if (!this.client) {\n throw new DiscoveryError(\n 'Client required for completion',\n DiscoveryErrorCodes.INVALID_STATE,\n );\n }\n\n const proposal = this.proposals.get(proposalSeq);\n if (!proposal) {\n throw new DiscoveryError(\n `Proposal ${proposalSeq} not found`,\n DiscoveryErrorCodes.INVALID_MESSAGE,\n );\n }\n\n const message: CompleteMessage = {\n p: 'hcs-18',\n op: DiscoveryOperation.COMPLETE,\n data: {\n proposer: this.config.accountId,\n proposal_seq: proposalSeq,\n flora_account: floraAccountId,\n topics,\n },\n };\n\n await this.sendDiscoveryMessage(message);\n\n const formation: FloraFormation = {\n proposalSeq,\n floraAccountId,\n topics,\n members: proposal.data.members.map(m => ({\n account: m.account,\n priority: m.priority,\n })),\n threshold: proposal.data.config.threshold,\n createdAt: new Date(),\n };\n\n this.formations.set(proposalSeq, formation);\n this.state = DiscoveryState.ACTIVE;\n\n this.emitEvent({\n type: 'formation_complete',\n sequenceNumber: proposalSeq,\n timestamp: new Date(),\n data: formation,\n });\n }\n\n /**\n * Withdraw from discovery\n */\n async withdraw(reason?: string): Promise<void> {\n if (!this.client || !this.myAnnouncementSeq) {\n throw new DiscoveryError(\n 'No active announcement to withdraw',\n DiscoveryErrorCodes.INVALID_STATE,\n );\n }\n\n const message: WithdrawMessage = {\n p: 'hcs-18',\n op: DiscoveryOperation.WITHDRAW,\n data: {\n account: this.config.accountId,\n announce_seq: this.myAnnouncementSeq,\n reason,\n },\n };\n\n await this.sendDiscoveryMessage(message);\n this.state = DiscoveryState.WITHDRAWN;\n\n this.emitEvent({\n type: 'withdrawal_received',\n timestamp: new Date(),\n data: message.data,\n });\n }\n\n /**\n * Sync discovery topic and process messages\n */\n private async syncDiscoveryTopic(): Promise<void> {\n try {\n const messages = await this.mirrorNode.getTopicMessages(\n this.config.discoveryTopicId.toString(),\n {\n sequenceNumber: this.lastSequenceNumber + 1,\n },\n );\n\n for (const message of messages) {\n try {\n if (message.p !== 'hcs-18') {\n continue;\n }\n\n const discoveryMessage = message as unknown as DiscoveryMessage;\n await this.processDiscoveryMessage(\n discoveryMessage,\n message.sequence_number!,\n );\n this.lastSequenceNumber = message.sequence_number!;\n } catch (error) {\n if (error instanceof DiscoveryError && error.code === DiscoveryErrorCodes.FLORA_CREATION_FAILED) {\n return;\n }\n }\n }\n\n } catch (error) {\n this.logger.error('Failed to sync discovery topic', error);\n }\n }\n\n /**\n * Process discovered messages\n */\n private async processDiscoveryMessage(\n message: DiscoveryMessage,\n sequenceNumber: number,\n ): Promise<void> {\n switch (message.op) {\n case DiscoveryOperation.ANNOUNCE:\n await this.handleAnnouncement(\n message as AnnounceMessage,\n sequenceNumber,\n );\n break;\n case DiscoveryOperation.PROPOSE:\n await this.handleProposal(message as ProposeMessage, sequenceNumber);\n break;\n case DiscoveryOperation.RESPOND:\n await this.handleResponse(message as RespondMessage, sequenceNumber);\n break;\n case DiscoveryOperation.COMPLETE:\n await this.handleCompletion(message as CompleteMessage, sequenceNumber);\n break;\n case DiscoveryOperation.WITHDRAW:\n await this.handleWithdrawal(message as WithdrawMessage, sequenceNumber);\n break;\n }\n }\n\n /**\n * Handle announcement message\n */\n private async handleAnnouncement(\n message: AnnounceMessage,\n sequenceNumber: number,\n ): Promise<void> {\n const announcement: TrackedAnnouncement = {\n account: message.data.account,\n sequenceNumber,\n consensusTimestamp: new Date().toISOString(),\n data: message.data,\n };\n\n this.announcements.set(sequenceNumber, announcement);\n\n if (message.data.account === this.config.accountId) {\n return;\n }\n\n this.emitEvent({\n type: 'announcement_received',\n sequenceNumber,\n timestamp: new Date(),\n data: message.data,\n });\n }\n\n /**\n * Handle proposal message\n */\n private async handleProposal(\n message: ProposeMessage,\n sequenceNumber: number,\n ): Promise<void> {\n const proposal: TrackedProposal = {\n sequenceNumber,\n consensusTimestamp: new Date().toISOString(),\n proposer: message.data.proposer,\n data: message.data,\n responses: new Map(),\n };\n\n this.proposals.set(sequenceNumber, proposal);\n\n if (this.config.autoAcceptFilter?.(proposal)) {\n await this.respondToProposal(sequenceNumber, 'accept');\n }\n\n const isIncluded = message.data.members.some(\n m => m.account === this.config.accountId,\n );\n\n if (isIncluded) {\n this.emitEvent({\n type: 'proposal_received',\n sequenceNumber,\n timestamp: new Date(),\n data: message.data,\n });\n }\n }\n\n /**\n * Handle response message\n */\n private async handleResponse(\n message: RespondMessage,\n sequenceNumber: number,\n ): Promise<void> {\n const proposal = this.proposals.get(message.data.proposal_seq);\n if (proposal) {\n proposal.responses.set(message.data.responder, message.data);\n\n if (this.isProposalReady(proposal)) {\n if (\n proposal.data.proposer === this.config.accountId &&\n this.floraClient &&\n !this.floraCreationInProgress.has(message.data.proposal_seq)\n ) {\n this.floraCreationInProgress.add(message.data.proposal_seq);\n try {\n await this.createFloraFromProposal(proposal);\n } finally {\n this.floraCreationInProgress.delete(message.data.proposal_seq);\n }\n }\n }\n }\n\n this.emitEvent({\n type: 'response_received',\n sequenceNumber,\n timestamp: new Date(),\n data: message.data,\n });\n }\n\n /**\n * Handle completion message\n */\n private async handleCompletion(\n message: CompleteMessage,\n sequenceNumber: number,\n ): Promise<void> {\n const formation: FloraFormation = {\n proposalSeq: message.data.proposal_seq,\n floraAccountId: message.data.flora_account,\n topics: message.data.topics,\n members: [],\n threshold: 0,\n createdAt: new Date(),\n };\n\n if (this.isPartOfFormation(formation)) {\n this.state = DiscoveryState.ACTIVE;\n }\n\n this.formations.set(message.data.proposal_seq, formation);\n\n this.emitEvent({\n type: 'formation_complete',\n sequenceNumber,\n timestamp: new Date(),\n data: formation,\n });\n }\n\n /**\n * Handle withdrawal message\n */\n private async handleWithdrawal(\n message: WithdrawMessage,\n sequenceNumber: number,\n ): Promise<void> {\n this.announcements.delete(message.data.announce_seq);\n\n this.emitEvent({\n type: 'withdrawal_received',\n sequenceNumber,\n timestamp: new Date(),\n data: message.data,\n });\n }\n\n /**\n * Check if proposal has enough responses\n */\n private isProposalReady(proposal: TrackedProposal): boolean {\n const acceptances = Array.from(proposal.responses.values()).filter(\n r => r.decision === 'accept',\n );\n\n const requiredResponses = proposal.data.members.length - 1;\n return acceptances.length >= requiredResponses;\n }\n\n /**\n * Check if we're part of a Flora formation\n */\n private isPartOfFormation(formation: FloraFormation): boolean {\n return formation.members.some(m => m.account === this.config.accountId);\n }\n\n /**\n * Create Flora from accepted proposal\n */\n private async createFloraFromProposal(\n proposal: TrackedProposal,\n ): Promise<void> {\n if (!this.floraClient) {\n throw new DiscoveryError(\n 'Flora client not available',\n DiscoveryErrorCodes.FLORA_CREATION_FAILED,\n );\n }\n\n try {\n const memberPubKeys = await Promise.all(\n proposal.data.members.map(async m => {\n const accountInfo = await this.mirrorNode.requestAccount(m.account);\n const privateKey = this.config.memberPrivateKeys?.get(m.account);\n return {\n accountId: m.account,\n publicKey: PublicKey.fromString(accountInfo.key.key),\n privateKey, // Include private key if available\n };\n }),\n );\n\n // Ensure at least the first member has a private key for profile creation\n if (!memberPubKeys[0].privateKey) {\n throw new DiscoveryError(\n 'First member must have private key for Flora profile creation',\n DiscoveryErrorCodes.FLORA_CREATION_FAILED,\n );\n }\n\n const floraResult = await this.floraClient.createFlora({\n members: memberPubKeys,\n threshold: proposal.data.config.threshold,\n initialBalance: 10,\n displayName: proposal.data.config.name,\n });\n\n await this.completeFloraFormation(\n proposal.sequenceNumber,\n floraResult.floraAccountId.toString(),\n {\n communication: floraResult.topics.communication.toString(),\n transaction: floraResult.topics.transaction.toString(),\n state: floraResult.topics.state.toString(),\n },\n );\n } catch (error) {\n this.logger.error('Failed to create Flora', { error: error instanceof Error ? error.message : error });\n return;\n }\n }\n\n /**\n * Send message to discovery topic\n */\n private async sendDiscoveryMessage(\n message: DiscoveryMessage,\n ): Promise<number> {\n if (!this.client) {\n throw new DiscoveryError(\n 'Client required for sending messages',\n DiscoveryErrorCodes.INVALID_STATE,\n );\n }\n\n const payload = JSON.stringify(message);\n\n const transaction = new TopicMessageSubmitTransaction()\n .setTopicId(this.config.discoveryTopicId)\n .setMessage(payload);\n\n const response = await transaction.execute(this.client);\n const receipt = await response.getReceipt(this.client);\n\n return receipt.topicSequenceNumber.toNumber();\n }\n\n /**\n * Emit discovery event\n */\n private emitEvent(event: DiscoveryEvent): void {\n if (this.eventEmitter) {\n this.eventEmitter(event);\n }\n }\n}\n\nexport { FloraDiscovery as HCS18Discovery };\n"],"names":[],"mappings":"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"}
|