@forgezero/runtime 0.1.14 → 0.1.16

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.
Files changed (44) hide show
  1. package/README.md +27 -388
  2. package/dist/jobs.d.ts +5 -6
  3. package/dist/notify-templates.js +1 -1
  4. package/dist/schema-typebox.js +116 -7
  5. package/dist/schema.d.ts +14 -1
  6. package/dist/schema.js +116 -7
  7. package/package.json +3 -62
  8. package/contracts/foundry.toml +0 -9
  9. package/contracts/src/ColdVault.sol +0 -206
  10. package/contracts/src/DepositFactory.sol +0 -202
  11. package/contracts/src/DepositProxy.sol +0 -72
  12. package/contracts/src/IERC20.sol +0 -7
  13. package/contracts/src/MockTokens.sol +0 -32
  14. package/contracts/src/SafeTransferLib.sol +0 -31
  15. package/contracts/test/Custody.t.sol +0 -361
  16. package/contracts/test/Vectors.t.sol +0 -45
  17. package/dist/compliance.d.ts +0 -172
  18. package/dist/compliance.js +0 -168
  19. package/dist/finance/chain-addresses.d.ts +0 -130
  20. package/dist/finance/chain-addresses.js +0 -462
  21. package/dist/finance/chain-deposits.d.ts +0 -193
  22. package/dist/finance/chain-deposits.js +0 -600
  23. package/dist/finance/chain-reconcile.d.ts +0 -112
  24. package/dist/finance/chain-reconcile.js +0 -76
  25. package/dist/finance/chain-withdrawals.d.ts +0 -223
  26. package/dist/finance/chain-withdrawals.js +0 -635
  27. package/dist/finance/chain.d.ts +0 -116
  28. package/dist/finance/chain.js +0 -316
  29. package/dist/finance/commission.d.ts +0 -155
  30. package/dist/finance/commission.js +0 -423
  31. package/dist/finance/custody.d.ts +0 -68
  32. package/dist/finance/custody.js +0 -107
  33. package/dist/finance/derive.d.ts +0 -115
  34. package/dist/finance/derive.js +0 -116
  35. package/dist/finance/ledger.d.ts +0 -227
  36. package/dist/finance/ledger.js +0 -313
  37. package/dist/finance/market.d.ts +0 -209
  38. package/dist/finance/market.js +0 -112
  39. package/dist/finance/rates.d.ts +0 -178
  40. package/dist/finance/rates.js +0 -292
  41. package/dist/finance/transfers.d.ts +0 -153
  42. package/dist/finance/transfers.js +0 -292
  43. package/dist/finance/venues.d.ts +0 -190
  44. package/dist/finance/venues.js +0 -251
