web3ql-client 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -0
- package/contracts/PublicKeyRegistry.sol +87 -0
- package/dist/src/access.d.ts +176 -0
- package/dist/src/access.d.ts.map +1 -0
- package/dist/src/access.js +283 -0
- package/dist/src/access.js.map +1 -0
- package/dist/src/batch.d.ts +107 -0
- package/dist/src/batch.d.ts.map +1 -0
- package/dist/src/batch.js +188 -0
- package/dist/src/batch.js.map +1 -0
- package/dist/src/cli.d.ts +40 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +361 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/constraints.d.ts +126 -0
- package/dist/src/constraints.d.ts.map +1 -0
- package/dist/src/constraints.js +192 -0
- package/dist/src/constraints.js.map +1 -0
- package/dist/src/crypto.d.ts +118 -0
- package/dist/src/crypto.d.ts.map +1 -0
- package/dist/src/crypto.js +192 -0
- package/dist/src/crypto.js.map +1 -0
- package/dist/src/factory-client.d.ts +106 -0
- package/dist/src/factory-client.d.ts.map +1 -0
- package/dist/src/factory-client.js +202 -0
- package/dist/src/factory-client.js.map +1 -0
- package/dist/src/index-cache.d.ts +156 -0
- package/dist/src/index-cache.d.ts.map +1 -0
- package/dist/src/index-cache.js +265 -0
- package/dist/src/index-cache.js.map +1 -0
- package/dist/src/index.d.ts +60 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +60 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/migrations.d.ts +114 -0
- package/dist/src/migrations.d.ts.map +1 -0
- package/dist/src/migrations.js +173 -0
- package/dist/src/migrations.js.map +1 -0
- package/dist/src/model.d.ts +198 -0
- package/dist/src/model.d.ts.map +1 -0
- package/dist/src/model.js +379 -0
- package/dist/src/model.js.map +1 -0
- package/dist/src/query.d.ts +155 -0
- package/dist/src/query.d.ts.map +1 -0
- package/dist/src/query.js +386 -0
- package/dist/src/query.js.map +1 -0
- package/dist/src/registry.d.ts +45 -0
- package/dist/src/registry.d.ts.map +1 -0
- package/dist/src/registry.js +80 -0
- package/dist/src/registry.js.map +1 -0
- package/dist/src/schema-manager.d.ts +109 -0
- package/dist/src/schema-manager.d.ts.map +1 -0
- package/dist/src/schema-manager.js +259 -0
- package/dist/src/schema-manager.js.map +1 -0
- package/dist/src/table-client.d.ts +156 -0
- package/dist/src/table-client.d.ts.map +1 -0
- package/dist/src/table-client.js +292 -0
- package/dist/src/table-client.js.map +1 -0
- package/dist/src/typed-table.d.ts +159 -0
- package/dist/src/typed-table.d.ts.map +1 -0
- package/dist/src/typed-table.js +246 -0
- package/dist/src/typed-table.js.map +1 -0
- package/dist/src/types.d.ts +48 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +222 -0
- package/dist/src/types.js.map +1 -0
- package/keyManager.js +337 -0
- package/package.json +38 -0
- package/src/access.ts +421 -0
- package/src/batch.ts +259 -0
- package/src/cli.ts +349 -0
- package/src/constraints.ts +283 -0
- package/src/crypto.ts +239 -0
- package/src/factory-client.ts +237 -0
- package/src/index-cache.ts +351 -0
- package/src/index.ts +171 -0
- package/src/migrations.ts +215 -0
- package/src/model.ts +538 -0
- package/src/query.ts +508 -0
- package/src/registry.ts +100 -0
- package/src/schema-manager.ts +301 -0
- package/src/table-client.ts +393 -0
- package/src/typed-table.ts +340 -0
- package/src/types.ts +284 -0
- package/tsconfig.json +22 -0
- package/walletUtils.js +204 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file model.ts
|
|
3
|
+
* @notice Web3QL ORM — Prisma-style Model class that unifies:
|
|
4
|
+
*
|
|
5
|
+
* • Encrypted record CRUD (via TypedTableClient under the hood)
|
|
6
|
+
* • On-chain COUNTER fields — automatically merged into every find result
|
|
7
|
+
* • Relation writes — `relatedCreate()` pays with native CELO or any ERC-20
|
|
8
|
+
* and atomically writes the source record + increments target counters
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ─────────────────────────────────────────────────────────────
|
|
12
|
+
* // 1. Define your models
|
|
13
|
+
* const projects = new Model<Project>('projects', projectsTableAddr, signer, keypair, {
|
|
14
|
+
* counterFields: ['vote_total', 'vote_count', 'tip_total', 'tip_count'],
|
|
15
|
+
* schema: projectSchema,
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const votes = new Model<Vote>('votes', votesTableAddr, signer, keypair);
|
|
19
|
+
*
|
|
20
|
+
* // 2. Standard CRUD
|
|
21
|
+
* await projects.create(1n, { id: 1n, name: 'Web3QL' });
|
|
22
|
+
*
|
|
23
|
+
* // 3. findUnique — counter fields merged in automatically
|
|
24
|
+
* const p = await projects.findUnique(1n);
|
|
25
|
+
* // p = { id: 1n, name: 'Web3QL', vote_total: 420n, vote_count: 3n, ... }
|
|
26
|
+
*
|
|
27
|
+
* // 4. Relation write — pay 2 CELO, atomically save vote + update project counters
|
|
28
|
+
* await votes.relatedCreate({
|
|
29
|
+
* wire : wireAddress,
|
|
30
|
+
* id : 10n,
|
|
31
|
+
* data : { project_id: 1n, voter: myAddr, amount: 2n * 10n**18n },
|
|
32
|
+
* targetId : 1n,
|
|
33
|
+
* amount : 2n * 10n**18n, // native CELO
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // 5. ERC-20 vote: approve first, then:
|
|
37
|
+
* await votes.relatedCreate({
|
|
38
|
+
* wire : wireAddress,
|
|
39
|
+
* id : 11n,
|
|
40
|
+
* data : { project_id: 1n, voter: myAddr, amount: 5_000000n },
|
|
41
|
+
* targetId : 1n,
|
|
42
|
+
* amount : 5_000000n, // 5 cUSD (6 decimals)
|
|
43
|
+
* token : CUSD_ADDRESS, // ERC-20 token — pre-approve wire contract first
|
|
44
|
+
* });
|
|
45
|
+
* ─────────────────────────────────────────────────────────────
|
|
46
|
+
*/
|
|
47
|
+
import { ethers } from 'ethers';
|
|
48
|
+
import { EncryptedTableClient, Role } from './table-client.js';
|
|
49
|
+
import { TypedTableClient } from './typed-table.js';
|
|
50
|
+
export { Role };
|
|
51
|
+
// ─────────────────────────────────────────────────────────────
|
|
52
|
+
// Minimal ABIs
|
|
53
|
+
// ─────────────────────────────────────────────────────────────
|
|
54
|
+
const COUNTER_ABI = [
|
|
55
|
+
'function counterValue(bytes32 targetKey, bytes32 field) external view returns (uint256)',
|
|
56
|
+
];
|
|
57
|
+
const WIRE_ABI = [
|
|
58
|
+
'function relatedWrite(bytes32 sourceKey, bytes ciphertext, bytes encryptedKey, bytes32 targetKey, address token, uint256 amount) payable external',
|
|
59
|
+
'function relatedWriteWithPermit(bytes32 sourceKey, bytes ciphertext, bytes encryptedKey, bytes32 targetKey, address token, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external',
|
|
60
|
+
'function withdrawProjectFunds(bytes32 targetKey, address token, address to) external',
|
|
61
|
+
'function withdrawAllProjectFunds(bytes32 targetKey, address to) external',
|
|
62
|
+
'function projectBalances(bytes32 targetKey) external view returns (address[] tokens, uint256[] balances)',
|
|
63
|
+
'function getAllowedTokens() external view returns (address[])',
|
|
64
|
+
];
|
|
65
|
+
const ERC20_ABI = [
|
|
66
|
+
'function allowance(address owner, address spender) external view returns (uint256)',
|
|
67
|
+
'function approve(address spender, uint256 amount) external returns (bool)',
|
|
68
|
+
'function nonces(address owner) external view returns (uint256)',
|
|
69
|
+
'function name() external view returns (string)',
|
|
70
|
+
'function version() external view returns (string)',
|
|
71
|
+
'function DOMAIN_SEPARATOR() external view returns (bytes32)',
|
|
72
|
+
];
|
|
73
|
+
// ─────────────────────────────────────────────────────────────
|
|
74
|
+
// Model
|
|
75
|
+
// ─────────────────────────────────────────────────────────────
|
|
76
|
+
/**
|
|
77
|
+
* `Model<T>` — the Web3QL ORM entry point.
|
|
78
|
+
*
|
|
79
|
+
* T is the shape of the ENCRYPTED fields only (not counter fields).
|
|
80
|
+
* Counter fields are added automatically to every returned object.
|
|
81
|
+
*/
|
|
82
|
+
export class Model {
|
|
83
|
+
tableName;
|
|
84
|
+
tableAddress;
|
|
85
|
+
inner;
|
|
86
|
+
rawClient;
|
|
87
|
+
counterFields;
|
|
88
|
+
counterFieldHashes; // name → keccak256
|
|
89
|
+
signer;
|
|
90
|
+
provider;
|
|
91
|
+
constructor(tableName, tableAddress, signer, keypair, options) {
|
|
92
|
+
this.tableName = tableName;
|
|
93
|
+
this.tableAddress = tableAddress;
|
|
94
|
+
this.signer = signer;
|
|
95
|
+
this.provider = signer.provider;
|
|
96
|
+
const cf = options?.counterFields ?? [];
|
|
97
|
+
this.counterFields = cf;
|
|
98
|
+
this.counterFieldHashes = new Map(cf.map((name) => [name, ethers.keccak256(ethers.toUtf8Bytes(name))]));
|
|
99
|
+
this.rawClient = new EncryptedTableClient(tableAddress, signer, keypair);
|
|
100
|
+
this.inner = new TypedTableClient(tableName, this.rawClient, options?.schema);
|
|
101
|
+
}
|
|
102
|
+
// ─────────────────────────────────────────────────────────────
|
|
103
|
+
// Key derivation
|
|
104
|
+
// ─────────────────────────────────────────────────────────────
|
|
105
|
+
/** Derive the on-chain bytes32 record key for a given primary key. */
|
|
106
|
+
key(id) {
|
|
107
|
+
return this.rawClient.deriveKey(this.tableName, id);
|
|
108
|
+
}
|
|
109
|
+
// ─────────────────────────────────────────────────────────────
|
|
110
|
+
// Counter reads (public — no auth needed)
|
|
111
|
+
// ─────────────────────────────────────────────────────────────
|
|
112
|
+
/** Read a single named counter for the record at `id`. */
|
|
113
|
+
async counter(id, field) {
|
|
114
|
+
const hash = this.counterFieldHashes.get(field)
|
|
115
|
+
?? ethers.keccak256(ethers.toUtf8Bytes(field));
|
|
116
|
+
const contract = new ethers.Contract(this.tableAddress, COUNTER_ABI, this.provider);
|
|
117
|
+
const raw = await contract['counterValue'](this.key(id), hash);
|
|
118
|
+
return BigInt(raw);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Read ALL registered counter fields for the record at `id`.
|
|
122
|
+
* Returns a plain object mapping field name → bigint value.
|
|
123
|
+
*/
|
|
124
|
+
async counters(id) {
|
|
125
|
+
if (this.counterFields.length === 0)
|
|
126
|
+
return {};
|
|
127
|
+
const contract = new ethers.Contract(this.tableAddress, COUNTER_ABI, this.provider);
|
|
128
|
+
const key = this.key(id);
|
|
129
|
+
const values = await Promise.all(this.counterFields.map(async (name) => {
|
|
130
|
+
const hash = this.counterFieldHashes.get(name);
|
|
131
|
+
const raw = await contract['counterValue'](key, hash);
|
|
132
|
+
return [name, BigInt(raw)];
|
|
133
|
+
}));
|
|
134
|
+
return Object.fromEntries(values);
|
|
135
|
+
}
|
|
136
|
+
// ─────────────────────────────────────────────────────────────
|
|
137
|
+
// CRUD — counter fields merged into results automatically
|
|
138
|
+
// ─────────────────────────────────────────────────────────────
|
|
139
|
+
/**
|
|
140
|
+
* Encrypt and store a new record.
|
|
141
|
+
* Pass only encrypted fields — counter fields are managed by the chain.
|
|
142
|
+
*/
|
|
143
|
+
async create(id, data) {
|
|
144
|
+
return this.inner.create(id, data);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Read and decrypt a record, with all counter values merged in.
|
|
148
|
+
* Returns `null` if the record does not exist.
|
|
149
|
+
*/
|
|
150
|
+
async findUnique(id) {
|
|
151
|
+
const [row, counterValues] = await Promise.all([
|
|
152
|
+
this.inner.findUnique(id),
|
|
153
|
+
this.counters(id),
|
|
154
|
+
]);
|
|
155
|
+
if (row === null)
|
|
156
|
+
return null;
|
|
157
|
+
return { ...row, ...counterValues };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* List and decrypt all records owned by `ownerAddress`.
|
|
161
|
+
* Counter values are merged into every record.
|
|
162
|
+
*/
|
|
163
|
+
async findMany(ownerAddress, options) {
|
|
164
|
+
const rows = await this.inner.findMany(ownerAddress, options);
|
|
165
|
+
if (this.counterFields.length === 0) {
|
|
166
|
+
return rows;
|
|
167
|
+
}
|
|
168
|
+
// Fetch counters for each record in parallel
|
|
169
|
+
const withCounters = await Promise.all(rows.map(async (row) => {
|
|
170
|
+
// We need to re-derive id from recordKey — we can't, but we can derive
|
|
171
|
+
// key from recordKey directly: the recordKey IS the bytes32 key
|
|
172
|
+
const counterValues = await this._countersFromBytes32Key(row.recordKey);
|
|
173
|
+
return {
|
|
174
|
+
...row,
|
|
175
|
+
data: { ...row.data, ...counterValues },
|
|
176
|
+
};
|
|
177
|
+
}));
|
|
178
|
+
return withCounters;
|
|
179
|
+
}
|
|
180
|
+
/** Get all records (no chain limit). Counter values merged. */
|
|
181
|
+
async findAll(ownerAddress) {
|
|
182
|
+
const total = Number(await this.inner.count(ownerAddress));
|
|
183
|
+
return this.findMany(ownerAddress, { chainOffset: 0n, chainLimit: BigInt(total) });
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Patch an existing record — fetches current, merges patch, re-encrypts.
|
|
187
|
+
* Counter fields in patch are silently ignored (they live on-chain, not in ciphertext).
|
|
188
|
+
*/
|
|
189
|
+
async update(id, patch) {
|
|
190
|
+
// Strip counter fields from patch — they can't be written via update
|
|
191
|
+
const safePatch = { ...patch };
|
|
192
|
+
for (const cf of this.counterFields)
|
|
193
|
+
delete safePatch[cf];
|
|
194
|
+
return this.inner.update(id, safePatch);
|
|
195
|
+
}
|
|
196
|
+
/** Delete a record (soft-delete — scrubs all encrypted key copies). */
|
|
197
|
+
async delete(id) {
|
|
198
|
+
return this.inner.remove(id);
|
|
199
|
+
}
|
|
200
|
+
/** True if a live record exists for `id`. */
|
|
201
|
+
async exists(id) {
|
|
202
|
+
return this.inner.exists(id);
|
|
203
|
+
}
|
|
204
|
+
/** Total record count (including deleted) for `ownerAddress`. */
|
|
205
|
+
async count(ownerAddress) {
|
|
206
|
+
return this.inner.count(ownerAddress);
|
|
207
|
+
}
|
|
208
|
+
// ─────────────────────────────────────────────────────────────
|
|
209
|
+
// Access control (pass-through to raw client)
|
|
210
|
+
// ─────────────────────────────────────────────────────────────
|
|
211
|
+
async share(id, recipient, role, registry) {
|
|
212
|
+
return this.rawClient.share(this.key(id), recipient, role, registry);
|
|
213
|
+
}
|
|
214
|
+
async revoke(id, user) {
|
|
215
|
+
return this.rawClient.revoke(this.key(id), user);
|
|
216
|
+
}
|
|
217
|
+
// ─────────────────────────────────────────────────────────────
|
|
218
|
+
// Relation write (the key feature)
|
|
219
|
+
// ─────────────────────────────────────────────────────────────
|
|
220
|
+
/**
|
|
221
|
+
* Write a record to THIS table via a RelationWire, atomically incrementing
|
|
222
|
+
* counter fields on the TARGET table in the same transaction.
|
|
223
|
+
*
|
|
224
|
+
* For native CELO: pass `amount` in wei, do NOT pass `token`.
|
|
225
|
+
* For ERC-20: pass `token` address + `amount` in token units.
|
|
226
|
+
* You must have approved the wire contract beforehand —
|
|
227
|
+
* call `model.approveWire(wire, token, amount)` once.
|
|
228
|
+
*/
|
|
229
|
+
async relatedCreate(opts) {
|
|
230
|
+
const { wire, id, data, targetId, targetTable, amount = 0n, token } = opts;
|
|
231
|
+
const isErc20 = !!token && token !== ethers.ZeroAddress;
|
|
232
|
+
const isNative = !isErc20;
|
|
233
|
+
const { ciphertextBytes, encryptedKeyBytes } = await this._encryptPayload(id, data);
|
|
234
|
+
const sourceKey = this.key(id);
|
|
235
|
+
const targetKey = ethers.keccak256(ethers.solidityPacked(['string', 'uint256'], [targetTable, targetId]));
|
|
236
|
+
const wireContract = new ethers.Contract(wire, WIRE_ABI, this.signer);
|
|
237
|
+
if (isNative) {
|
|
238
|
+
const tx = await wireContract['relatedWrite'](sourceKey, ciphertextBytes, encryptedKeyBytes, targetKey, ethers.ZeroAddress, 0n, { value: amount });
|
|
239
|
+
return tx.wait();
|
|
240
|
+
}
|
|
241
|
+
// ── ERC-20: try permit (gasless approve), fall back to standard approve ──
|
|
242
|
+
const signerAddr = await this.signer.getAddress();
|
|
243
|
+
let usedPermit = false;
|
|
244
|
+
try {
|
|
245
|
+
const sig = await this._signPermit(token, wire, amount, signerAddr);
|
|
246
|
+
const tx = await wireContract['relatedWriteWithPermit'](sourceKey, ciphertextBytes, encryptedKeyBytes, targetKey, token, amount, sig.deadline, sig.v, sig.r, sig.s);
|
|
247
|
+
const receipt = await tx.wait();
|
|
248
|
+
usedPermit = true;
|
|
249
|
+
return receipt;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Token doesn't support EIP-2612 permit, or wallet can't sign typed data — fall through
|
|
253
|
+
}
|
|
254
|
+
if (!usedPermit) {
|
|
255
|
+
// Standard path: check allowance, approve if needed, then relatedWrite
|
|
256
|
+
const tokenContract = new ethers.Contract(token, ERC20_ABI, this.signer);
|
|
257
|
+
const allowance = BigInt(await tokenContract['allowance'](signerAddr, wire));
|
|
258
|
+
if (allowance < amount) {
|
|
259
|
+
const approveTx = await tokenContract['approve'](wire, ethers.MaxUint256);
|
|
260
|
+
await approveTx.wait();
|
|
261
|
+
}
|
|
262
|
+
const tx = await wireContract['relatedWrite'](sourceKey, ciphertextBytes, encryptedKeyBytes, targetKey, token, amount);
|
|
263
|
+
return tx.wait();
|
|
264
|
+
}
|
|
265
|
+
// unreachable but satisfies TypeScript
|
|
266
|
+
throw new Error('relatedCreate: unexpected state');
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Approve a RelationWire to spend your ERC-20 tokens.
|
|
270
|
+
* Call this once before using `relatedCreate` with an ERC-20 wire.
|
|
271
|
+
* You can approve `MaxUint256` for unlimited allowance.
|
|
272
|
+
*/
|
|
273
|
+
async approveWire(wire, token, amount = ethers.MaxUint256) {
|
|
274
|
+
const tokenContract = new ethers.Contract(token, ERC20_ABI, this.signer);
|
|
275
|
+
const tx = await tokenContract['approve'](wire, amount);
|
|
276
|
+
return tx.wait();
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Withdraw a single token's accumulated payments for a project record.
|
|
280
|
+
* Caller must be the record owner of `id` on this table.
|
|
281
|
+
*
|
|
282
|
+
* @param wire Address of the RelationWire contract
|
|
283
|
+
* @param id Primary key of THIS table's record (the project)
|
|
284
|
+
* @param token Token to withdraw (ethers.ZeroAddress = native CELO)
|
|
285
|
+
* @param to Recipient address (defaults to signer)
|
|
286
|
+
*/
|
|
287
|
+
async withdrawFunds(wire, id, token = ethers.ZeroAddress, to) {
|
|
288
|
+
const recipient = to ?? await this.signer.getAddress();
|
|
289
|
+
const wireContract = new ethers.Contract(wire, WIRE_ABI, this.signer);
|
|
290
|
+
const tx = await wireContract['withdrawProjectFunds'](this.key(id), token, recipient);
|
|
291
|
+
return tx.wait();
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Withdraw ALL token balances for a project in one transaction.
|
|
295
|
+
* Caller must be the record owner of `id` on this table.
|
|
296
|
+
*
|
|
297
|
+
* @param wire Address of the RelationWire contract
|
|
298
|
+
* @param id Primary key of the project record
|
|
299
|
+
* @param to Recipient address (defaults to signer)
|
|
300
|
+
*/
|
|
301
|
+
async withdrawAllFunds(wire, id, to) {
|
|
302
|
+
const recipient = to ?? await this.signer.getAddress();
|
|
303
|
+
const wireContract = new ethers.Contract(wire, WIRE_ABI, this.signer);
|
|
304
|
+
const tx = await wireContract['withdrawAllProjectFunds'](this.key(id), recipient);
|
|
305
|
+
return tx.wait();
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Check pending balances for a project across all tokens accepted by the wire.
|
|
309
|
+
* Returns a plain object: { tokenAddress: bigintBalance, ... }
|
|
310
|
+
*
|
|
311
|
+
* @param wire Address of the RelationWire contract
|
|
312
|
+
* @param id Primary key of the project record
|
|
313
|
+
*/
|
|
314
|
+
async projectBalances(wire, id) {
|
|
315
|
+
const wireContract = new ethers.Contract(wire, WIRE_ABI, this.provider);
|
|
316
|
+
const { tokens, balances } = await wireContract['projectBalances'](this.key(id));
|
|
317
|
+
const result = {};
|
|
318
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
319
|
+
result[tokens[i]] = BigInt(balances[i]);
|
|
320
|
+
}
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
// ─────────────────────────────────────────────────────────────
|
|
324
|
+
// Private helpers
|
|
325
|
+
// ─────────────────────────────────────────────────────────────
|
|
326
|
+
/**
|
|
327
|
+
* Build and sign an EIP-2612 permit signature.
|
|
328
|
+
* Works for cUSD, cEUR, cREAL, USDC and any token that implements ERC-2612.
|
|
329
|
+
* Throws if the token doesn't expose `nonces()` or `DOMAIN_SEPARATOR()`.
|
|
330
|
+
*/
|
|
331
|
+
async _signPermit(token, spender, value, owner, ttl = 20 * 60) {
|
|
332
|
+
const tokenContract = new ethers.Contract(token, ERC20_ABI, this.provider);
|
|
333
|
+
const [nonce, name, deadline] = await Promise.all([
|
|
334
|
+
tokenContract['nonces'](owner).then(BigInt),
|
|
335
|
+
tokenContract['name'](),
|
|
336
|
+
Promise.resolve(BigInt(Math.floor(Date.now() / 1000) + ttl)),
|
|
337
|
+
]);
|
|
338
|
+
// Try ERC-2612 version(); many tokens omit it and default to "1"
|
|
339
|
+
let version = '1';
|
|
340
|
+
try {
|
|
341
|
+
version = await tokenContract['version']();
|
|
342
|
+
}
|
|
343
|
+
catch { /* default "1" */ }
|
|
344
|
+
const network = await this.provider.getNetwork();
|
|
345
|
+
const domain = { name, version, chainId: Number(network.chainId), verifyingContract: token };
|
|
346
|
+
const types = {
|
|
347
|
+
Permit: [
|
|
348
|
+
{ name: 'owner', type: 'address' },
|
|
349
|
+
{ name: 'spender', type: 'address' },
|
|
350
|
+
{ name: 'value', type: 'uint256' },
|
|
351
|
+
{ name: 'nonce', type: 'uint256' },
|
|
352
|
+
{ name: 'deadline', type: 'uint256' },
|
|
353
|
+
],
|
|
354
|
+
};
|
|
355
|
+
const message = { owner, spender, value, nonce, deadline };
|
|
356
|
+
const sig = await this.signer.signTypedData(domain, types, message);
|
|
357
|
+
const { v, r, s } = ethers.Signature.from(sig);
|
|
358
|
+
return { deadline, v, r, s };
|
|
359
|
+
}
|
|
360
|
+
async _countersFromBytes32Key(recordKey) {
|
|
361
|
+
if (this.counterFields.length === 0)
|
|
362
|
+
return {};
|
|
363
|
+
const contract = new ethers.Contract(this.tableAddress, COUNTER_ABI, this.provider);
|
|
364
|
+
const values = await Promise.all(this.counterFields.map(async (name) => {
|
|
365
|
+
const hash = this.counterFieldHashes.get(name);
|
|
366
|
+
const raw = await contract['counterValue'](recordKey, hash);
|
|
367
|
+
return [name, BigInt(raw)];
|
|
368
|
+
}));
|
|
369
|
+
return Object.fromEntries(values);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Encrypt a payload for self, returning raw bytes for the wire contract.
|
|
373
|
+
*/
|
|
374
|
+
async _encryptPayload(_id, data) {
|
|
375
|
+
const { ciphertext, encryptedKey } = await this.rawClient.encryptForSelf(JSON.stringify(data));
|
|
376
|
+
return { ciphertextBytes: ciphertext, encryptedKeyBytes: encryptedKey };
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file query.ts
|
|
3
|
+
* @notice Web3QL v1.1 — client-side query engine.
|
|
4
|
+
*
|
|
5
|
+
* After decrypting records from the chain, this module provides:
|
|
6
|
+
* • WHERE filtering — eq, ne, gt, gte, lt, lte, in, notIn, like, between, isNull, isNotNull
|
|
7
|
+
* • ORDER BY — multi-column, ASC/DESC
|
|
8
|
+
* • LIMIT / OFFSET — pagination over decrypted records
|
|
9
|
+
* • SELECT projection — pick only specific fields
|
|
10
|
+
* • DISTINCT — deduplicate on a column value
|
|
11
|
+
* • COUNT / SUM / AVG / MIN / MAX / GROUP BY aggregations
|
|
12
|
+
*
|
|
13
|
+
* All operations run in-process on the decrypted plaintext — the chain
|
|
14
|
+
* sees only ciphertext. For large tables, use the relay-maintained index
|
|
15
|
+
* endpoint (v1.2) to avoid decrypting every record.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ─────────────────────────────────────────────────────────────
|
|
19
|
+
* const results = query(records)
|
|
20
|
+
* .where('age', 'gt', 18n)
|
|
21
|
+
* .where('name', 'like', 'Ali%')
|
|
22
|
+
* .orderBy('age', 'asc')
|
|
23
|
+
* .limit(10)
|
|
24
|
+
* .select(['name', 'age'])
|
|
25
|
+
* .execute();
|
|
26
|
+
*
|
|
27
|
+
* const stats = query(records)
|
|
28
|
+
* .where('active', 'eq', true)
|
|
29
|
+
* .aggregate({ count: '*', avg: 'score', max: 'score' });
|
|
30
|
+
* ─────────────────────────────────────────────────────────────
|
|
31
|
+
*/
|
|
32
|
+
export type Row = Record<string, unknown>;
|
|
33
|
+
export type WhereOperator = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'like' | 'ilike' | 'between' | 'isNull' | 'isNotNull';
|
|
34
|
+
export interface WhereClause {
|
|
35
|
+
field: string;
|
|
36
|
+
op: WhereOperator;
|
|
37
|
+
/** Single value for eq/ne/gt/gte/lt/lte/like/ilike/isNull/isNotNull */
|
|
38
|
+
value?: unknown;
|
|
39
|
+
/** Array for `in` and `notIn` */
|
|
40
|
+
values?: unknown[];
|
|
41
|
+
/** Two-element tuple for `between` */
|
|
42
|
+
range?: [unknown, unknown];
|
|
43
|
+
}
|
|
44
|
+
export type SortDirection = 'asc' | 'desc';
|
|
45
|
+
export interface OrderByClause {
|
|
46
|
+
field: string;
|
|
47
|
+
direction: SortDirection;
|
|
48
|
+
}
|
|
49
|
+
export interface AggregateOptions {
|
|
50
|
+
count?: '*' | string;
|
|
51
|
+
sum?: string;
|
|
52
|
+
avg?: string;
|
|
53
|
+
min?: string;
|
|
54
|
+
max?: string;
|
|
55
|
+
groupBy?: string;
|
|
56
|
+
/** Time-bucketing: group timestamps by 'minute'|'hour'|'day'|'week'|'month'|'year' */
|
|
57
|
+
timeBucket?: {
|
|
58
|
+
field: string;
|
|
59
|
+
unit: TimeBucketUnit;
|
|
60
|
+
};
|
|
61
|
+
/** HAVING — filter on aggregated values (applied after aggregation) */
|
|
62
|
+
having?: HavingClause[];
|
|
63
|
+
}
|
|
64
|
+
export type TimeBucketUnit = 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
|
|
65
|
+
export interface HavingClause {
|
|
66
|
+
/** 'count'|'sum'|'avg'|'min'|'max' */
|
|
67
|
+
aggregate: 'count' | 'sum' | 'avg';
|
|
68
|
+
op: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte';
|
|
69
|
+
value: number;
|
|
70
|
+
}
|
|
71
|
+
export interface AggregateResult {
|
|
72
|
+
group?: unknown;
|
|
73
|
+
count?: number;
|
|
74
|
+
sum?: number;
|
|
75
|
+
avg?: number;
|
|
76
|
+
min?: unknown;
|
|
77
|
+
max?: unknown;
|
|
78
|
+
}
|
|
79
|
+
export type JoinType = 'inner' | 'left' | 'right';
|
|
80
|
+
export interface JoinClause {
|
|
81
|
+
type: JoinType;
|
|
82
|
+
right: Row[];
|
|
83
|
+
on: {
|
|
84
|
+
left: string;
|
|
85
|
+
right: string;
|
|
86
|
+
};
|
|
87
|
+
/** Prefix added to right-side fields to avoid collision. Default: 'j_' */
|
|
88
|
+
prefix?: string;
|
|
89
|
+
}
|
|
90
|
+
export declare class QueryBuilder<T extends Row> {
|
|
91
|
+
private _rows;
|
|
92
|
+
private _wheres;
|
|
93
|
+
private _orders;
|
|
94
|
+
private _limitN?;
|
|
95
|
+
private _offsetN?;
|
|
96
|
+
private _fields?;
|
|
97
|
+
private _distinct?;
|
|
98
|
+
private _joins;
|
|
99
|
+
constructor(rows: T[]);
|
|
100
|
+
/**
|
|
101
|
+
* Add a WHERE condition. Multiple calls are ANDed together.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* .where('age', 'gt', 18n)
|
|
105
|
+
* .where('status', 'in', undefined, ['active', 'pending'])
|
|
106
|
+
* .where('score', 'between', undefined, undefined, [0, 100])
|
|
107
|
+
* .where('deletedAt', 'isNull')
|
|
108
|
+
*/
|
|
109
|
+
where(field: string, op: 'isNull' | 'isNotNull'): this;
|
|
110
|
+
where(field: string, op: 'in' | 'notIn', values: unknown[]): this;
|
|
111
|
+
where(field: string, op: 'between', range: [unknown, unknown]): this;
|
|
112
|
+
where(field: string, op: WhereOperator, value?: unknown): this;
|
|
113
|
+
/** Add an ORDER BY clause. Multiple calls are applied in sequence. */
|
|
114
|
+
orderBy(field: string, direction?: SortDirection): this;
|
|
115
|
+
limit(n: number): this;
|
|
116
|
+
offset(n: number): this;
|
|
117
|
+
/** Return only the specified fields from each row. */
|
|
118
|
+
select(fields: string[]): this;
|
|
119
|
+
/** Deduplicate rows where `field` has the same value. */
|
|
120
|
+
distinct(field: string): this;
|
|
121
|
+
/**
|
|
122
|
+
* Join this table with a `right` array on matching key columns.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* query(orders)
|
|
126
|
+
* .join('inner', users, { left: 'userId', right: 'id' })
|
|
127
|
+
* .execute()
|
|
128
|
+
* // Each matched row = order fields + user fields prefixed with 'j_'
|
|
129
|
+
*
|
|
130
|
+
* query(orders)
|
|
131
|
+
* .join('left', users, { left: 'userId', right: 'id' }, 'user_')
|
|
132
|
+
* .select(['id', 'user_name', 'amount'])
|
|
133
|
+
* .execute()
|
|
134
|
+
*/
|
|
135
|
+
join(type: JoinType, right: Row[], on: {
|
|
136
|
+
left: string;
|
|
137
|
+
right: string;
|
|
138
|
+
}, prefix?: string): this;
|
|
139
|
+
execute(): Partial<T>[];
|
|
140
|
+
/**
|
|
141
|
+
* Run aggregation functions over filtered (but not sorted/limited) rows.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* query(rows).where('active', 'eq', true).aggregate({ count: '*', avg: 'score' })
|
|
145
|
+
* // => [{ count: 42, avg: 78.5 }]
|
|
146
|
+
*
|
|
147
|
+
* query(rows).aggregate({ count: '*', groupBy: 'status' })
|
|
148
|
+
* // => [{ group: 'active', count: 30 }, { group: 'inactive', count: 12 }]
|
|
149
|
+
*/
|
|
150
|
+
aggregate(opts: AggregateOptions): AggregateResult[];
|
|
151
|
+
private _aggregateGroup;
|
|
152
|
+
}
|
|
153
|
+
/** Fluent entry point: `query(records).where(...).orderBy(...).execute()` */
|
|
154
|
+
export declare function query<T extends Row>(rows: T[]): QueryBuilder<T>;
|
|
155
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/query.ts"],"names":[],"mappings":"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"}
|