@sig-net/midnight 0.20.0-rc.1 → 0.21.0-rc.2
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 +17 -325
- package/dist/compact-descriptors.d.ts +10 -0
- package/dist/compact-descriptors.d.ts.map +1 -1
- package/dist/compact-descriptors.js +27 -4
- package/dist/compact-descriptors.js.map +1 -1
- package/dist/ecdsa-attestation.d.ts +23 -7
- package/dist/ecdsa-attestation.d.ts.map +1 -1
- package/dist/ecdsa-attestation.js +50 -8
- package/dist/ecdsa-attestation.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/managed/compiler/contract-manifest.json +4 -4
- package/dist/managed/contract/index.js +86 -185
- package/dist/managed/contract/index.js.map +1 -1
- package/dist/signet-contract-events.d.ts +12 -3
- package/dist/signet-contract-events.d.ts.map +1 -1
- package/dist/signet-contract-events.js +11 -4
- package/dist/signet-contract-events.js.map +1 -1
- package/dist/signet-request-id.d.ts +2 -4
- package/dist/signet-request-id.d.ts.map +1 -1
- package/dist/signet-request-id.js +4 -6
- package/dist/signet-request-id.js.map +1 -1
- package/dist/signet-requests.d.ts +2 -2
- package/dist/signet-requests.d.ts.map +1 -1
- package/dist/signet-requests.js +7 -8
- package/dist/signet-requests.js.map +1 -1
- package/package.json +2 -2
- package/src/Signet.compact +66 -45
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The [Sig Network](https://sig.network) [Distributed MPC](https://github.com/sig-net/mpc) integration for the [Midnight blockchain](https://midnight.network) lets contracts on Midnight execute arbitrary transactions on foreign blockchains, and respond to the results of those transactions.
|
|
4
4
|
|
|
5
|
-
`@sig-net/midnight` is the client-agnostic protocol library for that integration. It carries everything a Midnight contract or off-chain client needs to speak the signet protocol (the MPC's [sign bidirectional flow](#sign-bidirectional-flow)). It does not bind to any particular contract.
|
|
5
|
+
`@sig-net/midnight` is the client-agnostic protocol library for that integration. It carries everything a Midnight contract or off-chain client needs to speak the signet protocol (the MPC's [sign bidirectional flow](https://github.com/sig-net/midnight-integration/blob/main/README.md#sign-bidirectional-flow)). It does not bind to any particular contract.
|
|
6
6
|
|
|
7
7
|
> ## 🚧 Under Construction 🚧
|
|
8
8
|
>
|
|
@@ -10,6 +10,7 @@ The [Sig Network](https://sig.network) [Distributed MPC](https://github.com/sig-
|
|
|
10
10
|
> Use at your own risk and expect rapid iteration.
|
|
11
11
|
|
|
12
12
|
## Package Contents
|
|
13
|
+
|
|
13
14
|
This package has 2 components:
|
|
14
15
|
|
|
15
16
|
- **Compact module** for contract code on chain: `.compact` sources for Compact contracts to import the protocol structs and circuits directly:
|
|
@@ -18,7 +19,7 @@ This package has 2 components:
|
|
|
18
19
|
import "@sig-net/midnight/src/Signet";
|
|
19
20
|
```
|
|
20
21
|
|
|
21
|
-
- **TypeScript library** for clients off chain: readers that poll the signet contract and verify the MPC's responses, key derivation and attestation crypto, output serialisation, the published per-network addresses and
|
|
22
|
+
- **TypeScript library** for clients off chain: readers that poll the signet contract and verify the MPC's responses, key derivation and attestation crypto, output serialisation, the published per-network addresses and constant values, and typed twins of the on-chain structs and circuits.
|
|
22
23
|
|
|
23
24
|
The [Export highlights](#export-highlights) section lists the specific exports each task uses.
|
|
24
25
|
|
|
@@ -28,325 +29,20 @@ The [Export highlights](#export-highlights) section lists the specific exports e
|
|
|
28
29
|
npm install @sig-net/midnight
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
##
|
|
32
|
-
|
|
33
|
-
The flow has 5 steps:
|
|
34
|
-
|
|
35
|
-
1. Client calls a contract on Midnight. The contract requests a signature for a transaction destined for a foreign chain. The signature is made with a key derived for the requesting contract (see [Derived keys](#derived-keys)).
|
|
36
|
-
2. The Sig Network MPC serves the request: it generates the transaction signature and posts it back to Midnight to the Sig Network Singleton Contract.
|
|
37
|
-
3. The client extracts the signature (from the Sig Network Singleton) and uses it to submit the signed transaction to the foreign chain.
|
|
38
|
-
4. The MPC observes the foreign transaction and posts an attestation of the execution back to Midnight to the Sig Network Singleton Contract. The attestation is an ECDSA signature over the digest `keccak256(requestId || serializedOutput)` created using the requesting contract's MPC response key (see [Derived keys](#derived-keys)). Both the digest and the output itself travel off chain.
|
|
39
|
-
5. The client obtains the execution output off chain (it broadcast the transaction in step 3, so it can read the result, see the output recovery note below for more details). It extracts the posted attestation and submits both back to the calling Midnight contract (same contract as step 1). The contract recomputes the digest from the output bytes and verifies the MPC's signature in-circuit against its own response key (see [Derived keys](#derived-keys)). The contract can then respond to the foreign execution output. This completes the foreign transaction execution.
|
|
40
|
-
|
|
41
|
-
> **Output recovery:** how the client reads the execution output is chain-specific. For EVM chains it is the mined call's return data. Extract it with `debug_traceTransaction` (callTracer, top call frame), the same RPC method the MPC observes executions with. Clients without trace access can fetch the raw output from the fakenet responder's helper API at `GET /responses/{requestId}` (served by [`ResponsesApi.ts`](https://github.com/sig-net/solana-signet-program/blob/fakenet-v0.8.0/fakenet-signer/src/server/ResponsesApi.ts), port 3040 in the local stack). The fetched bytes stay untrusted until step 5's in-circuit signature verification.
|
|
42
|
-
|
|
43
|
-
## Derived keys
|
|
44
|
-
|
|
45
|
-
Every key the MPC uses is derived for the requesting contract and a path. There are two kinds. The request signing key: derived from a path chosen by the requesting contract. The response signing key: derived from a path fixed by the protocol. Both key derivations are **scoped by the address** of the requesting contract ensuring that only a requesting contract has access to its own keys.
|
|
46
|
-
|
|
47
|
-
### Request signing key
|
|
48
|
-
|
|
49
|
-
The key the MPC uses to sign requested foreign transactions:
|
|
50
|
-
|
|
51
|
-
`requestSigningKey = f(mpcRootKey[keyVersion], caip2ChainId, contractAddress, hex::encode(path))`
|
|
52
|
-
|
|
53
|
-
The path is 32 opaque bytes of the contract's choosing (for example a fixed literal for a contract-owned account like "vault", or a hash of a caller's secret for per-user accounts). There are no format requirements: any 32 bytes are valid. **CRITICAL:** the MPC renders the path as `hex::encode(path)` before it derives the key: lowercase hex of the full 32 bytes, no trimming, no `0x` prefix. The contract address is always part of the derivation, so no contract can reach another contract's derived keys.
|
|
54
|
-
|
|
55
|
-
### Response key
|
|
56
|
-
|
|
57
|
-
The key the MPC uses to sign remote execution attestations when it posts them back to Midnight:
|
|
58
|
-
|
|
59
|
-
`responseKey = f(mpcRootKey[keyVersion], caip2ChainId, contractAddress, "midnight response key")`
|
|
60
|
-
|
|
61
|
-
This is the same derivation, but with the path fixed to the literal `"midnight response key"`. This fixed path is a protocol string that enters the derivation verbatim (no hex rendering, unlike a request's 32 path bytes). Each contract therefore has one well-known response key. A contract pins its own response key in its ledger after deploy, and verifies every response against it in-circuit (step 5 of the flow above).
|
|
62
|
-
|
|
63
|
-
> **keyVersion** is the version of the MPC root key that the derivation starts from. Current deployments use version `1`.
|
|
64
|
-
>
|
|
65
|
-
> **caip2ChainId** is the id of the chain the request originates from, in [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) form. For signature requests made on Midnight it is the Midnight variant (currently `midnight:testnet`). It is not the target chain id carried in the request record's `caip2Id` field.
|
|
66
|
-
|
|
67
|
-
## Integrator guide
|
|
68
|
-
|
|
69
|
-
A signet-compliant client contract does four things:
|
|
70
|
-
|
|
71
|
-
- it stores its requests in a public `SignBidirectionalEventMap` in its own ledger
|
|
72
|
-
- it pins its counterparties: the Signet singleton contract and its own MPC response key
|
|
73
|
-
- it submits signature requests
|
|
74
|
-
- it verifies execution responses in-circuit
|
|
75
|
-
|
|
76
|
-
The integration consists of:
|
|
77
|
-
|
|
78
|
-
- 3 once-off **setup** steps
|
|
79
|
-
- 5 per-request **runtime** steps that drive the full sign bidirectional flow
|
|
80
|
-
|
|
81
|
-
### Setup
|
|
82
|
-
|
|
83
|
-
Set up your contract for integration with the Sig Network MPC's sign bidirectional flow:
|
|
84
|
-
|
|
85
|
-
1. Import the Signet module at the top of your contract (resolved through `node_modules` via `COMPACT_PATH`):
|
|
86
|
-
|
|
87
|
-
```compact
|
|
88
|
-
import "@sig-net/midnight/src/Signet";
|
|
89
|
-
```
|
|
32
|
+
## Documentation
|
|
90
33
|
|
|
91
|
-
|
|
34
|
+
The protocol and integration documentation lives in the [sig-net/midnight-integration README](https://github.com/sig-net/midnight-integration/blob/main/README.md):
|
|
92
35
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
36
|
+
- [Sign Bidirectional Flow](https://github.com/sig-net/midnight-integration/blob/main/README.md#sign-bidirectional-flow): the 5-step protocol this package speaks, with diagram, failure handling and output recovery.
|
|
37
|
+
- [Derived keys](https://github.com/sig-net/midnight-integration/blob/main/README.md#derived-keys): the request signing key and the response key, and how the MPC derives them.
|
|
38
|
+
- [Integrator Guide](https://github.com/sig-net/midnight-integration/blob/main/README.md#integrator-guide): the once-off setup and the per-request runtime steps, built on this package's exports.
|
|
39
|
+
- [EVM Type 2 transactions and ABI calldata words](https://github.com/sig-net/midnight-integration/blob/main/README.md#evm-type-2-transactions-and-abi-calldata-words): building calldata words in-circuit and deserialising respond payloads.
|
|
96
40
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
2. Declare the required Sig Network protocol state in your ledger, plus the recommended deployer identity and initialisation state. The event map can sit at ANY ledger field. Each notification that your contract emits declares the stored request's id and carries the map's resolved ledger-tree path (see [The request map's ledger-tree path](#the-request-maps-ledger-tree-path)), and the MPC looks the authenticated request up there by that id.
|
|
100
|
-
|
|
101
|
-
```compact
|
|
102
|
-
// Required: Map of SignBidirectionalEvent signature requests, configured by transaction type.
|
|
103
|
-
// Configured and sized here for an EVM Type 2 transaction with
|
|
104
|
-
// <1 calldata word, 0 access-list entries, 0 storage keys> and
|
|
105
|
-
// 34-byte serialisation schemas.
|
|
106
|
-
export ledger signBidirectionalEventMap: SignBidirectionalEventMap<EvmType2TxParams<1, 0, 0>, 34, 34>;
|
|
107
|
-
|
|
108
|
-
// Required: The Signet singleton signer interface, set at deploy.
|
|
109
|
-
// Used to notify the MPC of events you add to your signBidirectionalEventMap.
|
|
110
|
-
sealed ledger signetSigner: SignetSigner;
|
|
111
|
-
|
|
112
|
-
// Required: This contract's MPC response key, set in step 3.
|
|
113
|
-
// Used to verify RespondBidirectionalEvents attesting the serialised output of foreign chain execution.
|
|
114
|
-
export ledger mpcResponseKey: Secp256k1Point;
|
|
115
|
-
|
|
116
|
-
// Recommended: contract-local source of request nonces, so identical
|
|
117
|
-
// requests hash to distinct request ids. Nothing off-chain reads it.
|
|
118
|
-
export ledger signetRequestNonce: Counter;
|
|
119
|
-
|
|
120
|
-
// Recommended: used in step 3 to ensure initialisation runs only once.
|
|
121
|
-
export ledger initialised: Counter;
|
|
122
|
-
|
|
123
|
-
// Recommended: set on deploy, used in step 3 to ensure only the deployer may set the mpcResponseKey.
|
|
124
|
-
sealed ledger deployer: Bytes<32>;
|
|
125
|
-
|
|
126
|
-
// Recommended: supplies the deployer's identity secret from private state
|
|
127
|
-
// off-chain. Only its commitment (below) ever reaches the ledger.
|
|
128
|
-
witness witnessDeployerSecretKey(): Bytes<32>;
|
|
129
|
-
|
|
130
|
-
// Recommended: the deployer identity commitment scheme. Exported so deploy
|
|
131
|
-
// tooling can compute the constructor argument by calling the compiled circuit.
|
|
132
|
-
export pure circuit calculateDeployerCommitment(sk: Bytes<32>): Bytes<32> {
|
|
133
|
-
return persistentHash<Vector<2, Bytes<32>>>([pad(32, "my-contract:deployer:"), sk]);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Required: set signet contract and (recommended) deployer commitment on deployment.
|
|
137
|
-
constructor(signetContract: SignetSigner, deployerCommitment: Bytes<32>) {
|
|
138
|
-
signetSigner = disclose(signetContract);
|
|
139
|
-
deployer = disclose(deployerCommitment);
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
3. Set the contract's MPC response key once, right after deploy. Deriving this key requires the address of the contract, which only exists after deploy (see [Response key](#response-key)):
|
|
144
|
-
|
|
145
|
-
```compact
|
|
146
|
-
export circuit initialise(responseKey: Secp256k1Point): [] {
|
|
147
|
-
// Recommended: confirm that only the deployer may initialise, and only once:
|
|
148
|
-
assert(deployer == calculateDeployerCommitment(witnessDeployerSecretKey()), "Not the deployer");
|
|
149
|
-
assert(initialised == 0, "Already initialised");
|
|
150
|
-
initialised.increment(1);
|
|
151
|
-
|
|
152
|
-
// Required: set MPC response key for verification of RespondBidirectionalEvents
|
|
153
|
-
mpcResponseKey = disclose(responseKey);
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### The request map's ledger-tree path
|
|
158
|
-
|
|
159
|
-
Each notification must tell the MPC where your `signBidirectionalEventMap` sits in your contract's compiled on-chain state. The MPC uses this location to read the authenticated request out of raw contract state. The location is a path in the state tree, passed to `constructSignBidirectionalEventNotificationV1` as two arguments:
|
|
160
|
-
|
|
161
|
-
- `requestsPathDepth`: the number of meaningful entries in the path (1 to 4).
|
|
162
|
-
- `requestsPath`: the path itself, zero padded to 4 entries.
|
|
163
|
-
|
|
164
|
-
The path shape comes from how compactc lays out state. The compiler packs a contract's public ledger fields into a tree whose array nodes hold at most 15 entries. With 15 or fewer fields, field N sits directly in the root array, at path `[N]` (depth 1). With more than 15 fields, the compiler groups the fields into segments of at most 15 (the remainder segment first), and the root array holds the segments. Each grouping adds one level to the tree and one entry to every field's path. A 20-field contract splits 5 + 15: field 4 sits at `[0, 4]` and field 19 sits at `[1, 14]` (depth 2).
|
|
165
|
-
|
|
166
|
-
**Do not derive the path by hand**. The compiler records it in your compiled artefacts. Compile your contract, then look up your request map's `"path"` in its generated accessor in `managed/<contract>/contract/index.js`. Its accessor shows the indices that the Signet Protocol needs: for example `state.asArray()[1].asArray()[14]` for a map recorded at `[1, 14]`. That path packs as `requestsPathDepth = 2` and `requestsPath = [1, 14, 0, 0]`.
|
|
167
|
-
|
|
168
|
-
The two caller contracts in the [sig-net/midnight-integration](https://github.com/sig-net/midnight-integration) repository are worked examples of each case:
|
|
169
|
-
|
|
170
|
-
- [`test-caller-contract`](https://github.com/sig-net/midnight-integration/tree/main/packages/test-caller-contract): the flat case. Its 8-field ledger stores the map at field 4, so notifications carry depth `1` and path `[4, 0, 0, 0]`.
|
|
171
|
-
- [`test-caller-contract-20-field`](https://github.com/sig-net/midnight-integration/tree/main/packages/test-caller-contract-20-field): the chunked case. Its 20 fields split 5 + 15, so the map at field 19 packs as depth `2` and path `[1, 14, 0, 0]`.
|
|
172
|
-
|
|
173
|
-
### Runtime
|
|
174
|
-
|
|
175
|
-
Each interaction with your contract that executes a transaction on a foreign chain runs these 5 steps.
|
|
176
|
-
|
|
177
|
-
Steps 1 and 5 are circuits on your contract. Steps 2 to 4 are off-chain client code built on the utilities in `@sig-net/midnight`.
|
|
178
|
-
|
|
179
|
-
The off-chain steps share two values. The first is one `SignetRequestResponseReader` over your contract and the Signet singleton. The second is the expected signer of the requested transaction: the key the MPC derives for your contract and the request's path (see [Derived keys](#derived-keys)).
|
|
180
|
-
|
|
181
|
-
```ts
|
|
182
|
-
import { indexerPublicDataProvider } from "@midnight-ntwrk/midnight-js-indexer-public-data-provider";
|
|
183
|
-
import {
|
|
184
|
-
deriveEvmAddress,
|
|
185
|
-
signetEventSourceFromPublicDataProvider,
|
|
186
|
-
SignetRequestResponseReader,
|
|
187
|
-
} from "@sig-net/midnight";
|
|
188
|
-
|
|
189
|
-
// Provider to index Midnight Blockchain
|
|
190
|
-
const publicDataProvider = indexerPublicDataProvider({
|
|
191
|
-
queryURL: indexerUrl,
|
|
192
|
-
subscriptionURL: indexerWsUrl
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// SignetRequestResponseReader to poll for Signed Transactions and Signed RespondBidirectionalEvents
|
|
196
|
-
const reader = new SignetRequestResponseReader({
|
|
197
|
-
// Address of YOUR deployed contract
|
|
198
|
-
requesterContractAddress: myContractAddress,
|
|
199
|
-
|
|
200
|
-
// signBidirectionalEventMap's ledger-tree path (see The request map's ledger-tree path)
|
|
201
|
-
requesterRequestsPath: [0],
|
|
202
|
-
// signBidirectionalEventMap's ledger-tree path (see The request map's ledger-tree path)
|
|
203
|
-
requesterRequestsPath: [0],
|
|
204
|
-
|
|
205
|
-
// Address of the Signet singleton contract
|
|
206
|
-
signetContractAddress,
|
|
207
|
-
|
|
208
|
-
// Raw contract state reads (your contract's request map)
|
|
209
|
-
publicDataProvider,
|
|
210
|
-
|
|
211
|
-
// The MPC's responses are read from the contract events the Signet
|
|
212
|
-
// singleton emits, through the same provider
|
|
213
|
-
eventSource: signetEventSourceFromPublicDataProvider(publicDataProvider),
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const expectedSigner = deriveEvmAddress(mpcRootPublicKey, myContractAddress, "my-path");
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
> **mpcRootPublicKey** is the root public key of the MPC network. On a local stack there is no fixed value: the [integration-test setup](https://github.com/sig-net/midnight-integration/tree/main/packages/integration-tests) generates a fresh `MPC_ROOT_KEY`, prints it during setup and appends it to the repo-root `.env`. For the public networks (stagenet, preview, preprod, mainnet) the fixed values are published in this package via `getMpcRootPublicKey` (placeholders until each network's key is published).
|
|
220
|
-
>
|
|
221
|
-
> **signetContractAddress** is the address of the deployed Signet singleton contract. On a local stack the same setup deploys a fresh singleton, prints the address as `MIDNIGHT_SIGNET_CONTRACT_ADDRESS` and appends it to `.env`. For the public networks the addresses are published in this package via `getSignetContractAddress` (placeholders until each deployment lands).
|
|
222
|
-
|
|
223
|
-
1. Store a signature request and notify the MPC via a cross contract call. Build (or overwrite) every part of the transaction your contract enforces in-circuit, calldata above all (see [EVM Type 2 transactions and ABI calldata words](#evm-type-2-transactions-and-abi-calldata-words)). Never pass caller input through unchecked:
|
|
224
|
-
|
|
225
|
-
```compact
|
|
226
|
-
// Construct SignBidirectionalEvent signature request and calculate its RequestId
|
|
227
|
-
const request = constructSignBidirectionalEvent<EvmType2TxParams<1, 0, 0>, 34, 34>(/* ... */);
|
|
228
|
-
const requestId = disclose(calculateRequestId<EvmType2TxParams<1, 0, 0>, 34, 34>(request));
|
|
229
|
-
|
|
230
|
-
// Store the signature request in your signBidirectionalEventMap for MPC to discover
|
|
231
|
-
signetRequestNonce.increment(1);
|
|
232
|
-
signBidirectionalEventMap.insert(requestId, disclose(request));
|
|
233
|
-
|
|
234
|
-
// Notify the MPC of the SignBidirectionalEvent and the location of your signBidirectionalEventMap.
|
|
235
|
-
// The map is at ledger field 0 (Setup step 2), so its path is [0] at depth 1
|
|
236
|
-
// (see The request map's ledger-tree path).
|
|
237
|
-
// The map is at ledger field 0 (Setup step 2), so its path is [0] at depth 1
|
|
238
|
-
// (see The request map's ledger-tree path).
|
|
239
|
-
signetSigner.signBidirectional(
|
|
240
|
-
requestId,
|
|
241
|
-
constructSignBidirectionalEventNotificationV1(
|
|
242
|
-
kernel.self(),
|
|
243
|
-
1 as Uint<8>, // requestsPathDepth
|
|
244
|
-
[0, 0, 0, 0] as Vector<4, Uint<8>>, // requestsPath, zero padded
|
|
245
|
-
),
|
|
246
|
-
);
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
**NOTE:** Return `requestId` from this circuit call so the client can use it in the next steps. You can also compute it off-chain with the `calculateRequestId` TS twin.
|
|
250
|
-
|
|
251
|
-
2. Poll the Signet singleton for the MPC's signature response. The singleton emits each response as a contract event that carries the request id it answers beside the signature. The id is unauthenticated routing data: it scopes the read to your request's posts and proves nothing. The event log is unauthenticated (anyone can post under any id), so use the verifying getter. It only returns a post whose signature recovers to `expectedSigner` over the signing hash of the requested transaction:
|
|
252
|
-
|
|
253
|
-
```ts
|
|
254
|
-
const { verified } = await reader.getVerifiedSignatureRespondedEvent(requestId, expectedSigner);
|
|
255
|
-
// verified === undefined: no valid response posted yet, poll again.
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
3. Construct the signed transaction and submit it to the foreign chain. The reader rebuilds the transaction from the request record on your ledger and attaches the verified MPC signature:
|
|
259
|
-
|
|
260
|
-
```ts
|
|
261
|
-
import { JsonRpcProvider } from "ethers";
|
|
262
|
-
|
|
263
|
-
const signedTx = await reader.getSignedEvmTransaction(requestId, expectedSigner);
|
|
264
|
-
await new JsonRpcProvider(foreignChainRpcUrl).broadcastTransaction(signedTx.serialized);
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
4. Poll the Signet singleton for the MPC's attestation of the remote execution output. The MPC posts it once it observes the transaction execute on the foreign chain, and the singleton emits it as a contract event that carries the request id beside the MPC's signature. Both the attestation digest and the serialised output travel off chain (you broadcast the transaction in step 3, so you can read its result). The event log is unauthenticated, so use the verifying getter, as in step 2. It reads your request's posts by id, recomputes the digest over the output that you present, and only returns a post whose signature verifies against the response key of your contract.
|
|
268
|
-
|
|
269
|
-
```ts
|
|
270
|
-
const respondBidirectionalEvent = await reader.getVerifiedRespondBidirectionalEvent(
|
|
271
|
-
requestId,
|
|
272
|
-
serializedOutput,
|
|
273
|
-
mpcResponseKey,
|
|
274
|
-
);
|
|
275
|
-
// undefined: no attestation of that output posted yet, poll again.
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
5. Deliver the response and the serialised output to your contract. The contract recomputes the attestation digest, verifies the event in-circuit against the response key pinned in Setup step 3, and consumes the request. The width argument is the exact packed size of your respond serialisation schema (a single bool packs to 1 byte):
|
|
279
|
-
|
|
280
|
-
```compact
|
|
281
|
-
assert(
|
|
282
|
-
verifyRespondBidirectionalEvent<1>(requestId, serializedOutput, respondBidirectionalEvent, mpcResponseKey),
|
|
283
|
-
"Invalid attestation signature"
|
|
284
|
-
);
|
|
285
|
-
signBidirectionalEventMap.remove(requestId);
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## EVM Type 2 transactions and ABI calldata words
|
|
289
|
-
|
|
290
|
-
An `EvmType2TxParams` request decomposes the EVM transaction into typed fields, so your contract can enforce each field in-circuit. Its optional `calldata` is an `EvmCalldata<maxWords>`: the 4-byte function selector plus a list of 32-byte ABI words, per the [Solidity ABI spec](https://docs.soliditylang.org/en/latest/abi-spec.html). Slots past `noWords` are unused capacity and never reach the transaction.
|
|
291
|
-
|
|
292
|
-
Every word must be stored in canonical ABI form (big-endian). The MPC signs a transaction whose calldata is exactly `selector || words[0..noWords]`, byte for byte. A word stored in any other form becomes a signed transaction that calls the foreign contract with garbage arguments. Compact's integer casts are little-endian, so do not hand-roll the byte order. Build every word with the module's helper circuits, and read words back with the matching readers.
|
|
293
|
-
|
|
294
|
-
| Solidity type | Build with | Read back with |
|
|
295
|
-
|---|---|---|
|
|
296
|
-
| `address` | `evmAddressAbiWord(addr: Bytes<20>)` | |
|
|
297
|
-
| unsigned integers up to `uint128` (amounts, ids) | `numericAbiWord(value: Uint<128>)` | `abiWordToUint128(word)` |
|
|
298
|
-
| `bool` | `boolAbiWord(value: Boolean)` | `abiWordToBool(word)` |
|
|
299
|
-
|
|
300
|
-
### Example: an ERC20 transfer
|
|
301
|
-
|
|
302
|
-
`transfer(address,uint256)`, selector `0xa9059cbb`, takes an address word and a numeric word:
|
|
303
|
-
|
|
304
|
-
```compact
|
|
305
|
-
const calldata = EvmCalldata<2> {
|
|
306
|
-
selector: Bytes[0xa9, 0x05, 0x9c, 0xbb],
|
|
307
|
-
noWords: 2 as Uint<16>,
|
|
308
|
-
words: [
|
|
309
|
-
evmAddressAbiWord(recipient), // address argument (Bytes<20>)
|
|
310
|
-
numericAbiWord(amount) // uint256 argument (from a Uint<128>)
|
|
311
|
-
]
|
|
312
|
-
};
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Example: a bool argument, and decoding a bool result
|
|
316
|
-
|
|
317
|
-
`setApprovalForAll(address,bool)`, selector `0xa22cb465`:
|
|
318
|
-
|
|
319
|
-
```compact
|
|
320
|
-
const calldata = EvmCalldata<2> {
|
|
321
|
-
selector: Bytes[0xa2, 0x2c, 0xb4, 0x65],
|
|
322
|
-
noWords: 2 as Uint<16>,
|
|
323
|
-
words: [
|
|
324
|
-
evmAddressAbiWord(operator),
|
|
325
|
-
boolAbiWord(true)
|
|
326
|
-
]
|
|
327
|
-
};
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
The readers run the same rules in the other direction. They reject any non-canonical word outright (no silent truncation or coercion).
|
|
331
|
-
|
|
332
|
-
The builders and readers apply to CALLDATA words only. The serialised output a settle circuit verifies (the explicit `serializedOutput` argument `verifyRespondBidirectionalEvent` recomputes the attestation digest from) is NOT ABI words. It is the packed respond payload produced from the request's respond serialisation schema (a bool packs to 1 byte). The circuit reads it with a single stdlib `deserialize<T, N>` call, where `T` is a struct that mirrors the schema and `N` is the schema's packed size. For an ERC20 `transfer`'s `bool` return under a one-field bool schema:
|
|
333
|
-
|
|
334
|
-
```compact
|
|
335
|
-
struct TransferResult {
|
|
336
|
-
success: Boolean;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const result = deserialize<TransferResult, 1>(serializedOutput);
|
|
340
|
-
assert(result.success, "Remote transfer failed");
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
**Respond schema range trap:** the respond serialisation maps `uint256`, `address` and `field` to Compact `Field`. `Field` values must lie strictly below the BLS12-381 Fr modulus (just under 2^255). An EVM `uint256` at or above Fr cannot be respond-serialised, and `serializeRespondOutput` throws at respond time (a max-uint256 allowance readback is the everyday case). When the full 256-bit range matters, declare the field as `bytes32` in the respond schema instead.
|
|
344
|
-
|
|
345
|
-
The same builders and readers exist as TypeScript twins under identical names, for composing expected words off-chain (UIs, expected-record builders, tests). This package's test suite keeps them in lockstep with the compiled circuits.
|
|
41
|
+
Full integration examples (such as an ERC20 cross chain vault) live in [`sig-net/midnight-examples`](https://github.com/sig-net/midnight-examples).
|
|
346
42
|
|
|
347
43
|
## Export highlights
|
|
348
44
|
|
|
349
|
-
The exports you reach for when integrating, by task.
|
|
45
|
+
The exports you reach for when integrating, by task. The setup and runtime step numbers refer to the [Integrator Guide](https://github.com/sig-net/midnight-integration/blob/main/README.md#integrator-guide).
|
|
350
46
|
|
|
351
47
|
### Compact module
|
|
352
48
|
|
|
@@ -354,10 +50,10 @@ What your contract imports with `import "@sig-net/midnight/src/Signet"`:
|
|
|
354
50
|
|
|
355
51
|
| Task | Exports |
|
|
356
52
|
|---|---|
|
|
357
|
-
| Declare the protocol ledger state (setup step
|
|
53
|
+
| Declare the protocol ledger state (setup step 3) | `SignBidirectionalEventMap` (the request map the MPC reads) and `SignetSigner` (the Signet singleton's cross-contract-call interface, pinned at deploy). |
|
|
358
54
|
| Build and store a signature request (runtime step 1) | `constructSignBidirectionalEvent` and `calculateRequestId`, over the request structs `EvmType2TxParams`, `EvmCalldata` and `EvmAccessListEntry`. |
|
|
359
55
|
| Notify the MPC of the request (runtime step 1) | `constructSignBidirectionalEventNotificationV1`: packs your contract's address and the request map's ledger-tree path. |
|
|
360
|
-
| Build and read calldata words in-circuit | The builders `evmAddressAbiWord`, `numericAbiWord` and `boolAbiWord`, and the readers `abiWordToUint128` and `abiWordToBool` (see [EVM Type 2 transactions and ABI calldata words](#evm-type-2-transactions-and-abi-calldata-words)). |
|
|
56
|
+
| Build and read calldata words in-circuit | The builders `evmAddressAbiWord`, `numericAbiWord` and `boolAbiWord`, and the readers `abiWordToUint128` and `abiWordToBool` (see [EVM Type 2 transactions and ABI calldata words](https://github.com/sig-net/midnight-integration/blob/main/README.md#evm-type-2-transactions-and-abi-calldata-words)). |
|
|
361
57
|
| Verify the execution attestation (runtime step 5) | `verifyRespondBidirectionalEvent`: recomputes the attestation digest from the output bytes and checks the MPC's signature against your pinned response key. |
|
|
362
58
|
|
|
363
59
|
### TypeScript library
|
|
@@ -367,11 +63,11 @@ What clients import from `@sig-net/midnight`:
|
|
|
367
63
|
| Task | Exports |
|
|
368
64
|
|---|---|
|
|
369
65
|
| Poll for the MPC's responses and verify them (runtime steps 2 to 4) | `SignetRequestResponseReader`: one reader per contract and Signet singleton pair. Its getters `getVerifiedSignatureRespondedEvent`, `getSignedEvmTransaction` and `getVerifiedRespondBidirectionalEvent` map to steps 2, 3 and 4. |
|
|
370
|
-
| Derive the key the MPC signs your requests with | `deriveEvmAddress`: the expected signer address checked in step 2 (see [Derived keys](#derived-keys)). |
|
|
371
|
-
| Derive the response key your deploy pins | `deriveMidnightResponseKey`: the key `initialise` stores (setup step
|
|
372
|
-
| Look up published counterparty values | `MidnightNetwork`, `getMpcRootPublicKey` and `getSignetContractAddress`: the fixed per-network values (see the notes in [Runtime](#runtime)). |
|
|
66
|
+
| Derive the key the MPC signs your requests with | `deriveEvmAddress`: the expected signer address checked in step 2 (see [Derived keys](https://github.com/sig-net/midnight-integration/blob/main/README.md#derived-keys)). |
|
|
67
|
+
| Derive the response key your deploy pins | `deriveMidnightResponseKey`: the key `initialise` stores (setup step 4), derived from your contract's address. |
|
|
68
|
+
| Look up published counterparty values | `MidnightNetwork`, `getMpcRootPublicKey` and `getSignetContractAddress`: the fixed per-network values (see the notes in [Runtime](https://github.com/sig-net/midnight-integration/blob/main/README.md#runtime)). |
|
|
373
69
|
| Compute a request id off chain | `calculateRequestId`: the TS twin of the on-chain circuit, plus `requestIdHex` and `parseRequestIdHex` for the hex form. |
|
|
374
|
-
| Compose expected calldata words off chain (UIs, expected-record builders, tests) | The builders `numericAbiWord`, `evmAddressAbiWord` and `boolAbiWord`, and the readers `abiWordToUint128` and `abiWordToBool`: TS twins of the circuits under identical names
|
|
70
|
+
| Compose expected calldata words off chain (UIs, expected-record builders, tests) | The builders `numericAbiWord`, `evmAddressAbiWord` and `boolAbiWord`, and the readers `abiWordToUint128` and `abiWordToBool`: TS twins of the circuits under identical names. |
|
|
375
71
|
| Convert a foreign execution output into respond bytes | `deserializeEvmOutput` (raw EVM return data to named values) and `serializeRespondOutput` (named values to the packed respond payload the MPC attests): together they rebuild the `serializedOutput` of steps 4 and 5. |
|
|
376
72
|
| Recognise a failed remote execution | `MPC_FAILURE_OUTPUT` and `isMpcFailureOutput`: the MPC's fixed 5-byte failure payload for reverted or replaced transactions. |
|
|
377
73
|
| Verify attestations without the reader | `verifyRespondBidirectionalSignature`: the check the reader runs internally, exposed for custom pipelines. |
|
|
@@ -414,10 +110,6 @@ const event = {
|
|
|
414
110
|
};
|
|
415
111
|
```
|
|
416
112
|
|
|
417
|
-
## More examples
|
|
418
|
-
|
|
419
|
-
For full integration examples (such as an ERC20 cross chain vault) see the [`sig-net/midnight-examples`](https://github.com/sig-net/midnight-examples) repository.
|
|
420
|
-
|
|
421
113
|
## Related packages
|
|
422
114
|
|
|
423
115
|
- [`@sig-net/midnight-contract`](https://www.npmjs.com/package/@sig-net/midnight-contract): the central signet contract this library reads from.
|
|
@@ -86,4 +86,14 @@ export declare function decodeExactly<T>(type: CompactType<T>, atoms: readonly U
|
|
|
86
86
|
* not a `Bytes` atom.
|
|
87
87
|
*/
|
|
88
88
|
export declare function declaredWidths(cell: AlignedValue, what: string): number[];
|
|
89
|
+
/**
|
|
90
|
+
* Descriptor of the Compact tuple `[RequestId, Bytes<serializedOutputLength>]`
|
|
91
|
+
* the attestation digest hashes, composed the way the compiler composes a
|
|
92
|
+
* tuple: the elements' alignments and values concatenated in order. The output
|
|
93
|
+
* width enters the descriptor, so it is fixed per call rather than a constant.
|
|
94
|
+
*
|
|
95
|
+
* @param serializedOutputLength - Declared width of the output element, in bytes.
|
|
96
|
+
* @returns The pair descriptor for {@link calculateSignetAttestationDigest}.
|
|
97
|
+
*/
|
|
98
|
+
export declare function attestationPreimageDescriptor(serializedOutputLength: number): CompactType<[Uint8Array, Uint8Array]>;
|
|
89
99
|
//# sourceMappingURL=compact-descriptors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compact-descriptors.d.ts","sourceRoot":"","sources":["../src/compact-descriptors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compact-descriptors.d.ts","sourceRoot":"","sources":["../src/compact-descriptors.ts"],"names":[],"mappings":"AA4BA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAEhB,gBAAgB,EAChB,0BAA0B,EAC3B,MAAM,iCAAiC,CAAC;AAKzC,0CAA0C;AAC1C,eAAO,MAAM,OAAO,kBAA0B,CAAC;AAC/C,2CAA2C;AAC3C,eAAO,MAAM,QAAQ,kBAA2B,CAAC;AACjD,2CAA2C;AAC3C,eAAO,MAAM,QAAQ,kBAA2B,CAAC;AACjD,2CAA2C;AAC3C,eAAO,MAAM,QAAQ,kBAA2B,CAAC;AACjD,yCAAyC;AACzC,eAAO,MAAM,MAAM,4BAAmD,CAAC;AACvE,0CAA0C;AAC1C,eAAO,MAAM,OAAO,4BAAoD,CAAC;AACzE,0CAA0C;AAC1C,eAAO,MAAM,OAAO,4BAAoD,CAAC;AACzE,2CAA2C;AAC3C,eAAO,MAAM,QAAQ,4BAAsD,CAAC;AAE5E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,eAAe,CAIzD,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;CACV;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE;IAChE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7C,GAAG,WAAW,CAAC,CAAC,CAAC,CAgBjB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAKtF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,IAAI,EAAE,MAAM,GACX,CAAC,CASH;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,sBAAsB,EAAE,MAAM,GAC7B,WAAW,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAUvC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// Compact-generic runtime descriptor toolkit: compact-runtime `CompactType`
|
|
2
2
|
// codecs (alignment/toValue/fromValue) at the same literals the compiler
|
|
3
3
|
// emits, composed into the signet record descriptors by the request modules.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// to the
|
|
7
|
-
//
|
|
4
|
+
// These are required so that packages can
|
|
5
|
+
// - decode raw state cells processed at runtime into types used by the protocol,
|
|
6
|
+
// without requiring access to the compactc generated contract specific SDK.
|
|
7
|
+
// - present a record to `transientHash` with the same alignment the circuits hash
|
|
8
|
+
// it under
|
|
9
|
+
// These descriptors are required as Midnight libraries expose no supported equivalent:
|
|
8
10
|
// - A compiled contract module (`src/managed/`) builds one such codec per
|
|
9
11
|
// ledger type but keeps them module-private, exporting only `ledger()`,
|
|
10
12
|
// which decodes the FULL state of the one contract it was compiled from.
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
// composer and no `Maybe` descriptor, and documents its own pre-built
|
|
16
18
|
// instances (`Bytes32Descriptor`, `ContractAddressDescriptor`, ...) as
|
|
17
19
|
// "not intended for direct consumption".
|
|
20
|
+
//
|
|
18
21
|
// Delete each piece of this file the moment compact-runtime exports a
|
|
19
22
|
// supported equivalent.
|
|
20
23
|
//
|
|
@@ -136,4 +139,24 @@ export function declaredWidths(cell, what) {
|
|
|
136
139
|
return segment.value.length;
|
|
137
140
|
});
|
|
138
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Descriptor of the Compact tuple `[RequestId, Bytes<serializedOutputLength>]`
|
|
144
|
+
* the attestation digest hashes, composed the way the compiler composes a
|
|
145
|
+
* tuple: the elements' alignments and values concatenated in order. The output
|
|
146
|
+
* width enters the descriptor, so it is fixed per call rather than a constant.
|
|
147
|
+
*
|
|
148
|
+
* @param serializedOutputLength - Declared width of the output element, in bytes.
|
|
149
|
+
* @returns The pair descriptor for {@link calculateSignetAttestationDigest}.
|
|
150
|
+
*/
|
|
151
|
+
export function attestationPreimageDescriptor(serializedOutputLength) {
|
|
152
|
+
const output = new CompactTypeBytes(serializedOutputLength);
|
|
153
|
+
return {
|
|
154
|
+
alignment: () => [...BYTES_32.alignment(), ...output.alignment()],
|
|
155
|
+
toValue: ([requestId, serializedOutput]) => [
|
|
156
|
+
...BYTES_32.toValue(requestId),
|
|
157
|
+
...output.toValue(serializedOutput),
|
|
158
|
+
],
|
|
159
|
+
fromValue: (value) => [BYTES_32.fromValue(value), output.fromValue(value)],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
139
162
|
//# sourceMappingURL=compact-descriptors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compact-descriptors.js","sourceRoot":"","sources":["../src/compact-descriptors.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,yEAAyE;AACzE,6EAA6E;AAC7E,
|
|
1
|
+
{"version":3,"file":"compact-descriptors.js","sourceRoot":"","sources":["../src/compact-descriptors.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Secp256k1Point } from "@midnight-ntwrk/compact-runtime";
|
|
2
2
|
import { Signature } from "ethers";
|
|
3
3
|
import type { MpcSignature, RespondBidirectionalEvent, SignatureRespondedEvent } from "./signet-contract-events.ts";
|
|
4
4
|
import type { RequestId } from "./signet-requests.ts";
|
|
@@ -103,23 +103,39 @@ export declare function formatSecp256k1PublicKey(point: Secp256k1Point): string;
|
|
|
103
103
|
export declare function secp256k1PublicKeyOf(secretKey: Uint8Array): Secp256k1Point;
|
|
104
104
|
/**
|
|
105
105
|
* The attestation digest of a respond-bidirectional response:
|
|
106
|
-
* `
|
|
107
|
-
* ECDSA-signs to attest a remote execution. TS twin of
|
|
108
|
-
* Compact circuit of the same name
|
|
109
|
-
* circuits in tests. The output is hashed as given, at its exact length:
|
|
110
|
-
* no padding, no length prefix.
|
|
106
|
+
* `upgradeFromTransient(transientHash([requestId, serializedOutput]))`, the
|
|
107
|
+
* 32-byte digest the MPC ECDSA-signs to attest a remote execution. TS twin of
|
|
108
|
+
* the size-generic Compact circuit of the same name.
|
|
111
109
|
*
|
|
112
110
|
* @param requestId - The 32-byte request id the response answers.
|
|
113
111
|
* @param serializedOutput - The serialised execution output, exact unpadded bytes.
|
|
114
112
|
* @returns The 32-byte attestation digest.
|
|
115
113
|
*/
|
|
116
114
|
export declare function calculateSignetAttestationDigest(requestId: RequestId, serializedOutput: Uint8Array): Uint8Array;
|
|
115
|
+
/**
|
|
116
|
+
* Produce the circuit-input form of a posted respond-bidirectional
|
|
117
|
+
* attestation: `signature.bigR.x` and `signature.s` byte-reversed into
|
|
118
|
+
* little-endian, everything else verbatim. The in-circuit
|
|
119
|
+
* `verifyRespondBidirectionalEvent` reads those two scalars through
|
|
120
|
+
* little-endian casts (the reversal is free off-chain and costly
|
|
121
|
+
* in-circuit), while the wire and ledger records stay big-endian: pass every
|
|
122
|
+
* event through this exactly once, at the circuit call. A record passed
|
|
123
|
+
* without the flip fails verification, never falsely accepts.
|
|
124
|
+
*
|
|
125
|
+
* @param event - The posted record as read off the ledger (big-endian).
|
|
126
|
+
* @returns The record in circuit-input form.
|
|
127
|
+
* @throws {Error} If a signature component is not exactly 32 bytes.
|
|
128
|
+
*/
|
|
129
|
+
export declare function respondBidirectionalEventToCircuitInput(event: RespondBidirectionalEvent): RespondBidirectionalEvent;
|
|
117
130
|
/**
|
|
118
131
|
* Off-chain twin of the in-circuit `verifyRespondBidirectionalEvent`: checks
|
|
119
132
|
* a posted respond-bidirectional attestation against the execution output
|
|
120
133
|
* and the contract's pinned MPC response key. Clients run it to sift
|
|
121
134
|
* candidate posts before calling a contract: a post this accepts verifies
|
|
122
|
-
* in-circuit
|
|
135
|
+
* in-circuit (once flipped to circuit-input form, see
|
|
136
|
+
* {@link respondBidirectionalEventToCircuitInput}). Takes the record as read
|
|
137
|
+
* off the ledger (big-endian). Malformed records return `false` rather than
|
|
138
|
+
* throwing.
|
|
123
139
|
*
|
|
124
140
|
* @param requestId - The 32-byte request id the response answers.
|
|
125
141
|
* @param serializedOutput - The serialised execution output, exact unpadded bytes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ecdsa-attestation.d.ts","sourceRoot":"","sources":["../src/ecdsa-attestation.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ecdsa-attestation.d.ts","sourceRoot":"","sources":["../src/ecdsa-attestation.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAW,MAAM,QAAQ,CAAC;AAI5C,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,uCAAuC;AACvC,eAAO,MAAM,eAAe,QAA2B,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,CAAC,EAAE,MAAM,CAAC;IACV,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,cAAc,CAc/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,cAAc,GAAG,YAAY,CAqBpF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,YAAY,GAAG,cAAc,CAapF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,uBAAuB,GAAG,SAAS,CAO/F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,SAAS,CAAC,GAChD,uBAAuB,CAQzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAgBrE;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAGtE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,UAAU,GAAG,cAAc,CAO1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAC9C,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,UAAU,GAC3B,UAAU,CAOZ;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uCAAuC,CACrD,KAAK,EAAE,yBAAyB,GAC/B,yBAAyB,CAQ3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mCAAmC,CACjD,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,UAAU,EAC5B,KAAK,EAAE,yBAAyB,EAChC,cAAc,EAAE,cAAc,GAC7B,OAAO,CAyBT"}
|