mtok-verify 0.1.3 → 0.1.5
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 +11 -0
- package/fee-policy.js +30 -0
- package/onchain.js +2 -2
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -25,6 +25,17 @@ const paid = await verifier.verifyDrawPaid(drawPaidTxHash, {
|
|
|
25
25
|
if (!paid.ok) refuse(paid.reason); // else serve, bounded by paid.event
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Seller hosts can use the same historical fee policy as the market and reference relay:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { normalizeFeeSchedule, paymentFeeBpsAt } from 'mtok-verify/fee-policy';
|
|
32
|
+
|
|
33
|
+
const feeBps = paymentFeeBpsAt(normalizeFeeSchedule(config.feeSchedule), paid.paidAtMs);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Refresh the public config before new claims. Keep completed and pending claims replayable
|
|
37
|
+
without applying a new fee policy. `paidAtMs` must come from the verifier, never the request.
|
|
38
|
+
|
|
28
39
|
|
|
29
40
|
---
|
|
30
41
|
|
package/fee-policy.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function normalizeFeeSchedule(schedule) {
|
|
2
|
+
if (!Array.isArray(schedule) || !schedule.length || schedule.length > 64) throw new TypeError('fee schedule must contain 1..64 activation records');
|
|
3
|
+
let previous = -1;
|
|
4
|
+
return schedule.map(({ effectiveAtMs, feeBps }, index) => {
|
|
5
|
+
if (!Number.isSafeInteger(effectiveAtMs) || effectiveAtMs <= previous || (index === 0 && effectiveAtMs !== 0)) {
|
|
6
|
+
throw new TypeError('fee activations must start at 0 and increase in integer milliseconds');
|
|
7
|
+
}
|
|
8
|
+
if (!Number.isSafeInteger(feeBps) || feeBps < 0 || feeBps > 10_000) throw new TypeError('feeBps must be an integer from 0 to 10000');
|
|
9
|
+
previous = effectiveAtMs;
|
|
10
|
+
return { effectiveAtMs, feeBps };
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Schedules are normalized when configuration is loaded. Historical payments
|
|
15
|
+
// use their verified block time, never the relay's boot or first-observation time.
|
|
16
|
+
export function feeBpsAt(schedule, timeMs) {
|
|
17
|
+
if (!Number.isSafeInteger(timeMs) || timeMs < 0) throw new TypeError('verified payment time is required for fee policy');
|
|
18
|
+
return schedule.findLast(entry => entry.effectiveAtMs <= timeMs).feeBps;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// A buyer can read config immediately before an activation, then mine just
|
|
22
|
+
// after it. The previous rate is valid for one minute, never for a relay's lifetime.
|
|
23
|
+
export function paymentFeeBpsAt(schedule, paidAtMs) {
|
|
24
|
+
const start = Math.max(0, paidAtMs - 60_000);
|
|
25
|
+
let minimum = Math.min(feeBpsAt(schedule, paidAtMs), feeBpsAt(schedule, start));
|
|
26
|
+
for (const entry of schedule) {
|
|
27
|
+
if (entry.effectiveAtMs > start && entry.effectiveAtMs <= paidAtMs) minimum = Math.min(minimum, entry.feeBps);
|
|
28
|
+
}
|
|
29
|
+
return minimum;
|
|
30
|
+
}
|
package/onchain.js
CHANGED
|
@@ -277,9 +277,9 @@ export function createOnchainVerifier({ rpcUrl, rpcUrls, usdcAddress, expectedCh
|
|
|
277
277
|
// Once redemption records expire, verified payment age is the replay boundary.
|
|
278
278
|
// An unreadable timestamp is retryable uncertainty, never permission to spend.
|
|
279
279
|
const maxAge = Number(maxPaidAgeMs);
|
|
280
|
+
let paidAtMs = null;
|
|
280
281
|
if (Number.isFinite(maxAge) && maxAge > 0) {
|
|
281
282
|
const bn = matchedLog?.blockNumber ?? got.receipt.blockNumber;
|
|
282
|
-
let paidAtMs = null;
|
|
283
283
|
if (bn != null) {
|
|
284
284
|
for (let i = 0; i <= receiptRetries; i++) {
|
|
285
285
|
try {
|
|
@@ -317,7 +317,7 @@ export function createOnchainVerifier({ rpcUrl, rpcUrls, usdcAddress, expectedCh
|
|
|
317
317
|
if (!feeTransfer.ok) return { ok: false, reason: 'fee_transfer_' + feeTransfer.reason };
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
return { ok: true, event, from: sellerTransfer?.from ?? feeTransfer?.from ?? null };
|
|
320
|
+
return { ok: true, event, paidAtMs, from: sellerTransfer?.from ?? feeTransfer?.from ?? null };
|
|
321
321
|
},
|
|
322
322
|
};
|
|
323
323
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mtok-verify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "The on-chain verify core for mtok.market sellers: decode + verify a MtokDripLedger DrawPaid receipt (and its USDC transfer legs) against a paid draw, with the canonical DrawPaid topic set. Dependency-free, runs anywhere fetch runs (node, a CF Worker). The SSOT the platform + reference relay + house seller all share.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
-
".": "./onchain.js"
|
|
7
|
+
".": "./onchain.js",
|
|
8
|
+
"./fee-policy": "./fee-policy.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"onchain.js",
|
|
11
12
|
"errors.js",
|
|
13
|
+
"fee-policy.js",
|
|
12
14
|
"README.md"
|
|
13
15
|
],
|
|
14
16
|
"engines": {
|