@@ -1,423 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined")
5
- return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
-
9
- // src/finance/money.ts
10
- class MoneyError extends Error {
11
- code;
12
- constructor(code, message) {
13
- super(message);
14
- this.code = code;
15
- this.name = "MoneyError";
16
- }
17
- }
18
- var ASSETS = [
19
- { code: "USDT", decimals: 6 },
20
- { code: "USDC", decimals: 6 },
21
- { code: "BTC", decimals: 8 },
22
- { code: "ETH", decimals: 18 },
23
- { code: "BNB", decimals: 18 },
24
- { code: "EUR", decimals: 2 },
25
- { code: "USD", decimals: 2 }
26
- ];
27
- var REGISTRY = new Map(ASSETS.map((asset) => [asset.code, asset]));
28
- function defineAsset(spec) {
29
- if (spec.decimals < 0 || spec.decimals > 30 || !Number.isInteger(spec.decimals)) {
30
- throw new MoneyError("UNKNOWN_ASSET", `${spec.code}: decimals must be an integer 0–30.`);
31
- }
32
- REGISTRY.set(spec.code, spec);
33
- }
34
- function assetSpec(code) {
35
- const spec = REGISTRY.get(code);
36
- if (!spec)
37
- throw new MoneyError("UNKNOWN_ASSET", `Unknown asset "${code}". Call defineAsset first.`);
38
- return spec;
39
- }
40
- var money = (units, asset) => {
41
- assetSpec(asset);
42
- return { units, asset };
43
- };
44
- var zero = (asset) => money(0n, asset);
45
- function parseAmount(value, asset) {
46
- const spec = assetSpec(asset);
47
- const text = value.trim();
48
- if (!/^-?\d+(\.\d+)?$/.test(text)) {
49
- throw new MoneyError("NOT_FINITE", `"${value}" is not a plain decimal amount.`);
50
- }
51
- const negative = text.startsWith("-");
52
- const [whole, fraction = ""] = text.replace("-", "").split(".");
53
- if (fraction.length > spec.decimals) {
54
- throw new MoneyError("PRECISION_LOSS", `${asset} has ${spec.decimals} decimals; "${value}" has ${fraction.length}.`);
55
- }
56
- const padded = fraction.padEnd(spec.decimals, "0");
57
- const units = BigInt(whole + padded);
58
- return { units: negative ? -units : units, asset };
59
- }
60
- function formatAmount(amount, options = {}) {
61
- const spec = assetSpec(amount.asset);
62
- const negative = amount.units < 0n;
63
- const digits = (negative ? -amount.units : amount.units).toString().padStart(spec.decimals + 1, "0");
64
- const whole = digits.slice(0, digits.length - spec.decimals);
65
- let fraction = spec.decimals === 0 ? "" : digits.slice(digits.length - spec.decimals);
66
- if (options.trim && fraction)
67
- fraction = fraction.replace(/0+$/, "");
68
- return `${negative ? "-" : ""}${whole}${fraction ? `.${fraction}` : ""}`;
69
- }
70
- function sameAsset(a, b) {
71
- if (a.asset !== b.asset) {
72
- throw new MoneyError("ASSET_MISMATCH", `Cannot combine ${a.asset} and ${b.asset}.`);
73
- }
74
- }
75
- function add(a, b) {
76
- sameAsset(a, b);
77
- return { units: a.units + b.units, asset: a.asset };
78
- }
79
- function subtract(a, b) {
80
- sameAsset(a, b);
81
- return { units: a.units - b.units, asset: a.asset };
82
- }
83
- var negate = (amount) => ({ units: -amount.units, asset: amount.asset });
84
- var abs = (amount) => ({
85
- units: amount.units < 0n ? -amount.units : amount.units,
86
- asset: amount.asset
87
- });
88
- var isZero = (amount) => amount.units === 0n;
89
- var isNegative = (amount) => amount.units < 0n;
90
- function compare(a, b) {
91
- sameAsset(a, b);
92
- return a.units < b.units ? -1 : a.units > b.units ? 1 : 0;
93
- }
94
- var equals = (a, b) => a.asset === b.asset && a.units === b.units;
95
- var ROUNDING = ["down", "up", "half-up"];
96
- function divideRounded(numerator, denominator, mode) {
97
- if (denominator === 0n)
98
- throw new MoneyError("DIVIDE_BY_ZERO", "Division by zero.");
99
- const negative = numerator < 0n !== denominator < 0n;
100
- const a = numerator < 0n ? -numerator : numerator;
101
- const b = denominator < 0n ? -denominator : denominator;
102
- const quotient = a / b;
103
- const remainder = a % b;
104
- if (remainder === 0n)
105
- return negative ? -quotient : quotient;
106
- let result = quotient;
107
- if (mode === "up")
108
- result += 1n;
109
- else if (mode === "half-up" && remainder * 2n >= b)
110
- result += 1n;
111
- return negative ? -result : result;
112
- }
113
- function mulRate(amount, rate, mode = "down") {
114
- if (!/^-?\d+(\.\d+)?$/.test(rate.trim())) {
115
- throw new MoneyError("NOT_FINITE", `"${rate}" is not a plain decimal rate.`);
116
- }
117
- const [whole, fraction = ""] = rate.trim().replace("-", "").split(".");
118
- const scale = 10n ** BigInt(fraction.length);
119
- const scaled = BigInt(whole + fraction) * (rate.trim().startsWith("-") ? -1n : 1n);
120
- return { units: divideRounded(amount.units * scaled, scale, mode), asset: amount.asset };
121
- }
122
- function convert(amount, to, rate, mode = "down") {
123
- const from = assetSpec(amount.asset);
124
- const target = assetSpec(to);
125
- const asTarget = mulRate({ units: amount.units, asset: to }, rate, mode);
126
- const shift = target.decimals - from.decimals;
127
- if (shift === 0)
128
- return asTarget;
129
- if (shift > 0)
130
- return { units: asTarget.units * 10n ** BigInt(shift), asset: to };
131
- return { units: divideRounded(asTarget.units, 10n ** BigInt(-shift), mode), asset: to };
132
- }
133
- function allocate(amount, parts) {
134
- if (parts < 1)
135
- throw new MoneyError("NOT_FINITE", "Cannot allocate into fewer than one part.");
136
- const each = divideRounded(amount.units, BigInt(parts), "down");
137
- const allocated = Array.from({ length: parts }, () => each);
138
- let remainder = amount.units - each * BigInt(parts);
139
- const step = remainder < 0n ? -1n : 1n;
140
- for (let index = 0;remainder !== 0n; index = (index + 1) % parts) {
141
- allocated[index] += step;
142
- remainder -= step;
143
- }
144
- return allocated.map((units) => ({ units, asset: amount.asset }));
145
- }
146
- function toStep(amount, step, mode = "down") {
147
- const stepUnits = parseAmount(step, amount.asset).units;
148
- if (stepUnits <= 0n)
149
- throw new MoneyError("NOT_FINITE", "A step must be positive.");
150
- return { units: divideRounded(amount.units, stepUnits, mode) * stepUnits, asset: amount.asset };
151
- }
152
- var VERSION = "0.1.0";
153
-
154
- // src/finance/ledger.ts
155
- class LedgerError extends Error {
156
- code;
157
- constructor(code, message) {
158
- super(message);
159
- this.code = code;
160
- this.name = "LedgerError";
161
- }
162
- }
163
- var BUCKETS = ["available", "held"];
164
- var ACCOUNT_KINDS = ["user", "platform", "external"];
165
- var accountId = (account) => `${account.kind}:${account.owner}:${account.bucket ?? "available"}`;
166
- function parseAccount(id) {
167
- const [kind, owner, bucket] = id.split(":");
168
- return { kind, owner, bucket };
169
- }
170
- var queueKeyFor = (account) => `${account.kind}:${account.owner}`;
171
- var MAX_LEDGER_ENTRIES = 64;
172
- function assertBalanced(transaction) {
173
- if (transaction.entries.length < 2) {
174
- throw new LedgerError("EMPTY_TRANSACTION", "A transaction needs at least two entries.");
175
- }
176
- if (transaction.entries.length > MAX_LEDGER_ENTRIES) {
177
- throw new LedgerError("TOO_MANY_ENTRIES", `A transaction may contain at most ${MAX_LEDGER_ENTRIES} entries; split this batch into separate transactions.`);
178
- }
179
- const totals = new Map;
180
- for (const entry of transaction.entries) {
181
- if (entry.amount.units === 0n) {
182
- throw new LedgerError("ZERO_ENTRY", `An entry on ${accountId(entry.account)} moves nothing. Remove it or give it an amount.`);
183
- }
184
- totals.set(entry.amount.asset, (totals.get(entry.amount.asset) ?? 0n) + entry.amount.units);
185
- }
186
- for (const [asset, total] of totals) {
187
- if (total !== 0n) {
188
- throw new LedgerError("UNBALANCED", `${asset} does not sum to zero — it is off by ${total} minor units. Every movement needs a counterparty.`);
189
- }
190
- }
191
- }
192
- function transfer(args) {
193
- const transaction = {
194
- reference: args.reference,
195
- kind: args.kind,
196
- atMs: args.atMs,
197
- memo: args.memo,
198
- entries: [
199
- { account: args.from, amount: { units: -args.amount.units, asset: args.amount.asset } },
200
- { account: args.to, amount: args.amount }
201
- ]
202
- };
203
- assertBalanced(transaction);
204
- return transaction;
205
- }
206
- var placeHold = (args) => transfer({
207
- reference: args.reference,
208
- kind: "hold.place",
209
- from: { kind: args.kind ?? "user", owner: args.owner, bucket: "available" },
210
- to: { kind: args.kind ?? "user", owner: args.owner, bucket: "held" },
211
- amount: args.amount,
212
- atMs: args.atMs,
213
- memo: args.memo
214
- });
215
- var releaseHold = (args) => transfer({
216
- reference: args.reference,
217
- kind: "hold.release",
218
- from: { kind: args.kind ?? "user", owner: args.owner, bucket: "held" },
219
- to: { kind: args.kind ?? "user", owner: args.owner, bucket: "available" },
220
- amount: args.amount,
221
- atMs: args.atMs
222
- });
223
- var captureHold = (args) => transfer({
224
- reference: args.reference,
225
- kind: "hold.capture",
226
- from: { kind: args.kind ?? "user", owner: args.owner, bucket: "held" },
227
- to: args.to,
228
- amount: args.amount,
229
- atMs: args.atMs,
230
- memo: args.memo
231
- });
232
- function balancesFrom(transactions) {
233
- const balances = new Map;
234
- for (const transaction of transactions) {
235
- for (const entry of transaction.entries) {
236
- const id = accountId(entry.account);
237
- const perAsset = balances.get(id) ?? new Map;
238
- const current = perAsset.get(entry.amount.asset) ?? zero(entry.amount.asset);
239
- perAsset.set(entry.amount.asset, add(current, entry.amount));
240
- balances.set(id, perAsset);
241
- }
242
- }
243
- return balances;
244
- }
245
- function balanceOf(balances, account, asset) {
246
- return balances.get(accountId(account))?.get(asset) ?? zero(asset);
247
- }
248
- var availableOf = (balances, owner, asset, kind = "user") => balanceOf(balances, { kind, owner, bucket: "available" }, asset);
249
- var heldOf = (balances, owner, asset, kind = "user") => balanceOf(balances, { kind, owner, bucket: "held" }, asset);
250
- var totalOf = (balances, owner, asset, kind = "user") => add(availableOf(balances, owner, asset, kind), heldOf(balances, owner, asset, kind));
251
- function trialBalance(transactions) {
252
- const totals = new Map;
253
- const accounts = new Map;
254
- for (const transaction of transactions) {
255
- for (const entry of transaction.entries) {
256
- totals.set(entry.amount.asset, (totals.get(entry.amount.asset) ?? 0n) + entry.amount.units);
257
- const seen = accounts.get(entry.amount.asset) ?? new Set;
258
- seen.add(accountId(entry.account));
259
- accounts.set(entry.amount.asset, seen);
260
- }
261
- }
262
- const perAsset = [...totals.entries()].map(([asset, total]) => ({
263
- asset,
264
- total,
265
- accounts: accounts.get(asset)?.size ?? 0
266
- }));
267
- const discrepancies = perAsset.filter((row) => row.total !== 0n).map((row) => ({ asset: row.asset, off: row.total }));
268
- return { ok: discrepancies.length === 0, perAsset, discrepancies };
269
- }
270
- function statement(transactions, account, asset) {
271
- const id = accountId(account);
272
- let running = zero(asset);
273
- return [...transactions].sort((a, b) => a.atMs - b.atMs).flatMap((transaction) => transaction.entries.filter((entry) => accountId(entry.account) === id && entry.amount.asset === asset).map((entry) => {
274
- running = add(running, entry.amount);
275
- return {
276
- atMs: transaction.atMs,
277
- reference: transaction.reference,
278
- kind: transaction.kind,
279
- amount: formatAmount(entry.amount, { trim: true }),
280
- balance: formatAmount(running, { trim: true })
281
- };
282
- }));
283
- }
284
- function assertAvailable(balances, args) {
285
- const available = availableOf(balances, args.owner, args.amount.asset, args.kind ?? "user");
286
- if (subtract(available, args.amount).units < 0n) {
287
- throw new LedgerError("INSUFFICIENT_AVAILABLE", `${args.owner} has ${formatAmount(available, { trim: true })} ${args.amount.asset} available; this needs ${formatAmount(args.amount, { trim: true })}.`);
288
- }
289
- }
290
- var VERSION2 = "0.1.0";
291
-
292
- // src/finance/commission.ts
293
- class CommissionError extends Error {
294
- code;
295
- constructor(code, message) {
296
- super(message);
297
- this.code = code;
298
- this.name = "CommissionError";
299
- }
300
- }
301
- var RATE = /^\d+(\.\d+)?$/;
302
- function assertRate(rate, field) {
303
- if (typeof rate !== "string") {
304
- throw new CommissionError("BAD_RATE", `${field} must be a decimal STRING, not a ${typeof rate}. A rate as a float literal is how 0.3 becomes 0.30000000000000004.`);
305
- }
306
- if (!RATE.test(rate.trim()) || Number(rate) > 1) {
307
- throw new CommissionError("BAD_RATE", `${field} must be a decimal string between 0 and 1, not "${rate}". A rate as a float literal is how 0.3 becomes 0.30000000000000004.`);
308
- }
309
- }
310
- function periodProfit(performance) {
311
- const asset = performance.openingEquity.asset;
312
- for (const [name, amount] of Object.entries(performance)) {
313
- if (amount.asset !== asset) {
314
- throw new CommissionError("ASSET_MISMATCH", `${name} is in ${amount.asset} and the period opens in ${asset}.`);
315
- }
316
- }
317
- const gross = subtract(performance.closingEquity, performance.openingEquity);
318
- return add(subtract(gross, performance.deposits), performance.withdrawals);
319
- }
320
- function chargeableProfit(performance) {
321
- const asset = performance.openingEquity.asset;
322
- const profit = periodProfit(performance);
323
- if (profit.units <= 0n)
324
- return zero(asset);
325
- const netClosing = add(subtract(performance.closingEquity, performance.deposits), performance.withdrawals);
326
- if (netClosing.units <= performance.highWaterMark.units)
327
- return zero(asset);
328
- const aboveMark = subtract(netClosing, performance.highWaterMark);
329
- return aboveMark.units < profit.units ? aboveMark : profit;
330
- }
331
- var nextHighWaterMark = (performance) => {
332
- const netClosing = add(subtract(performance.closingEquity, performance.deposits), performance.withdrawals);
333
- return netClosing.units > performance.highWaterMark.units ? netClosing : performance.highWaterMark;
334
- };
335
- function splitCommission(input) {
336
- assertRate(input.commissionRate, "The commission rate");
337
- if (input.referralRate)
338
- assertRate(input.referralRate, "The referral rate");
339
- const asset = input.profit.asset;
340
- if (input.profit.units <= 0n) {
341
- return { total: zero(asset), platform: zero(asset), referral: zero(asset) };
342
- }
343
- const total = mulRate(input.profit, input.commissionRate, "down");
344
- if (!input.referrer || !input.referralRate || total.units === 0n) {
345
- return { total, platform: total, referral: zero(asset) };
346
- }
347
- const referral = mulRate(total, input.referralRate, "down");
348
- return {
349
- total,
350
- platform: subtract(total, referral),
351
- referral,
352
- referrer: input.referrer
353
- };
354
- }
355
- function commissionTransaction(args) {
356
- if (args.split.total.units === 0n)
357
- return null;
358
- const revenue = args.revenueAccount ?? { kind: "platform", owner: "revenue" };
359
- const from = { kind: "user", owner: args.owner, bucket: "available" };
360
- if (args.split.referral.units === 0n) {
361
- return transfer({
362
- reference: args.reference,
363
- kind: "commission",
364
- from,
365
- to: revenue,
366
- amount: args.split.total,
367
- atMs: args.atMs
368
- });
369
- }
370
- return {
371
- reference: args.reference,
372
- kind: "commission",
373
- atMs: args.atMs,
374
- memo: `commission with referral to ${args.split.referrer}`,
375
- entries: [
376
- { account: from, amount: { units: -args.split.total.units, asset: args.split.total.asset } },
377
- { account: revenue, amount: args.split.platform },
378
- {
379
- account: { kind: "user", owner: args.split.referrer, bucket: "available" },
380
- amount: args.split.referral
381
- }
382
- ]
383
- };
384
- }
385
- function projectPrepay(input) {
386
- assertRate(input.projectedReturnRate, "The projected return");
387
- assertRate(input.commissionRate, "The commission rate");
388
- assertRate(input.prepayRate, "The prepay rate");
389
- const projectedProfit = mulRate(input.subscriptionAmount, input.projectedReturnRate, "down");
390
- const projectedCommission = mulRate(projectedProfit, input.commissionRate, "down");
391
- return {
392
- projectedProfit,
393
- projectedCommission,
394
- due: mulRate(projectedCommission, input.prepayRate, "down")
395
- };
396
- }
397
- function splitReferrals(income, shares) {
398
- let remaining = income;
399
- const paid = [];
400
- for (const share of shares) {
401
- assertRate(share.rate, `The rate for ${share.referrer}`);
402
- const amount = mulRate(income, share.rate, "down");
403
- if (amount.units === 0n)
404
- continue;
405
- if (amount.units > remaining.units) {
406
- throw new CommissionError("BAD_RATE", `Referral rates total more than the income of ${formatAmount(income, { trim: true })} ${income.asset}.`);
407
- }
408
- remaining = subtract(remaining, amount);
409
- paid.push({ referrer: share.referrer, amount });
410
- }
411
- return { platform: remaining, paid };
412
- }
413
- export {
414
- splitReferrals,
415
- splitCommission,
416
- projectPrepay,
417
- periodProfit,
418
- nextHighWaterMark,
419
- commissionTransaction,
420
- chargeableProfit,
421
- allocate,
422
- CommissionError
423
- };
@@ -1,68 +0,0 @@
1
- export declare class CustodyError extends Error {
2
- readonly code: 'MALFORMED' | 'NOT_AN_ADDRESS' | 'BAD_THRESHOLD';
3
- constructor(code: 'MALFORMED' | 'NOT_AN_ADDRESS' | 'BAD_THRESHOLD', message: string);
4
- }
5
- /**
6
- * EIP-55 checksum.
7
- *
8
- * A lowercase address is valid and checks nothing. The mixed-case form catches
9
- * a mistyped character, which for a treasury destination is the difference
10
- * between a failed transaction and an unrecoverable one.
11
- */
12
- export declare function toChecksumAddress(address: string): string;
13
- /**
14
- * A salt from a namespace and a key.
15
- *
16
- * The contract treats a salt as opaque, so the CONVENTION is the platform's.
17
- * This only makes it consistent: a namespace stops a user key and an invoice
18
- * key that happen to share a value from deriving the same address, which would
19
- * silently merge two balances.
20
- */
21
- export declare function saltFor(namespace: string, key: string): string;
22
- /**
23
- * The CREATE2 deposit address for a salt.
24
- *
25
- * `keccak256(0xff ++ factory ++ salt ++ initCodeHash)`, last 20 bytes. The
26
- * init-code hash comes from the deployed factory's `PROXY_INIT_CODE_HASH`
27
- * rather than being hardcoded: a compiler change alters it, and a stale
28
- * constant would derive addresses the factory cannot sweep.
29
- */
30
- export declare function depositAddress(args: {
31
- factory: string;
32
- salt: string;
33
- proxyInitCodeHash: string;
34
- }): string;
35
- export declare function domainSeparator(args: {
36
- chainId: bigint;
37
- vault: string;
38
- }): string;
39
- /**
40
- * What each custodian signs, computed offline.
41
- *
42
- * Four things are inside it and each closes a replay: `chainId` stops a testnet
43
- * rehearsal executing on mainnet, `vault` stops approvals for one deployment
44
- * being pointed at another, `nonce` makes an approval spendable once, and the
45
- * request itself means changing the amount or destination voids every signature
46
- * already collected.
47
- */
48
- export declare function withdrawDigest(args: {
49
- chainId: bigint;
50
- vault: string;
51
- token: string;
52
- to: string;
53
- amount: bigint;
54
- nonce: bigint;
55
- }): string;
56
- /**
57
- * Order signatures the way the vault requires: ascending by signer address.
58
- *
59
- * Not cosmetic. The contract uses strict ordering to reject the same custodian
60
- * signing twice in one submission, so an unsorted batch of otherwise valid
61
- * approvals is refused — and a batch sorted the wrong way makes an M-of-N vault
62
- * satisfiable by one custodian.
63
- */
64
- export declare function orderSignatures(signatures: readonly {
65
- signer: string;
66
- signature: string;
67
- }[]): string[];
68
- export declare const VERSION = "0.1.0";
@@ -1,107 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined")
5
- return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
-
9
- // src/finance/custody.ts
10
- import { keccak_256 } from "@noble/hashes/sha3.js";
11
- var hex = (bytes) => [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
12
- var bytes = (value) => {
13
- const bare = value.replace(/^0x/i, "");
14
- if (bare.length % 2)
15
- throw new CustodyError("MALFORMED", `Not byte-aligned: ${value}`);
16
- const out = new Uint8Array(bare.length / 2);
17
- for (let i = 0;i < out.length; i++)
18
- out[i] = parseInt(bare.slice(i * 2, i * 2 + 2), 16);
19
- return out;
20
- };
21
- var concat = (...parts) => {
22
- const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
23
- let at = 0;
24
- for (const part of parts) {
25
- out.set(part, at);
26
- at += part.length;
27
- }
28
- return out;
29
- };
30
-
31
- class CustodyError extends Error {
32
- code;
33
- constructor(code, message) {
34
- super(message);
35
- this.code = code;
36
- this.name = "CustodyError";
37
- }
38
- }
39
- var assertAddress = (value, what) => {
40
- if (!/^0x[0-9a-fA-F]{40}$/.test(value)) {
41
- throw new CustodyError("NOT_AN_ADDRESS", `${what} is not an address: ${value}`);
42
- }
43
- return value;
44
- };
45
- function toChecksumAddress(address) {
46
- const bare = assertAddress(address, "address").slice(2).toLowerCase();
47
- const digest = hex(keccak_256(new TextEncoder().encode(bare)));
48
- let out = "0x";
49
- for (let i = 0;i < bare.length; i++) {
50
- out += parseInt(digest[i], 16) >= 8 ? bare[i].toUpperCase() : bare[i];
51
- }
52
- return out;
53
- }
54
- function saltFor(namespace, key) {
55
- return `0x${hex(keccak_256(new TextEncoder().encode(`${namespace}:${key}`)))}`;
56
- }
57
- function depositAddress(args) {
58
- assertAddress(args.factory, "factory");
59
- const salt = bytes(args.salt);
60
- if (salt.length !== 32)
61
- throw new CustodyError("MALFORMED", "A salt is 32 bytes.");
62
- const initCodeHash = bytes(args.proxyInitCodeHash);
63
- if (initCodeHash.length !== 32)
64
- throw new CustodyError("MALFORMED", "An init code hash is 32 bytes.");
65
- const digest = keccak_256(concat(Uint8Array.of(255), bytes(args.factory), salt, initCodeHash));
66
- return toChecksumAddress(`0x${hex(digest.slice(12))}`);
67
- }
68
- var keccakText = (value) => keccak_256(new TextEncoder().encode(value));
69
- var word = (value) => {
70
- const raw = typeof value === "bigint" ? value.toString(16) : value.replace(/^0x/i, "");
71
- return bytes(raw.padStart(64, "0"));
72
- };
73
- var DOMAIN_TYPEHASH = keccakText("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
74
- var WITHDRAW_TYPEHASH = keccakText("Withdraw(address token,address to,uint256 amount,uint256 nonce)");
75
- function domainSeparator(args) {
76
- assertAddress(args.vault, "vault");
77
- return `0x${hex(keccak_256(concat(DOMAIN_TYPEHASH, keccakText("ForgeZeroColdVault"), keccakText("1"), word(args.chainId), word(args.vault))))}`;
78
- }
79
- function withdrawDigest(args) {
80
- assertAddress(args.to, "to");
81
- assertAddress(args.token, "token");
82
- const structHash = keccak_256(concat(WITHDRAW_TYPEHASH, word(args.token), word(args.to), word(args.amount), word(args.nonce)));
83
- const separator = bytes(domainSeparator({ chainId: args.chainId, vault: args.vault }));
84
- return `0x${hex(keccak_256(concat(Uint8Array.of(25, 1), separator, structHash)))}`;
85
- }
86
- function orderSignatures(signatures) {
87
- const seen = new Set;
88
- for (const entry of signatures) {
89
- const key = assertAddress(entry.signer, "signer").toLowerCase();
90
- if (seen.has(key)) {
91
- throw new CustodyError("BAD_THRESHOLD", `${entry.signer} signed twice; that is one approval.`);
92
- }
93
- seen.add(key);
94
- }
95
- return [...signatures].sort((a, b) => BigInt(a.signer) < BigInt(b.signer) ? -1 : 1).map((entry) => entry.signature);
96
- }
97
- var VERSION = "0.1.0";
98
- export {
99
- withdrawDigest,
100
- toChecksumAddress,
101
- saltFor,
102
- orderSignatures,
103
- domainSeparator,
104
- depositAddress,
105
- VERSION,
106
- CustodyError
107
- };