@verify-network/protocol 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +147 -2
- package/dist/domain-CXJsoNRU.d.ts +9 -0
- package/dist/ecvrf.d.ts +69 -0
- package/dist/ecvrf.js +174 -0
- package/dist/event.d.ts +101 -0
- package/dist/event.js +53 -0
- package/dist/fee.d.ts +142 -0
- package/dist/fee.js +142 -0
- package/dist/fulfillment.d.ts +32 -0
- package/dist/fulfillment.js +28 -0
- package/dist/index.d.ts +708 -0
- package/dist/index.js +872 -0
- package/dist/request.d.ts +60 -0
- package/dist/request.js +61 -0
- package/package.json +56 -4
package/dist/fee.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Hex } from "viem";
|
|
2
|
+
//#region src/fee.d.ts
|
|
3
|
+
/** EIP-1559 fees for one broadcast. */
|
|
4
|
+
export type GasFees = {
|
|
5
|
+
readonly maxFeePerGas: bigint;
|
|
6
|
+
readonly maxPriorityFeePerGas: bigint;
|
|
7
|
+
};
|
|
8
|
+
/** The fees a node's sender never goes below unless configured otherwise; tuned for Base. */
|
|
9
|
+
export declare const DEFAULT_FEE_FLOOR: GasFees;
|
|
10
|
+
/**
|
|
11
|
+
* The fees a node's sender bids given the latest base fee: twice the base fee plus the tip, never
|
|
12
|
+
* under the floor. Here because a signer mirrors it: the enclave refuses an authorization whose
|
|
13
|
+
* maximum gas price is under this bid (ADR 0028), so a client sizes its maximum from it.
|
|
14
|
+
*/
|
|
15
|
+
export declare const computeFees: (baseFeePerGas: bigint, floor?: GasFees) => GasFees;
|
|
16
|
+
/**
|
|
17
|
+
* `Config.CALLDATA_GAS_PER_BYTE`: EIP-7623's calldata floor for a non-zero byte, charged for every
|
|
18
|
+
* echoed byte (ADR 0023).
|
|
19
|
+
*/
|
|
20
|
+
export declare const CALLDATA_GAS_PER_BYTE = 40n;
|
|
21
|
+
/**
|
|
22
|
+
* The gas price a request locks, mirroring the router's: the request transaction's gas price, never
|
|
23
|
+
* below the base fee of the block it lands in (ADR 0019). An OP-stack L1→L2 deposit transaction
|
|
24
|
+
* runs at a zero gas price; priced at that, its request would reserve nothing and its fulfillment
|
|
25
|
+
* charge nothing.
|
|
26
|
+
*/
|
|
27
|
+
export declare const lockedGasPrice: ({ gasPrice, baseFeePerGas }: {
|
|
28
|
+
readonly gasPrice: bigint;
|
|
29
|
+
readonly baseFeePerGas: bigint;
|
|
30
|
+
}) => bigint;
|
|
31
|
+
/**
|
|
32
|
+
* The fee a request locks at request time (ADR 0013, 0019, 0023):
|
|
33
|
+
* `(callbackGasLimit + fulfillmentOverheadGas + 40 × callbackDataLength) × lockedGasPrice × (100% + premium)`,
|
|
34
|
+
* rounded down to the wei, where the locked gas price is `gasPrice` floored at `baseFeePerGas`
|
|
35
|
+
* (`lockedGasPrice`). Mirrors the router's fee, so the router must multiply before it divides by
|
|
36
|
+
* 100 too. Gas amounts and the premium are accepted as `number` so a decoded request can be priced
|
|
37
|
+
* without conversion.
|
|
38
|
+
*/
|
|
39
|
+
export declare const fee: ({ callbackGasLimit, fulfillmentOverheadGas, callbackDataLength, gasPrice, baseFeePerGas, premiumPercent }: {
|
|
40
|
+
readonly callbackGasLimit: bigint | number;
|
|
41
|
+
readonly fulfillmentOverheadGas: bigint | number;
|
|
42
|
+
readonly callbackDataLength: bigint | number;
|
|
43
|
+
/** The gas price the request transaction is sent at. */
|
|
44
|
+
readonly gasPrice: bigint;
|
|
45
|
+
/** The base fee of the block the request lands in: the floor of the locked gas price. */
|
|
46
|
+
readonly baseFeePerGas: bigint;
|
|
47
|
+
readonly premiumPercent: bigint | number;
|
|
48
|
+
}) => bigint;
|
|
49
|
+
/**
|
|
50
|
+
* The most a direct request can ever charge (ADR 0028): the reservation formula at the maximum
|
|
51
|
+
* gas price the authorization names, with the same overhead and premium as an on-chain request.
|
|
52
|
+
* Mirrors the router's ceiling, which debits it from the signer's balance before the callback and
|
|
53
|
+
* credits back what the settlement does not take.
|
|
54
|
+
*/
|
|
55
|
+
export declare const ceiling: ({ callbackGasLimit, fulfillmentOverheadGas, callbackDataLength, maxGasPrice, premiumPercent }: {
|
|
56
|
+
readonly callbackGasLimit: bigint | number;
|
|
57
|
+
readonly fulfillmentOverheadGas: bigint | number;
|
|
58
|
+
readonly callbackDataLength: bigint | number;
|
|
59
|
+
/** The most the signer agreed to pay per gas: `DirectRequest.maxGasPrice`. */
|
|
60
|
+
readonly maxGasPrice: bigint;
|
|
61
|
+
readonly premiumPercent: bigint | number;
|
|
62
|
+
}) => bigint;
|
|
63
|
+
/**
|
|
64
|
+
* What a fulfillment is owed for the gas it took, mirroring the router's settlement: that gas at
|
|
65
|
+
* the price the request locked, plus the premium, and never more than the request reserved. The
|
|
66
|
+
* submitting transaction's gas price does not change it (ADR 0019). The premium decays in a
|
|
67
|
+
* straight line with the time since the assignment (ADR 0029): whole when `settledAt`, the
|
|
68
|
+
* router's `block.timestamp`, is `assignedAt`, and nothing once the request is late (ADR 0025),
|
|
69
|
+
* so the same timing decides the quote here and on the router:
|
|
70
|
+
* `gasUsed × lockedGasPrice × (100 × D + premiumPercent × remaining) / (100 × D)`, with `D` the
|
|
71
|
+
* stale delay and `remaining` the seconds left of it (`remainingDelay`). Everything is multiplied
|
|
72
|
+
* before the one division, as on the router, so both round down to the same wei. The rest of the
|
|
73
|
+
* reservation goes back to the consumer.
|
|
74
|
+
*/
|
|
75
|
+
export declare const settlement: ({ gasUsed, requestGasPrice, premiumPercent, fee: reserved, assignedAt, settledAt }: {
|
|
76
|
+
readonly gasUsed: bigint | number;
|
|
77
|
+
readonly requestGasPrice: bigint;
|
|
78
|
+
readonly premiumPercent: bigint | number;
|
|
79
|
+
readonly fee: bigint;
|
|
80
|
+
readonly assignedAt: bigint | number;
|
|
81
|
+
readonly settledAt: bigint | number;
|
|
82
|
+
}) => bigint;
|
|
83
|
+
/**
|
|
84
|
+
* The share of the premium a settlement pays (ADR 0029), exact: `remaining` seconds of the stale
|
|
85
|
+
* delay's `delay`. A fraction and not a percentage, so a charge is reproduced from it to the wei.
|
|
86
|
+
*/
|
|
87
|
+
export type PremiumShare = {
|
|
88
|
+
readonly remaining: bigint;
|
|
89
|
+
readonly delay: bigint;
|
|
90
|
+
};
|
|
91
|
+
/** The whole premium: what the assignment's block pays, and a direct request whenever it lands. */
|
|
92
|
+
export declare const WHOLE_PREMIUM: PremiumShare;
|
|
93
|
+
/**
|
|
94
|
+
* The share of the premium a fulfillment settled at `settledAt`, the router's `block.timestamp`,
|
|
95
|
+
* was paid for a request assigned at `assignedAt`. `RequestSettled` does not carry it, so a reader
|
|
96
|
+
* of a settlement works it out from the two times, by the same `remainingDelay` the charge uses.
|
|
97
|
+
*/
|
|
98
|
+
export declare const premiumShare: ({ assignedAt, settledAt }: {
|
|
99
|
+
readonly assignedAt: bigint | number;
|
|
100
|
+
readonly settledAt: bigint | number;
|
|
101
|
+
}) => PremiumShare;
|
|
102
|
+
/**
|
|
103
|
+
* `settlement` at a share of the premium already worked out, as the router's own takes the
|
|
104
|
+
* seconds left: `gasUsed × lockedGasPrice × (100 × delay + premiumPercent × remaining) / (100 × delay)`,
|
|
105
|
+
* capped by the reservation.
|
|
106
|
+
*/
|
|
107
|
+
export declare const settlementAtShare: ({ gasUsed, requestGasPrice, premiumPercent, fee: reserved, share: { remaining, delay } }: {
|
|
108
|
+
readonly gasUsed: bigint | number;
|
|
109
|
+
readonly requestGasPrice: bigint;
|
|
110
|
+
readonly premiumPercent: bigint | number;
|
|
111
|
+
readonly fee: bigint;
|
|
112
|
+
readonly share: PremiumShare;
|
|
113
|
+
}) => bigint;
|
|
114
|
+
/**
|
|
115
|
+
* The gas a charge was computed from, which `RequestSettled` does not carry: the charge divided
|
|
116
|
+
* back by the locked price and the premium's share, rounded up, since the charge was rounded down
|
|
117
|
+
* by less than one gas's worth. `settlementAtShare` on it reproduces the charge to the wei. A
|
|
118
|
+
* charge the reservation capped says only that the gas was at least this; a gas price of nothing
|
|
119
|
+
* says nothing of the gas.
|
|
120
|
+
*/
|
|
121
|
+
export declare const chargedGas: ({ charged, requestGasPrice, premiumPercent, share: { remaining, delay } }: {
|
|
122
|
+
readonly charged: bigint;
|
|
123
|
+
readonly requestGasPrice: bigint;
|
|
124
|
+
readonly premiumPercent: bigint | number;
|
|
125
|
+
readonly share: PremiumShare;
|
|
126
|
+
}) => bigint;
|
|
127
|
+
/** Transaction intrinsic gas. */
|
|
128
|
+
export declare const INTRINSIC_GAS = 21000n;
|
|
129
|
+
/**
|
|
130
|
+
* The gas one fulfillment adds to a transaction, given the calldata that carries it, every byte
|
|
131
|
+
* at EIP-7623's non-zero floor (`CALLDATA_GAS_PER_BYTE`), below which the chain refuses a
|
|
132
|
+
* transaction whose execution is small beside its calldata (ADR 0023). The router
|
|
133
|
+
* reverts `InsufficientFulfillmentGas` unless `gasleft()` at the callback covers the callback gas
|
|
134
|
+
* limit scaled by 64/63 (EIP-150 keeps a 64th back from a call) plus what it needs afterwards, so
|
|
135
|
+
* the item needs that requirement plus everything spent before the callback. A batch's limit is
|
|
136
|
+
* the intrinsic gas plus every item's share.
|
|
137
|
+
*/
|
|
138
|
+
export declare const fulfillmentItemGas: ({ callbackGasLimit, data }: {
|
|
139
|
+
readonly callbackGasLimit: number;
|
|
140
|
+
readonly data: Hex;
|
|
141
|
+
}) => bigint;
|
|
142
|
+
//#endregion
|
package/dist/fee.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { remainingDelay } from "./request.js";
|
|
2
|
+
import { parseGwei, size } from "viem";
|
|
3
|
+
//#region src/fee.ts
|
|
4
|
+
/** The fees a node's sender never goes below unless configured otherwise; tuned for Base. */
|
|
5
|
+
const DEFAULT_FEE_FLOOR = {
|
|
6
|
+
maxFeePerGas: parseGwei("0.005"),
|
|
7
|
+
maxPriorityFeePerGas: parseGwei("0.001")
|
|
8
|
+
};
|
|
9
|
+
/** Headroom over the base fee so a send stays mineable while the base fee climbs between refreshes. */
|
|
10
|
+
const BASE_FEE_MULTIPLIER = 2n;
|
|
11
|
+
/**
|
|
12
|
+
* The fees a node's sender bids given the latest base fee: twice the base fee plus the tip, never
|
|
13
|
+
* under the floor. Here because a signer mirrors it: the enclave refuses an authorization whose
|
|
14
|
+
* maximum gas price is under this bid (ADR 0028), so a client sizes its maximum from it.
|
|
15
|
+
*/
|
|
16
|
+
const computeFees = (baseFeePerGas, floor = DEFAULT_FEE_FLOOR) => {
|
|
17
|
+
const headroom = baseFeePerGas * BASE_FEE_MULTIPLIER + floor.maxPriorityFeePerGas;
|
|
18
|
+
return {
|
|
19
|
+
maxFeePerGas: headroom > floor.maxFeePerGas ? headroom : floor.maxFeePerGas,
|
|
20
|
+
maxPriorityFeePerGas: floor.maxPriorityFeePerGas
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* `Config.CALLDATA_GAS_PER_BYTE`: EIP-7623's calldata floor for a non-zero byte, charged for every
|
|
25
|
+
* echoed byte (ADR 0023).
|
|
26
|
+
*/
|
|
27
|
+
const CALLDATA_GAS_PER_BYTE = 40n;
|
|
28
|
+
/**
|
|
29
|
+
* The gas price a request locks, mirroring the router's: the request transaction's gas price, never
|
|
30
|
+
* below the base fee of the block it lands in (ADR 0019). An OP-stack L1→L2 deposit transaction
|
|
31
|
+
* runs at a zero gas price; priced at that, its request would reserve nothing and its fulfillment
|
|
32
|
+
* charge nothing.
|
|
33
|
+
*/
|
|
34
|
+
const lockedGasPrice = ({ gasPrice, baseFeePerGas }) => gasPrice > baseFeePerGas ? gasPrice : baseFeePerGas;
|
|
35
|
+
/**
|
|
36
|
+
* The fee a request locks at request time (ADR 0013, 0019, 0023):
|
|
37
|
+
* `(callbackGasLimit + fulfillmentOverheadGas + 40 × callbackDataLength) × lockedGasPrice × (100% + premium)`,
|
|
38
|
+
* rounded down to the wei, where the locked gas price is `gasPrice` floored at `baseFeePerGas`
|
|
39
|
+
* (`lockedGasPrice`). Mirrors the router's fee, so the router must multiply before it divides by
|
|
40
|
+
* 100 too. Gas amounts and the premium are accepted as `number` so a decoded request can be priced
|
|
41
|
+
* without conversion.
|
|
42
|
+
*/
|
|
43
|
+
const fee = ({ callbackGasLimit, fulfillmentOverheadGas, callbackDataLength, gasPrice, baseFeePerGas, premiumPercent }) => (BigInt(callbackGasLimit) + BigInt(fulfillmentOverheadGas) + CALLDATA_GAS_PER_BYTE * BigInt(callbackDataLength)) * lockedGasPrice({
|
|
44
|
+
gasPrice,
|
|
45
|
+
baseFeePerGas
|
|
46
|
+
}) * (100n + BigInt(premiumPercent)) / 100n;
|
|
47
|
+
/**
|
|
48
|
+
* The most a direct request can ever charge (ADR 0028): the reservation formula at the maximum
|
|
49
|
+
* gas price the authorization names, with the same overhead and premium as an on-chain request.
|
|
50
|
+
* Mirrors the router's ceiling, which debits it from the signer's balance before the callback and
|
|
51
|
+
* credits back what the settlement does not take.
|
|
52
|
+
*/
|
|
53
|
+
const ceiling = ({ callbackGasLimit, fulfillmentOverheadGas, callbackDataLength, maxGasPrice, premiumPercent }) => fee({
|
|
54
|
+
callbackGasLimit,
|
|
55
|
+
fulfillmentOverheadGas,
|
|
56
|
+
callbackDataLength,
|
|
57
|
+
gasPrice: maxGasPrice,
|
|
58
|
+
baseFeePerGas: 0n,
|
|
59
|
+
premiumPercent
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* What a fulfillment is owed for the gas it took, mirroring the router's settlement: that gas at
|
|
63
|
+
* the price the request locked, plus the premium, and never more than the request reserved. The
|
|
64
|
+
* submitting transaction's gas price does not change it (ADR 0019). The premium decays in a
|
|
65
|
+
* straight line with the time since the assignment (ADR 0029): whole when `settledAt`, the
|
|
66
|
+
* router's `block.timestamp`, is `assignedAt`, and nothing once the request is late (ADR 0025),
|
|
67
|
+
* so the same timing decides the quote here and on the router:
|
|
68
|
+
* `gasUsed × lockedGasPrice × (100 × D + premiumPercent × remaining) / (100 × D)`, with `D` the
|
|
69
|
+
* stale delay and `remaining` the seconds left of it (`remainingDelay`). Everything is multiplied
|
|
70
|
+
* before the one division, as on the router, so both round down to the same wei. The rest of the
|
|
71
|
+
* reservation goes back to the consumer.
|
|
72
|
+
*/
|
|
73
|
+
const settlement = ({ gasUsed, requestGasPrice, premiumPercent, fee: reserved, assignedAt, settledAt }) => settlementAtShare({
|
|
74
|
+
gasUsed,
|
|
75
|
+
requestGasPrice,
|
|
76
|
+
premiumPercent,
|
|
77
|
+
fee: reserved,
|
|
78
|
+
share: premiumShare({
|
|
79
|
+
assignedAt,
|
|
80
|
+
settledAt
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
/** The whole premium: what the assignment's block pays, and a direct request whenever it lands. */
|
|
84
|
+
const WHOLE_PREMIUM = {
|
|
85
|
+
remaining: BigInt(30),
|
|
86
|
+
delay: BigInt(30)
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The share of the premium a fulfillment settled at `settledAt`, the router's `block.timestamp`,
|
|
90
|
+
* was paid for a request assigned at `assignedAt`. `RequestSettled` does not carry it, so a reader
|
|
91
|
+
* of a settlement works it out from the two times, by the same `remainingDelay` the charge uses.
|
|
92
|
+
*/
|
|
93
|
+
const premiumShare = ({ assignedAt, settledAt }) => ({
|
|
94
|
+
remaining: remainingDelay({
|
|
95
|
+
assignedAt,
|
|
96
|
+
at: settledAt
|
|
97
|
+
}),
|
|
98
|
+
delay: BigInt(30)
|
|
99
|
+
});
|
|
100
|
+
/**
|
|
101
|
+
* `settlement` at a share of the premium already worked out, as the router's own takes the
|
|
102
|
+
* seconds left: `gasUsed × lockedGasPrice × (100 × delay + premiumPercent × remaining) / (100 × delay)`,
|
|
103
|
+
* capped by the reservation.
|
|
104
|
+
*/
|
|
105
|
+
const settlementAtShare = ({ gasUsed, requestGasPrice, premiumPercent, fee: reserved, share: { remaining, delay } }) => {
|
|
106
|
+
const amount = BigInt(gasUsed) * requestGasPrice * (100n * delay + BigInt(premiumPercent) * remaining) / (100n * delay);
|
|
107
|
+
return amount > reserved ? reserved : amount;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* The gas a charge was computed from, which `RequestSettled` does not carry: the charge divided
|
|
111
|
+
* back by the locked price and the premium's share, rounded up, since the charge was rounded down
|
|
112
|
+
* by less than one gas's worth. `settlementAtShare` on it reproduces the charge to the wei. A
|
|
113
|
+
* charge the reservation capped says only that the gas was at least this; a gas price of nothing
|
|
114
|
+
* says nothing of the gas.
|
|
115
|
+
*/
|
|
116
|
+
const chargedGas = ({ charged, requestGasPrice, premiumPercent, share: { remaining, delay } }) => {
|
|
117
|
+
const perGas = requestGasPrice * (100n * delay + BigInt(premiumPercent) * remaining);
|
|
118
|
+
return perGas === 0n ? 0n : (charged * 100n * delay + perGas - 1n) / perGas;
|
|
119
|
+
};
|
|
120
|
+
/** Transaction intrinsic gas. */
|
|
121
|
+
const INTRINSIC_GAS = 21000n;
|
|
122
|
+
/**
|
|
123
|
+
* What the router spends around the callback: the diamond dispatch, recomputing the request
|
|
124
|
+
* id, recovering the enclave signature, closing the request, and crediting the operator before
|
|
125
|
+
* it, the event after it. Measured under 60k besides the callback (`GasBudget.test.ts`); the
|
|
126
|
+
* margin covers cold storage slots, and in a batch the array encoding around each item.
|
|
127
|
+
*/
|
|
128
|
+
const FULFILLMENT_OVERHEAD_GAS = 150000n;
|
|
129
|
+
/** `Config.FULFILLMENT_POST_CALLBACK_GAS`: what the router keeps back for after the callback. */
|
|
130
|
+
const FULFILLMENT_POST_CALLBACK_GAS = 80000n;
|
|
131
|
+
/**
|
|
132
|
+
* The gas one fulfillment adds to a transaction, given the calldata that carries it, every byte
|
|
133
|
+
* at EIP-7623's non-zero floor (`CALLDATA_GAS_PER_BYTE`), below which the chain refuses a
|
|
134
|
+
* transaction whose execution is small beside its calldata (ADR 0023). The router
|
|
135
|
+
* reverts `InsufficientFulfillmentGas` unless `gasleft()` at the callback covers the callback gas
|
|
136
|
+
* limit scaled by 64/63 (EIP-150 keeps a 64th back from a call) plus what it needs afterwards, so
|
|
137
|
+
* the item needs that requirement plus everything spent before the callback. A batch's limit is
|
|
138
|
+
* the intrinsic gas plus every item's share.
|
|
139
|
+
*/
|
|
140
|
+
const fulfillmentItemGas = ({ callbackGasLimit, data }) => CALLDATA_GAS_PER_BYTE * BigInt(size(data)) + FULFILLMENT_OVERHEAD_GAS + BigInt(callbackGasLimit) * 64n / 63n + FULFILLMENT_POST_CALLBACK_GAS;
|
|
141
|
+
//#endregion
|
|
142
|
+
export { CALLDATA_GAS_PER_BYTE, DEFAULT_FEE_FLOOR, INTRINSIC_GAS, WHOLE_PREMIUM, ceiling, chargedGas, computeFees, fee, fulfillmentItemGas, lockedGasPrice, premiumShare, settlement, settlementAtShare };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { t as RouterDomain } from "./domain-CXJsoNRU.js";
|
|
2
|
+
import { Hex } from "viem";
|
|
3
|
+
//#region src/fulfillment.d.ts
|
|
4
|
+
/** The typed data an enclave signs to deliver a fulfillment, as viem's `signTypedData` takes it. */
|
|
5
|
+
export declare const fulfillmentTypedData: ({ chainId, router, requestId, proofCommitment }: RouterDomain & {
|
|
6
|
+
readonly requestId: Hex;
|
|
7
|
+
readonly proofCommitment: Hex;
|
|
8
|
+
}) => {
|
|
9
|
+
readonly domain: {
|
|
10
|
+
readonly name: "VerifyNetworkVRF";
|
|
11
|
+
readonly version: "2";
|
|
12
|
+
readonly chainId: number | bigint;
|
|
13
|
+
readonly verifyingContract: `0x${string}`;
|
|
14
|
+
};
|
|
15
|
+
readonly types: {
|
|
16
|
+
readonly Fulfillment: readonly [{
|
|
17
|
+
readonly name: "requestId";
|
|
18
|
+
readonly type: "bytes32";
|
|
19
|
+
}, {
|
|
20
|
+
readonly name: "proofCommitment";
|
|
21
|
+
readonly type: "bytes32";
|
|
22
|
+
}];
|
|
23
|
+
};
|
|
24
|
+
readonly primaryType: "Fulfillment";
|
|
25
|
+
readonly message: {
|
|
26
|
+
readonly requestId: `0x${string}`;
|
|
27
|
+
readonly proofCommitment: `0x${string}`;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
/** Mirrors `Signatures.fulfillmentDigest` in the router: the hash the enclave signature is recovered against. */
|
|
31
|
+
export declare const fulfillmentDigest: (fulfillment: Parameters<typeof fulfillmentTypedData>[0]) => Hex;
|
|
32
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { hashTypedData } from "viem";
|
|
2
|
+
//#region src/fulfillment.ts
|
|
3
|
+
const fulfillmentTypes = { Fulfillment: [{
|
|
4
|
+
name: "requestId",
|
|
5
|
+
type: "bytes32"
|
|
6
|
+
}, {
|
|
7
|
+
name: "proofCommitment",
|
|
8
|
+
type: "bytes32"
|
|
9
|
+
}] };
|
|
10
|
+
/** The typed data an enclave signs to deliver a fulfillment, as viem's `signTypedData` takes it. */
|
|
11
|
+
const fulfillmentTypedData = ({ chainId, router, requestId, proofCommitment }) => ({
|
|
12
|
+
domain: {
|
|
13
|
+
name: "VerifyNetworkVRF",
|
|
14
|
+
version: "2",
|
|
15
|
+
chainId,
|
|
16
|
+
verifyingContract: router
|
|
17
|
+
},
|
|
18
|
+
types: fulfillmentTypes,
|
|
19
|
+
primaryType: "Fulfillment",
|
|
20
|
+
message: {
|
|
21
|
+
requestId,
|
|
22
|
+
proofCommitment
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
/** Mirrors `Signatures.fulfillmentDigest` in the router: the hash the enclave signature is recovered against. */
|
|
26
|
+
const fulfillmentDigest = (fulfillment) => hashTypedData(fulfillmentTypedData(fulfillment));
|
|
27
|
+
//#endregion
|
|
28
|
+
export { fulfillmentDigest, fulfillmentTypedData };
|