holosphere 2.0.0-alpha1 → 2.0.0-alpha4
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/2019-D2OG2idw.js +6680 -0
- package/dist/2019-D2OG2idw.js.map +1 -0
- package/dist/2019-EION3wKo.cjs +8 -0
- package/dist/2019-EION3wKo.cjs.map +1 -0
- package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
- package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
- package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
- package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
- package/dist/browser-BSniCNqO.js +3058 -0
- package/dist/browser-BSniCNqO.js.map +1 -0
- package/dist/browser-Cq59Ij19.cjs +2 -0
- package/dist/browser-Cq59Ij19.cjs.map +1 -0
- package/dist/cjs/holosphere.cjs +2 -0
- package/dist/cjs/holosphere.cjs.map +1 -0
- package/dist/esm/holosphere.js +53 -0
- package/dist/esm/holosphere.js.map +1 -0
- package/dist/index-BB_vVJgv.cjs +5 -0
- package/dist/index-BB_vVJgv.cjs.map +1 -0
- package/dist/index-CBitK71M.cjs +12 -0
- package/dist/index-CBitK71M.cjs.map +1 -0
- package/dist/index-CV0eOogK.js +37423 -0
- package/dist/index-CV0eOogK.js.map +1 -0
- package/dist/index-Cz-PLCUR.js +15104 -0
- package/dist/index-Cz-PLCUR.js.map +1 -0
- package/dist/indexeddb-storage-CRsZyB2f.cjs +2 -0
- package/dist/indexeddb-storage-CRsZyB2f.cjs.map +1 -0
- package/dist/indexeddb-storage-DZaGlY_a.js +132 -0
- package/dist/indexeddb-storage-DZaGlY_a.js.map +1 -0
- package/dist/memory-storage-BkUi6sZG.js +51 -0
- package/dist/memory-storage-BkUi6sZG.js.map +1 -0
- package/dist/memory-storage-C0DuUsdY.cjs +2 -0
- package/dist/memory-storage-C0DuUsdY.cjs.map +1 -0
- package/dist/secp256k1-0kPdAVkK.cjs +12 -0
- package/dist/secp256k1-0kPdAVkK.cjs.map +1 -0
- package/dist/secp256k1-DN4FVXcv.js +1890 -0
- package/dist/secp256k1-DN4FVXcv.js.map +1 -0
- package/docs/CONTRACTS.md +797 -0
- package/docs/FOSDEM_PROPOSAL.md +388 -0
- package/docs/LOCALFIRST.md +266 -0
- package/docs/contracts/api-interface.md +793 -0
- package/docs/data-model.md +476 -0
- package/docs/gun-async-usage.md +338 -0
- package/docs/plan.md +349 -0
- package/docs/quickstart.md +674 -0
- package/docs/research.md +362 -0
- package/docs/spec.md +244 -0
- package/docs/storage-backends.md +326 -0
- package/docs/tasks.md +947 -0
- package/examples/demo.html +47 -0
- package/package.json +10 -5
- package/src/contracts/abis/Appreciative.json +1280 -0
- package/src/contracts/abis/AppreciativeFactory.json +101 -0
- package/src/contracts/abis/Bundle.json +1435 -0
- package/src/contracts/abis/BundleFactory.json +106 -0
- package/src/contracts/abis/Holon.json +881 -0
- package/src/contracts/abis/Holons.json +330 -0
- package/src/contracts/abis/Managed.json +1262 -0
- package/src/contracts/abis/ManagedFactory.json +149 -0
- package/src/contracts/abis/Membrane.json +261 -0
- package/src/contracts/abis/Splitter.json +1624 -0
- package/src/contracts/abis/SplitterFactory.json +220 -0
- package/src/contracts/abis/TestToken.json +321 -0
- package/src/contracts/abis/Zoned.json +1461 -0
- package/src/contracts/abis/ZonedFactory.json +154 -0
- package/src/contracts/chain-manager.js +375 -0
- package/src/contracts/deployer.js +443 -0
- package/src/contracts/event-listener.js +507 -0
- package/src/contracts/holon-contracts.js +344 -0
- package/src/contracts/index.js +83 -0
- package/src/contracts/networks.js +224 -0
- package/src/contracts/operations.js +670 -0
- package/src/contracts/queries.js +589 -0
- package/src/core/holosphere.js +453 -1
- package/src/crypto/nostr-utils.js +263 -0
- package/src/federation/handshake.js +455 -0
- package/src/federation/hologram.js +1 -1
- package/src/hierarchical/upcast.js +6 -5
- package/src/index.js +463 -1939
- package/src/lib/ai-methods.js +308 -0
- package/src/lib/contract-methods.js +293 -0
- package/src/lib/errors.js +23 -0
- package/src/lib/federation-methods.js +238 -0
- package/src/lib/index.js +26 -0
- package/src/spatial/h3-operations.js +2 -2
- package/src/storage/backends/gundb-backend.js +377 -46
- package/src/storage/global-tables.js +28 -1
- package/src/storage/gun-auth.js +303 -0
- package/src/storage/gun-federation.js +776 -0
- package/src/storage/gun-references.js +198 -0
- package/src/storage/gun-schema.js +291 -0
- package/src/storage/gun-wrapper.js +347 -31
- package/src/storage/indexeddb-storage.js +49 -11
- package/src/storage/memory-storage.js +5 -0
- package/src/storage/nostr-async.js +45 -23
- package/src/storage/nostr-client.js +11 -5
- package/src/storage/persistent-storage.js +6 -1
- package/src/storage/unified-storage.js +119 -0
- package/src/subscriptions/manager.js +1 -1
- package/types/index.d.ts +133 -0
- package/tests/unit/ai/aggregation.test.js +0 -295
- package/tests/unit/ai/breakdown.test.js +0 -446
- package/tests/unit/ai/classifier.test.js +0 -294
- package/tests/unit/ai/council.test.js +0 -262
- package/tests/unit/ai/embeddings.test.js +0 -384
- package/tests/unit/ai/federation-ai.test.js +0 -344
- package/tests/unit/ai/h3-ai.test.js +0 -458
- package/tests/unit/ai/index.test.js +0 -304
- package/tests/unit/ai/json-ops.test.js +0 -307
- package/tests/unit/ai/llm-service.test.js +0 -390
- package/tests/unit/ai/nl-query.test.js +0 -383
- package/tests/unit/ai/relationships.test.js +0 -311
- package/tests/unit/ai/schema-extractor.test.js +0 -384
- package/tests/unit/ai/spatial.test.js +0 -279
- package/tests/unit/ai/tts.test.js +0 -279
- package/tests/unit/content.test.js +0 -332
- package/tests/unit/contract/core.test.js +0 -88
- package/tests/unit/contract/crypto.test.js +0 -198
- package/tests/unit/contract/data.test.js +0 -223
- package/tests/unit/contract/federation.test.js +0 -181
- package/tests/unit/contract/hierarchical.test.js +0 -113
- package/tests/unit/contract/schema.test.js +0 -114
- package/tests/unit/contract/social.test.js +0 -217
- package/tests/unit/contract/spatial.test.js +0 -110
- package/tests/unit/contract/subscriptions.test.js +0 -128
- package/tests/unit/contract/utils.test.js +0 -159
- package/tests/unit/core.test.js +0 -152
- package/tests/unit/crypto.test.js +0 -328
- package/tests/unit/federation.test.js +0 -234
- package/tests/unit/gun-async.test.js +0 -252
- package/tests/unit/hierarchical.test.js +0 -399
- package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
- package/tests/unit/integration/scenario-02-federation.test.js +0 -76
- package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
- package/tests/unit/integration/scenario-04-validation.test.js +0 -129
- package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
- package/tests/unit/integration/scenario-06-social.test.js +0 -135
- package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
- package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
- package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
- package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
- package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
- package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
- package/tests/unit/performance/benchmark.test.js +0 -85
- package/tests/unit/schema.test.js +0 -213
- package/tests/unit/spatial.test.js +0 -158
- package/tests/unit/storage.test.js +0 -195
- package/tests/unit/subscriptions.test.js +0 -328
- package/tests/unit/test-data-permanence-debug.js +0 -197
- package/tests/unit/test-data-permanence.js +0 -340
- package/tests/unit/test-key-persistence-fixed.js +0 -148
- package/tests/unit/test-key-persistence.js +0 -172
- package/tests/unit/test-relay-permanence.js +0 -376
- package/tests/unit/test-second-node.js +0 -95
- package/tests/unit/test-simple-write.js +0 -89
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContractOperations - All contract functions exposed with clear parameters
|
|
3
|
+
* Provides a unified interface for interacting with all Holosphere contract types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class ContractOperations {
|
|
7
|
+
constructor(contract, type, chainManager) {
|
|
8
|
+
this.contract = contract;
|
|
9
|
+
this.type = type;
|
|
10
|
+
this.chainManager = chainManager;
|
|
11
|
+
this.ethers = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Load ethers dynamically
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
async _loadEthers() {
|
|
19
|
+
if (!this.ethers) {
|
|
20
|
+
this.ethers = await import('ethers');
|
|
21
|
+
}
|
|
22
|
+
return this.ethers;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ========================================================================
|
|
26
|
+
// MEMBER MANAGEMENT
|
|
27
|
+
// ========================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Add a single member to the contract
|
|
31
|
+
* @param {string} userId - User identifier (string-based, e.g., 'alice', 'telegram_12345')
|
|
32
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
33
|
+
*/
|
|
34
|
+
async addMember(userId) {
|
|
35
|
+
const tx = await this.contract.addMember(userId);
|
|
36
|
+
const receipt = await tx.wait();
|
|
37
|
+
return { txHash: receipt.hash, receipt };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Add multiple members at once (batch operation)
|
|
42
|
+
* @param {string[]} userIds - Array of user identifiers
|
|
43
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
44
|
+
*/
|
|
45
|
+
async addMembers(userIds) {
|
|
46
|
+
const tx = await this.contract.addMembers(userIds);
|
|
47
|
+
const receipt = await tx.wait();
|
|
48
|
+
return { txHash: receipt.hash, receipt };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get all member user IDs
|
|
53
|
+
* @returns {Promise<string[]>}
|
|
54
|
+
*/
|
|
55
|
+
async getMembers() {
|
|
56
|
+
const userIds = await this.contract.userIds();
|
|
57
|
+
// userIds is typically a getter for the array - try different approaches
|
|
58
|
+
try {
|
|
59
|
+
// Try to get all members by iterating
|
|
60
|
+
const members = [];
|
|
61
|
+
let i = 0;
|
|
62
|
+
while (true) {
|
|
63
|
+
try {
|
|
64
|
+
const userId = await this.contract.userIds(i);
|
|
65
|
+
members.push(userId);
|
|
66
|
+
i++;
|
|
67
|
+
} catch {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return members;
|
|
72
|
+
} catch {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if a user is a member
|
|
79
|
+
* @param {string} userId - User identifier
|
|
80
|
+
* @returns {Promise<boolean>}
|
|
81
|
+
*/
|
|
82
|
+
async isMember(userId) {
|
|
83
|
+
try {
|
|
84
|
+
// Different contracts use different naming conventions
|
|
85
|
+
if (this.type === 'Splitter') {
|
|
86
|
+
return await this.contract.isSplitterMember(userId);
|
|
87
|
+
}
|
|
88
|
+
return await this.contract.isMember(userId);
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get the address associated with a user ID
|
|
96
|
+
* @param {string} userId - User identifier
|
|
97
|
+
* @returns {Promise<string>} Ethereum address (or zero address if not set)
|
|
98
|
+
*/
|
|
99
|
+
async getUserAddress(userId) {
|
|
100
|
+
return this.contract.userIdToAddress(userId);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ========================================================================
|
|
104
|
+
// FUND DISTRIBUTION
|
|
105
|
+
// ========================================================================
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Trigger reward distribution for ERC20 tokens
|
|
109
|
+
* @param {string} tokenAddress - ERC20 token contract address
|
|
110
|
+
* @param {string|bigint} amount - Amount in wei (or token's smallest unit)
|
|
111
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
112
|
+
*/
|
|
113
|
+
async reward(tokenAddress, amount) {
|
|
114
|
+
const ethers = await this._loadEthers();
|
|
115
|
+
const amountBigInt = typeof amount === 'string' ? ethers.parseUnits(amount, 18) : amount;
|
|
116
|
+
const tx = await this.contract.reward(tokenAddress, amountBigInt);
|
|
117
|
+
const receipt = await tx.wait();
|
|
118
|
+
return { txHash: receipt.hash, receipt };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Trigger reward distribution for ETH
|
|
123
|
+
* @param {string} amount - Amount in ETH (e.g., '1.5' for 1.5 ETH)
|
|
124
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
125
|
+
*/
|
|
126
|
+
async rewardEth(amount) {
|
|
127
|
+
const ethers = await this._loadEthers();
|
|
128
|
+
const amountWei = ethers.parseEther(amount);
|
|
129
|
+
const tx = await this.contract.reward(
|
|
130
|
+
'0x0000000000000000000000000000000000000000',
|
|
131
|
+
amountWei,
|
|
132
|
+
{ value: amountWei }
|
|
133
|
+
);
|
|
134
|
+
const receipt = await tx.wait();
|
|
135
|
+
return { txHash: receipt.hash, receipt };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Send ETH directly to contract (triggers receive/fallback)
|
|
140
|
+
* @param {string} amount - Amount in ETH
|
|
141
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
142
|
+
*/
|
|
143
|
+
async sendEth(amount) {
|
|
144
|
+
const ethers = await this._loadEthers();
|
|
145
|
+
const signer = this.chainManager.getSigner();
|
|
146
|
+
const amountWei = ethers.parseEther(amount);
|
|
147
|
+
const tx = await signer.sendTransaction({
|
|
148
|
+
to: await this.contract.getAddress(),
|
|
149
|
+
value: amountWei
|
|
150
|
+
});
|
|
151
|
+
const receipt = await tx.wait();
|
|
152
|
+
return { txHash: receipt.hash, receipt };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Claim accumulated rewards for a user
|
|
157
|
+
* @param {string} userId - User identifier
|
|
158
|
+
* @param {string} beneficiaryAddress - Ethereum address to receive funds
|
|
159
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
160
|
+
*/
|
|
161
|
+
async claim(userId, beneficiaryAddress) {
|
|
162
|
+
const tx = await this.contract.claim(userId, beneficiaryAddress);
|
|
163
|
+
const receipt = await tx.wait();
|
|
164
|
+
return { txHash: receipt.hash, receipt };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get ETH balance for a user
|
|
169
|
+
* @param {string} userId - User identifier
|
|
170
|
+
* @returns {Promise<string>} Balance in ETH
|
|
171
|
+
*/
|
|
172
|
+
async getEthBalance(userId) {
|
|
173
|
+
const ethers = await this._loadEthers();
|
|
174
|
+
const balance = await this.contract.etherBalance(userId);
|
|
175
|
+
return ethers.formatEther(balance);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get ERC20 token balance for a user
|
|
180
|
+
* @param {string} userId - User identifier
|
|
181
|
+
* @param {string} tokenAddress - ERC20 token address
|
|
182
|
+
* @returns {Promise<string>} Balance in tokens (18 decimals assumed)
|
|
183
|
+
*/
|
|
184
|
+
async getTokenBalance(userId, tokenAddress) {
|
|
185
|
+
const ethers = await this._loadEthers();
|
|
186
|
+
const balance = await this.contract.tokenBalance(userId, tokenAddress);
|
|
187
|
+
return ethers.formatUnits(balance, 18);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Check if user has already claimed
|
|
192
|
+
* @param {string} userId - User identifier
|
|
193
|
+
* @returns {Promise<boolean>}
|
|
194
|
+
*/
|
|
195
|
+
async hasClaimed(userId) {
|
|
196
|
+
return this.contract.hasClaimed(userId);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get total deposited amount for a token
|
|
201
|
+
* @param {string} tokenAddress - Token address (use zero address for ETH)
|
|
202
|
+
* @returns {Promise<string>}
|
|
203
|
+
*/
|
|
204
|
+
async getTotalDeposited(tokenAddress) {
|
|
205
|
+
const ethers = await this._loadEthers();
|
|
206
|
+
const total = await this.contract.totalDeposited(tokenAddress);
|
|
207
|
+
return ethers.formatUnits(total, 18);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ========================================================================
|
|
211
|
+
// SPLITTER OPERATIONS
|
|
212
|
+
// ========================================================================
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Set the internal/external split percentages (Splitter only)
|
|
216
|
+
* @param {number} internalPct - Internal percentage (0-100)
|
|
217
|
+
* @param {number} externalPct - External percentage (0-100, must sum to 100 with internal)
|
|
218
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
219
|
+
*/
|
|
220
|
+
async setContractSplit(internalPct, externalPct) {
|
|
221
|
+
this._requireType(['Splitter']);
|
|
222
|
+
if (internalPct + externalPct !== 100) {
|
|
223
|
+
throw new Error('Percentages must sum to 100');
|
|
224
|
+
}
|
|
225
|
+
const tx = await this.contract.setContractSplit(internalPct, externalPct);
|
|
226
|
+
const receipt = await tx.wait();
|
|
227
|
+
return { txHash: receipt.hash, receipt };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get current split percentages (Splitter only)
|
|
232
|
+
* @returns {Promise<{internal: number, external: number}>}
|
|
233
|
+
*/
|
|
234
|
+
async getContractSplit() {
|
|
235
|
+
this._requireType(['Splitter']);
|
|
236
|
+
const internal = await this.contract.internalContractSplitPercentage();
|
|
237
|
+
const external = await this.contract.externalContractSplitPercentage();
|
|
238
|
+
return {
|
|
239
|
+
internal: Number(internal),
|
|
240
|
+
external: Number(external)
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create a Managed child contract (Splitter only)
|
|
246
|
+
* @param {string} creatorUserId - Creator's user ID
|
|
247
|
+
* @param {string} name - Contract name
|
|
248
|
+
* @param {number} [parameter=0] - Optional parameter
|
|
249
|
+
* @returns {Promise<{address, txHash, receipt}>}
|
|
250
|
+
*/
|
|
251
|
+
async createManagedContract(creatorUserId, name, parameter = 0) {
|
|
252
|
+
this._requireType(['Splitter']);
|
|
253
|
+
const tx = await this.contract.createManagedContract(creatorUserId, name, parameter);
|
|
254
|
+
const receipt = await tx.wait();
|
|
255
|
+
const address = await this.contract.contractsByType(`${name}_managed`);
|
|
256
|
+
return { address, txHash: receipt.hash, receipt };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Create a Zoned child contract (Splitter only)
|
|
261
|
+
* @param {string} creatorUserId - Creator's user ID
|
|
262
|
+
* @param {string} name - Contract name
|
|
263
|
+
* @param {number} [nZones=6] - Number of zones
|
|
264
|
+
* @returns {Promise<{address, txHash, receipt}>}
|
|
265
|
+
*/
|
|
266
|
+
async createZonedContract(creatorUserId, name, nZones = 6) {
|
|
267
|
+
this._requireType(['Splitter']);
|
|
268
|
+
const tx = await this.contract.createZonedContract(creatorUserId, name, nZones);
|
|
269
|
+
const receipt = await tx.wait();
|
|
270
|
+
const address = await this.contract.contractsByType(`${name}_zoned`);
|
|
271
|
+
return { address, txHash: receipt.hash, receipt };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Get all child contract keys (Splitter only)
|
|
276
|
+
* @returns {Promise<string[]>}
|
|
277
|
+
*/
|
|
278
|
+
async getChildContractKeys() {
|
|
279
|
+
this._requireType(['Splitter']);
|
|
280
|
+
return this.contract.getContractKeys();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get child contract addresses (Splitter only)
|
|
285
|
+
* @returns {Promise<{keys: string[], addresses: string[]}>}
|
|
286
|
+
*/
|
|
287
|
+
async getChildContracts() {
|
|
288
|
+
this._requireType(['Splitter']);
|
|
289
|
+
const [keys, addresses] = await this.contract.getContractAddresses();
|
|
290
|
+
return { keys, addresses };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Get child contract address by key (Splitter only)
|
|
295
|
+
* @param {string} key - Contract key (e.g., 'MyHolon_managed')
|
|
296
|
+
* @returns {Promise<string>}
|
|
297
|
+
*/
|
|
298
|
+
async getChildContract(key) {
|
|
299
|
+
this._requireType(['Splitter']);
|
|
300
|
+
return this.contract.contractsByType(key);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ========================================================================
|
|
304
|
+
// MANAGED OPERATIONS (Appreciation-Based)
|
|
305
|
+
// ========================================================================
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Set appreciation values for members (Managed only)
|
|
309
|
+
* Appreciation determines reward distribution proportionally
|
|
310
|
+
* @param {string[]} userIds - Array of user identifiers
|
|
311
|
+
* @param {number[]} amounts - Array of appreciation amounts (integers)
|
|
312
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
313
|
+
* @example
|
|
314
|
+
* // Alice gets 60%, Bob gets 40%
|
|
315
|
+
* await ops.setAppreciation(['alice', 'bob'], [300, 200]);
|
|
316
|
+
*/
|
|
317
|
+
async setAppreciation(userIds, amounts) {
|
|
318
|
+
this._requireType(['Managed']);
|
|
319
|
+
if (userIds.length !== amounts.length) {
|
|
320
|
+
throw new Error('userIds and amounts arrays must have same length');
|
|
321
|
+
}
|
|
322
|
+
const tx = await this.contract.setAppreciation(userIds, amounts);
|
|
323
|
+
const receipt = await tx.wait();
|
|
324
|
+
return { txHash: receipt.hash, receipt };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get appreciation value for a user (Managed only)
|
|
329
|
+
* @param {string} userId - User identifier
|
|
330
|
+
* @returns {Promise<number>}
|
|
331
|
+
*/
|
|
332
|
+
async getAppreciation(userId) {
|
|
333
|
+
this._requireType(['Managed']);
|
|
334
|
+
const appreciation = await this.contract.appreciation(userId);
|
|
335
|
+
return Number(appreciation);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Get total appreciation across all members (Managed only)
|
|
340
|
+
* @returns {Promise<number>}
|
|
341
|
+
*/
|
|
342
|
+
async getTotalAppreciation() {
|
|
343
|
+
this._requireType(['Managed']);
|
|
344
|
+
const total = await this.contract.totalappreciation();
|
|
345
|
+
return Number(total);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ========================================================================
|
|
349
|
+
// ZONED OPERATIONS (Tier-Based)
|
|
350
|
+
// ========================================================================
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Add a user to a zone (Zoned only)
|
|
354
|
+
* Higher zones receive more rewards based on quadratic formula
|
|
355
|
+
* @param {string} senderUserId - Sender's user ID (for authorization)
|
|
356
|
+
* @param {string} userId - User to add to zone
|
|
357
|
+
* @param {number} zone - Zone number (0 = unassigned, 1-N = contribution tiers)
|
|
358
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
359
|
+
*/
|
|
360
|
+
async addToZone(senderUserId, userId, zone) {
|
|
361
|
+
this._requireType(['Zoned']);
|
|
362
|
+
const tx = await this.contract.addToZone(senderUserId, userId, zone);
|
|
363
|
+
const receipt = await tx.wait();
|
|
364
|
+
return { txHash: receipt.hash, receipt };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Remove a user from their zone (Zoned only)
|
|
369
|
+
* @param {string} senderUserId - Sender's user ID
|
|
370
|
+
* @param {string} userId - User to remove
|
|
371
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
372
|
+
*/
|
|
373
|
+
async removeFromZone(senderUserId, userId) {
|
|
374
|
+
this._requireType(['Zoned']);
|
|
375
|
+
const tx = await this.contract.removeFromZone(senderUserId, userId);
|
|
376
|
+
const receipt = await tx.wait();
|
|
377
|
+
return { txHash: receipt.hash, receipt };
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Get a user's zone (Zoned only)
|
|
382
|
+
* @param {string} userId - User identifier
|
|
383
|
+
* @returns {Promise<number>}
|
|
384
|
+
*/
|
|
385
|
+
async getZone(userId) {
|
|
386
|
+
this._requireType(['Zoned']);
|
|
387
|
+
const zone = await this.contract.zones(userId);
|
|
388
|
+
return Number(zone);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Get number of zones (Zoned only)
|
|
393
|
+
* @returns {Promise<number>}
|
|
394
|
+
*/
|
|
395
|
+
async getNumZones() {
|
|
396
|
+
this._requireType(['Zoned']);
|
|
397
|
+
const nzones = await this.contract.nzones();
|
|
398
|
+
return Number(nzones);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Set the reward function parameters (Zoned only)
|
|
403
|
+
* Formula: reward_units = a*zone² + b*zone + c
|
|
404
|
+
* @param {string} senderUserId - Sender's user ID
|
|
405
|
+
* @param {number} a - Quadratic coefficient
|
|
406
|
+
* @param {number} b - Linear coefficient
|
|
407
|
+
* @param {number} c - Constant
|
|
408
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
409
|
+
*/
|
|
410
|
+
async setZoneParameters(senderUserId, a, b, c) {
|
|
411
|
+
this._requireType(['Zoned']);
|
|
412
|
+
const tx = await this.contract.setRewardFunction(senderUserId, a, b, c);
|
|
413
|
+
const receipt = await tx.wait();
|
|
414
|
+
return { txHash: receipt.hash, receipt };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ========================================================================
|
|
418
|
+
// APPRECIATIVE OPERATIONS (Peer-to-Peer)
|
|
419
|
+
// ========================================================================
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Give appreciation from one user to another (Appreciative only)
|
|
423
|
+
* Each member has a limited appreciation pool to distribute
|
|
424
|
+
* @param {string} fromUserId - Giver's user ID
|
|
425
|
+
* @param {string} toUserId - Receiver's user ID
|
|
426
|
+
* @param {number} amount - Amount of appreciation to give
|
|
427
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
428
|
+
*/
|
|
429
|
+
async appreciate(fromUserId, toUserId, amount) {
|
|
430
|
+
this._requireType(['Appreciative']);
|
|
431
|
+
const tx = await this.contract.appreciate(fromUserId, toUserId, amount);
|
|
432
|
+
const receipt = await tx.wait();
|
|
433
|
+
return { txHash: receipt.hash, receipt };
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Get appreciation given by a user (Appreciative only)
|
|
438
|
+
* @param {string} userId - User identifier
|
|
439
|
+
* @returns {Promise<number>}
|
|
440
|
+
*/
|
|
441
|
+
async getAppreciationGiven(userId) {
|
|
442
|
+
this._requireType(['Appreciative']);
|
|
443
|
+
const given = await this.contract.appreciationGiven(userId);
|
|
444
|
+
return Number(given);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Get appreciation received by a user (Appreciative only)
|
|
449
|
+
* @param {string} userId - User identifier
|
|
450
|
+
* @returns {Promise<number>}
|
|
451
|
+
*/
|
|
452
|
+
async getAppreciationReceived(userId) {
|
|
453
|
+
this._requireType(['Appreciative']);
|
|
454
|
+
const received = await this.contract.appreciationReceived(userId);
|
|
455
|
+
return Number(received);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Get remaining appreciation pool for a user (Appreciative only)
|
|
460
|
+
* @param {string} userId - User identifier
|
|
461
|
+
* @returns {Promise<number>}
|
|
462
|
+
*/
|
|
463
|
+
async getAppreciationRemaining(userId) {
|
|
464
|
+
this._requireType(['Appreciative']);
|
|
465
|
+
const remaining = await this.contract.appreciationRemaining(userId);
|
|
466
|
+
return Number(remaining);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ========================================================================
|
|
470
|
+
// BUNDLE OPERATIONS (2-Way Split)
|
|
471
|
+
// ========================================================================
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Set steepness for zone decay (Bundle only)
|
|
475
|
+
* Higher steepness = faster decay = more concentration in higher zones
|
|
476
|
+
* @param {string|bigint} steepness - Steepness value (0 < s < 1e18, e.g., 0.5e18 for 50% decay)
|
|
477
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
478
|
+
*/
|
|
479
|
+
async setSteepness(steepness) {
|
|
480
|
+
this._requireType(['Bundle']);
|
|
481
|
+
const ethers = await this._loadEthers();
|
|
482
|
+
const steepnessValue = typeof steepness === 'string' ? ethers.parseEther(steepness) : steepness;
|
|
483
|
+
const tx = await this.contract.setSteepness(steepnessValue);
|
|
484
|
+
const receipt = await tx.wait();
|
|
485
|
+
return { txHash: receipt.hash, receipt };
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Get current steepness (Bundle only)
|
|
490
|
+
* @returns {Promise<string>} Steepness as decimal string (e.g., '0.5')
|
|
491
|
+
*/
|
|
492
|
+
async getSteepness() {
|
|
493
|
+
this._requireType(['Bundle']);
|
|
494
|
+
const ethers = await this._loadEthers();
|
|
495
|
+
const steepness = await this.contract.steepness();
|
|
496
|
+
return ethers.formatEther(steepness);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Set interior split percentages (Bundle only)
|
|
501
|
+
* @param {string[]} userIds - User identifiers
|
|
502
|
+
* @param {number[]} percentages - Percentages (must sum to 100)
|
|
503
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
504
|
+
*/
|
|
505
|
+
async setInteriorSplit(userIds, percentages) {
|
|
506
|
+
this._requireType(['Bundle']);
|
|
507
|
+
const total = percentages.reduce((a, b) => a + b, 0);
|
|
508
|
+
if (total !== 100) {
|
|
509
|
+
throw new Error('Percentages must sum to 100');
|
|
510
|
+
}
|
|
511
|
+
const tx = await this.contract.setInteriorSplit(userIds, percentages);
|
|
512
|
+
const receipt = await tx.wait();
|
|
513
|
+
return { txHash: receipt.hash, receipt };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ========================================================================
|
|
517
|
+
// GOVERNANCE (Bundle)
|
|
518
|
+
// ========================================================================
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Start an election for new owner (Bundle only)
|
|
522
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
523
|
+
*/
|
|
524
|
+
async startElection() {
|
|
525
|
+
this._requireType(['Bundle']);
|
|
526
|
+
const tx = await this.contract.startElection();
|
|
527
|
+
const receipt = await tx.wait();
|
|
528
|
+
return { txHash: receipt.hash, receipt };
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Nominate yourself as candidate (Bundle only)
|
|
533
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
534
|
+
*/
|
|
535
|
+
async nominateSelf() {
|
|
536
|
+
this._requireType(['Bundle']);
|
|
537
|
+
const tx = await this.contract.nominateSelf();
|
|
538
|
+
const receipt = await tx.wait();
|
|
539
|
+
return { txHash: receipt.hash, receipt };
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Vote for a nominee (Bundle only)
|
|
544
|
+
* @param {string} nomineeAddress - Address of the nominee
|
|
545
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
546
|
+
*/
|
|
547
|
+
async vote(nomineeAddress) {
|
|
548
|
+
this._requireType(['Bundle']);
|
|
549
|
+
const tx = await this.contract.vote(nomineeAddress);
|
|
550
|
+
const receipt = await tx.wait();
|
|
551
|
+
return { txHash: receipt.hash, receipt };
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Finalize election and transfer ownership to winner (Bundle only)
|
|
556
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
557
|
+
*/
|
|
558
|
+
async finalizeElection() {
|
|
559
|
+
this._requireType(['Bundle']);
|
|
560
|
+
const tx = await this.contract.finalizeElection();
|
|
561
|
+
const receipt = await tx.wait();
|
|
562
|
+
return { txHash: receipt.hash, receipt };
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// ========================================================================
|
|
566
|
+
// READ-ONLY QUERIES
|
|
567
|
+
// ========================================================================
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Get contract name
|
|
571
|
+
* @returns {Promise<string>}
|
|
572
|
+
*/
|
|
573
|
+
async getName() {
|
|
574
|
+
return this.contract.name();
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Get contract owner address
|
|
579
|
+
* @returns {Promise<string>}
|
|
580
|
+
*/
|
|
581
|
+
async getOwner() {
|
|
582
|
+
return this.contract.owner();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Get bot address (for Managed/Zoned)
|
|
587
|
+
* @returns {Promise<string>}
|
|
588
|
+
*/
|
|
589
|
+
async getBotAddress() {
|
|
590
|
+
try {
|
|
591
|
+
return await this.contract.botAddress();
|
|
592
|
+
} catch {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Get creator user ID
|
|
599
|
+
* @returns {Promise<string>}
|
|
600
|
+
*/
|
|
601
|
+
async getCreatorUserId() {
|
|
602
|
+
try {
|
|
603
|
+
return await this.contract.creatorUserId();
|
|
604
|
+
} catch {
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Get contract address
|
|
611
|
+
* @returns {Promise<string>}
|
|
612
|
+
*/
|
|
613
|
+
async getAddress() {
|
|
614
|
+
return this.contract.getAddress();
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Get contract type
|
|
619
|
+
* @returns {string}
|
|
620
|
+
*/
|
|
621
|
+
getType() {
|
|
622
|
+
return this.type;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// ========================================================================
|
|
626
|
+
// UTILITIES
|
|
627
|
+
// ========================================================================
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Require specific contract type(s)
|
|
631
|
+
* @private
|
|
632
|
+
*/
|
|
633
|
+
_requireType(allowedTypes) {
|
|
634
|
+
if (!allowedTypes.includes(this.type)) {
|
|
635
|
+
throw new Error(`Operation only available for ${allowedTypes.join('/')} contracts. This is a ${this.type} contract.`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Get raw contract instance for advanced usage
|
|
641
|
+
* @returns {Contract}
|
|
642
|
+
*/
|
|
643
|
+
getRawContract() {
|
|
644
|
+
return this.contract;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Execute a raw contract call
|
|
649
|
+
* @param {string} method - Method name
|
|
650
|
+
* @param {Array} args - Method arguments
|
|
651
|
+
* @returns {Promise<any>}
|
|
652
|
+
*/
|
|
653
|
+
async call(method, ...args) {
|
|
654
|
+
return this.contract[method](...args);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Execute a raw contract transaction
|
|
659
|
+
* @param {string} method - Method name
|
|
660
|
+
* @param {Array} args - Method arguments
|
|
661
|
+
* @returns {Promise<{txHash, receipt}>}
|
|
662
|
+
*/
|
|
663
|
+
async send(method, ...args) {
|
|
664
|
+
const tx = await this.contract[method](...args);
|
|
665
|
+
const receipt = await tx.wait();
|
|
666
|
+
return { txHash: receipt.hash, receipt };
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
export default ContractOperations;
|