@sig-net/midnight 0.0.8 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +254 -112
  2. package/dist/index.d.ts +4 -11
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +4 -11
  5. package/dist/index.js.map +1 -1
  6. package/dist/managed/compiler/contract-info.json +88 -0
  7. package/dist/managed/compiler/contract-manifest.json +8 -8
  8. package/dist/managed/contract/index.d.ts +12 -0
  9. package/dist/managed/contract/index.js +328 -54
  10. package/dist/managed/contract/index.js.map +1 -1
  11. package/dist/signature-requests-state-reader.d.ts.map +1 -1
  12. package/dist/signature-requests-state-reader.js +2 -1
  13. package/dist/signature-requests-state-reader.js.map +1 -1
  14. package/dist/signature-response-verification.d.ts +1 -1
  15. package/dist/signature-response-verification.d.ts.map +1 -1
  16. package/dist/signature-response-verification.js +1 -1
  17. package/dist/signature-response-verification.js.map +1 -1
  18. package/dist/signet-evtype2tx-requests.d.ts +247 -0
  19. package/dist/signet-evtype2tx-requests.d.ts.map +1 -0
  20. package/dist/signet-evtype2tx-requests.js +371 -0
  21. package/dist/signet-evtype2tx-requests.js.map +1 -0
  22. package/dist/signet-request-response-reader.d.ts +1 -1
  23. package/dist/signet-request-response-reader.d.ts.map +1 -1
  24. package/dist/signet-request-response-reader.js +1 -1
  25. package/dist/signet-request-response-reader.js.map +1 -1
  26. package/dist/signet-requests.d.ts +36 -202
  27. package/dist/signet-requests.d.ts.map +1 -1
  28. package/dist/signet-requests.js +31 -300
  29. package/dist/signet-requests.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/Signet.compact +74 -4
  32. package/src/circuits.compact +13 -27
package/README.md CHANGED
@@ -2,146 +2,288 @@
2
2
 
3
3
  The client-agnostic [Sig Network](https://sig.network) protocol library for the [Midnight blockchain](https://midnight.network), and the seed of a future signet.js Midnight adapter. It carries everything a Midnight contract or off-chain client needs to speak the signet protocol (the MPC's [sign bidirectional flow](https://docs.sig.network/architecture/sign-bidirectional)) without binding to any particular contract.
4
4
 
5
+ > ## 🚧 Under Construction 🚧
6
+ >
7
+ > This Sig Network Midnight integration is still under construction.
8
+ > Use at your own risk and expect rapid iteration.
9
+
5
10
  ## What is in it
6
11
 
7
12
  - **Shared Compact modules**: the package ships its `.compact` sources, so contracts import them directly:
8
13
  ```compact
9
14
  import "@sig-net/midnight/src/Signet";
10
15
  ```
11
- - **Compiled pure circuits** (`pureCircuits`): the executable reference implementation of the client-agnostic circuits (path/identity checks, the attestation message, the sign-bidirectional notification packer, the Schnorr challenge). Off-chain code calls these compiled artefacts instead of re-porting the algorithms, so it always agrees with what the contracts prove.
16
+ - **Compiled pure circuits** (`pureCircuits`): the executable reference implementation of the client-agnostic circuits (the attestation digest, response verification, the deploy-time key pin, the notification packer, the ABI word builders and readers). Off-chain code calls these compiled artefacts instead of re-porting the algorithms, so it always agrees with what the contracts prove.
12
17
  - **TypeScript twins of the wire structs** and signet request-id computation.
13
18
  - **State readers, request feed and resolver**: poll the signet contract for pending requests and their signature / remote-execution responses.
14
- - **Crypto helpers**: epsilon derivation and Jubjub Schnorr response verification.
19
+ - **Crypto helpers**: epsilon derivation and ECDSA attestation verification.
20
+
21
+ Where signet.js already covers something (for example EVM transaction preparation or address derivation), import it from there. Only what is Midnight-specific lives here.
22
+
23
+ ## Install
24
+
25
+ ```sh
26
+ npm install @sig-net/midnight
27
+ ```
28
+
29
+ ## Sign bidirectional flow
30
+
31
+ The flow comprises 5 steps:
15
32
 
16
- Where signet.js already covers something (for example EVM transaction preparation or address derivation), import it from there; only what is Midnight-specific lives here.
33
+ 1. Client calls a contract on Midnight which 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)).
34
+ 2. The Sig Network MPC honours the request, generating the transaction signature and posting it back to Midnight.
35
+ 3. Client extracts the signature, using it to submit the signed transaction to the foreign chain.
36
+ 4. The Sig Network MPC observes the foreign transaction and posts the output of the execution (signed) back to Midnight.
37
+ 5. Client extracts the signed foreign execution output and submits it back to the Midnight contract, which verifies the MPC's signature over it in-circuit against the contract's own response key (see [Derived keys](#derived-keys)), completing the foreign transaction execution.
17
38
 
18
39
  ## Derived keys
19
40
 
20
- Every key the MPC signs with is scoped by the requesting contract:
41
+ Every key the MPC uses is derived for the requesting contract and a path. There are two kinds: the request signing key, whose path each contract chooses, and the response signing key, whose path is fixed by the protocol. Both key derivations are **scoped by the address** of the requesting contract.
21
42
 
22
- `derivedSigningKey = f(mpcRootKey[keyVersion], contractAddress, path)`
43
+ ### Request signing key
23
44
 
24
- The path is 32 opaque bytes of the contract's choosing (a fixed literal for a contract-owned account, a hash of a caller's secret for per-user accounts). There are no format requirements. The contract address is always part of the derivation, so no contract can reach another contract's derived keys.
45
+ The key the MPC signs requested foreign transactions with:
25
46
 
26
- ## Install
47
+ `requestSigningKey = f(mpcRootKey[keyVersion], contractAddress, path)`
27
48
 
28
- ```sh
29
- npm install @sig-net/midnight
49
+ The path is 32 opaque bytes of the contract's choosing (e.g. 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. The contract address is always part of the derivation, so no contract can reach another contract's derived keys.
50
+
51
+ ### Response key
52
+
53
+ The key the MPC signs foreign execution outputs with when posting them back to Midnight:
54
+
55
+ `responseKey = f(mpcRootKey[keyVersion], contractAddress, "midnight response key")`
56
+
57
+ The same derivation, but with the path fixed to the literal `"midnight response key"`, giving each contract 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).
58
+
59
+ ## Integrator guide
60
+
61
+ A signet-compliant client contract does four things: it stores its requests in a public `SignBidirectionalEventMap` in its own ledger, it pins its counterparties (the Signet singleton contract and its own MPC response key), it submits signature requests, and it verifies execution responses in-circuit. Concretely, the integration consists of:
62
+
63
+ - 3 once-off **setup** steps
64
+ - 5 per-request **runtime** steps that drive the full sign bidirectional flow
65
+
66
+ ### Setup
67
+
68
+ Set up your contract for integration with the Sig Network MPC's sign bidirectional flow:
69
+
70
+ 1. Import the Signet module at the top of your contract (resolved through `node_modules` via `COMPACT_PATH`):
71
+
72
+ ```compact
73
+ import "@sig-net/midnight/src/Signet";
74
+ ```
75
+
76
+ Then tell the compact compiler about the npm packages with its `COMPACT_PATH` environment variable at compile time:
77
+
78
+ ```sh
79
+ COMPACT_PATH=node_modules compact compile --feature-zkir-v3 src/my-contract.compact src/managed/my-contract
80
+ ```
81
+
82
+ Compile with the pinned toolchain (currently `compact update 0.33.0-rc.2`) and always pass `--feature-zkir-v3`: compiled output without it is not compatible with the ledger-9 matched stack (node, indexer, proof server).
83
+
84
+ 2. Declare the required Sig Network protocol state in your ledger (plus recommended deployer identity and initialisation state). The event map can sit at ANY ledger field: each notification your contract registers names the field position holding it (runtime step 1), and the MPC reads the authenticated request from there.
85
+
86
+ ```compact
87
+ // Required: Map of SignBidirectionalEvent signature requests, configured by transaction type.
88
+ // Configured and sized here for an EVM Type 2 transaction with
89
+ // <1 calldata word, 0 access-list entries, 0 storage keys> and
90
+ // 34-byte serialisation schemas.
91
+ export ledger signBidirectionalEventMap: SignBidirectionalEventMap<EVMType2TxParams<1, 0, 0>, 34, 34>;
92
+
93
+ // Required: The Signet singleton signer interface, set at deploy.
94
+ // Used to notify the MPC of events you add to your signBidirectionalEventMap.
95
+ sealed ledger signetSigner: SignetSigner;
96
+
97
+ // Required: This contract's MPC response key, set in step 3.
98
+ // Used to verify RespondBidirectionalEvents containing the serialised output of foreign chain execution.
99
+ export ledger mpcResponseKey: Secp256k1Point;
100
+
101
+ // Recommended: contract-local source of request nonces, so identical
102
+ // requests hash to distinct request ids. Nothing off-chain reads it.
103
+ export ledger signetRequestNonce: Counter;
104
+
105
+ // Recommended: used in step 3 to ensure initialisation runs only once.
106
+ export ledger initialised: Counter;
107
+
108
+ // Recommended: set on deploy, used in step 3 to ensure only the deployer may set the mpcResponseKey.
109
+ sealed ledger deployer: Bytes<32>;
110
+
111
+ // Recommended: supplies the deployer's identity secret from private state
112
+ // off-chain; only its commitment (below) ever reaches the ledger.
113
+ witness witnessDeployerSecretKey(): Bytes<32>;
114
+
115
+ // Recommended: the deployer identity commitment scheme. Exported so deploy
116
+ // tooling can compute the constructor argument by calling the compiled circuit.
117
+ export pure circuit calculateDeployerCommitment(sk: Bytes<32>): Bytes<32> {
118
+ return persistentHash<Vector<2, Bytes<32>>>([pad(32, "my-contract:deployer:"), sk]);
119
+ }
120
+
121
+ // Required: set signet contract and (recommended) deployer commitment on deployment.
122
+ constructor(signetContract: SignetSigner, deployerCommitment: Bytes<32>) {
123
+ signetSigner = disclose(signetContract);
124
+ deployer = disclose(deployerCommitment);
125
+ }
126
+ ```
127
+
128
+ 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)):
129
+
130
+ ```compact
131
+ export circuit initialise(responseKey: Secp256k1Point): [] {
132
+ // Recommended: confirm that only the deployer may initialise, and only once:
133
+ assert(deployer == calculateDeployerCommitment(witnessDeployerSecretKey()), "Not the deployer");
134
+ assert(initialised == 0, "Already initialised");
135
+ initialised.increment(1);
136
+
137
+ // Required: set MPC response key for verification of RespondBidirectionalEvents
138
+ mpcResponseKey = disclose(responseKey);
139
+ }
140
+ ```
141
+
142
+ ### Runtime
143
+
144
+ Each interaction with your contract that executes a transaction on a foreign chain runs these 5 steps.
145
+
146
+ Steps 1 and 5 are circuits on your contract, and steps 2 to 4 are off-chain client code built on the utilities in `@sig-net/midnight`.
147
+
148
+ The off-chain steps share one `SignetRequestResponseReader` over your contract / Signet singleton pair, and 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)):
149
+
150
+ ```ts
151
+ import { indexerPublicDataProvider } from "@midnight-ntwrk/midnight-js-indexer-public-data-provider";
152
+ import { deriveEvmAddress, SignetRequestResponseReader } from "@sig-net/midnight";
153
+
154
+ // SignetRequestResponseReader to poll for Signed Transactions and Signed RespondBidirectionalEvents
155
+ const reader = new SignetRequestResponseReader({
156
+ // Address of YOUR deployed contract
157
+ requesterContractAddress: myContractAddress,
158
+
159
+ // signBidirectionalEventMap's field position (Setup step 2)
160
+ requesterRequestsIndexField: 0,
161
+
162
+ // Address of the Signet singleton contract
163
+ signetContractAddress,
164
+
165
+ // Provider to index Midnight Blockchain
166
+ publicDataProvider: indexerPublicDataProvider({
167
+ queryURL: indexerUrl,
168
+ subscriptionURL: indexerWsUrl
169
+ }),
170
+ });
171
+
172
+ const expectedSigner = deriveEvmAddress(mpcRootPublicKey, myContractAddress, "my-path");
173
+ ```
174
+
175
+ 1. Store a signature request and notify the MPC via 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:
176
+
177
+ ```compact
178
+ // Construct SignBidirectionalEvent signature request and calculate its RequestId
179
+ const request = constructSignBidirectionalEvent<EVMType2TxParams<1, 0, 0>, 34, 34>(/* ... */);
180
+ const requestId = disclose(calculateRequestId<EVMType2TxParams<1, 0, 0>, 34, 34>(request));
181
+
182
+ // Store the signature request in your signBidirectionalEventMap for MPC to discover
183
+ signetRequestNonce.increment(1);
184
+ signBidirectionalEventMap.insert(requestId, disclose(request));
185
+
186
+ // Notify the MPC of the SignBidirectionalEvent and the location of your signBidirectionalEventMap.
187
+ // The location is 0 here based on the position of the declaration in Setup step 2.
188
+ signetSigner.signBidirectionalEvent(
189
+ requestId,
190
+ constructSignBidirectionalEventNotificationV1(kernel.self(), 0 as Uint<8>),
191
+ );
192
+ ```
193
+
194
+ **NOTE:** `requestId` should be returned from the above circuit call so that it may be used in subsequent steps (or compute it off-chain with the `calculateRequestId` TS twin).
195
+
196
+ 2. Poll the Signet singleton for the MPC's signature response. The response log is unauthenticated (anyone can post), so use the verifying getter: it only returns a post whose signature recovers to `expectedSigner` over the requested transaction's signing hash:
197
+
198
+ ```ts
199
+ const { verified } = await reader.getVerifiedSignatureRespondedEvent(requestId, expectedSigner);
200
+ // verified === undefined: no valid response posted yet, poll again.
201
+ ```
202
+
203
+ 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:
204
+
205
+ ```ts
206
+ import { JsonRpcProvider } from "ethers";
207
+
208
+ const signedTx = await reader.getSignedEVMTransaction(requestId, expectedSigner);
209
+ await new JsonRpcProvider(foreignChainRpcUrl).broadcastTransaction(signedTx.serialized);
210
+ ```
211
+
212
+ 4. Poll the Signet singleton for the MPC's signed remote execution output (posted once the MPC observes the transaction execute on the foreign chain). Posts are stored unverified, so treat them as candidates: the authoritative check is your contract's verify circuit in step 5:
213
+
214
+ ```ts
215
+ const [respondBidirectionalEvent] = await reader.getRespondBidirectionalEvents(requestId);
216
+ // Empty array: not posted yet, poll again.
217
+ ```
218
+
219
+ 5. Deliver the response to your contract, which verifies it in-circuit against the response key pinned in Setup step 3 and consumes the request:
220
+
221
+ ```compact
222
+ assert(
223
+ verifyRespondBidirectionalEvent(requestId, respondBidirectionalEvent, mpcResponseKey),
224
+ "Invalid attestation signature"
225
+ );
226
+ signBidirectionalEventMap.remove(requestId);
227
+ ```
228
+
229
+ ## EVM Type 2 transactions and ABI calldata words
230
+
231
+ An `EVMType2TxParams` request decomposes the EVM transaction into typed fields your contract can enforce field by 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.
232
+
233
+ 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, so a word stored in any other form becomes a signed transaction calling 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.
234
+
235
+ | Solidity type | Build with | Read back with |
236
+ |---|---|---|
237
+ | `address` | `evmAddressAbiWord(addr: Bytes<20>)` | |
238
+ | unsigned integers up to `uint128` (amounts, ids) | `numericAbiWord(value: Uint<128>)` | `abiWordToUint128(word)` |
239
+ | `bool` | `boolAbiWord(value: Boolean)` | `abiWordToBool(word)` |
240
+
241
+ ### Example: an ERC20 transfer
242
+
243
+ `transfer(address,uint256)`, selector `0xa9059cbb`, takes an address word and a numeric word:
244
+
245
+ ```compact
246
+ const calldata = EVMCalldata<2> {
247
+ selector: Bytes[0xa9, 0x05, 0x9c, 0xbb],
248
+ noWords: 2 as Uint<16>,
249
+ words: [
250
+ evmAddressAbiWord(recipient), // address argument (Bytes<20>)
251
+ numericAbiWord(amount) // uint256 argument (from a Uint<128>)
252
+ ]
253
+ };
30
254
  ```
31
255
 
32
- ## How a client contract integrates
256
+ ### Example: a bool argument, and decoding a bool result
33
257
 
34
- A signet-compliant client contract does four things:
258
+ `setApprovalForAll(address,bool)`, selector `0xa22cb465`:
35
259
 
36
- 1. **Stores requests in a public index**: a `SignBidirectionalRequestIndex` map in its ledger. The index can sit at ANY ledger field: each notification the contract registers names the field position holding it, and the MPC reads the authenticated request from there. A contract-local `SignetNonce` counter is a convenient source of request nonces (identical requests must hash to distinct ids); nothing off-chain reads it.
37
- 2. **Pins its counterparties at deploy time**: the central signet contract it notifies, and the MPC attestation key its verify circuit accepts.
38
- 3. **Submits signature requests**: builds the transaction decomposition in-circuit, constructs the canonical request record, stores it in its own index under the request id, and registers a notification in the central registry (which the MPC polls; the MPC then reads the authenticated request back from the ledger field the notification names).
39
- 4. **Verifies the execution response**: checks the attestation key, verifies the MPC's Schnorr attestation in-circuit over (request id, output), and consumes the request.
260
+ ```compact
261
+ const calldata = EVMCalldata<2> {
262
+ selector: Bytes[0xa2, 0x2c, 0xb4, 0x65],
263
+ noWords: 2 as Uint<16>,
264
+ words: [
265
+ evmAddressAbiWord(operator),
266
+ boolAbiWord(true)
267
+ ]
268
+ };
269
+ ```
270
+
271
+ The readers run the same rules in the other direction, rejecting any non-canonical word instead of silently truncating or coercing it. A `RespondBidirectionalEvent`'s `serializedOutput` is the ABI-encoded return data of the remote call, so a settle circuit can decode an ERC20 `transfer`'s `bool` return from the first output word:
40
272
 
41
273
  ```compact
42
- pragma language_version >= 0.25;
43
-
44
- import CompactStandardLibrary;
45
- import "@sig-net/midnight/src/Signet";
46
-
47
- // (1) The request index: the public map the MPC reads requests back from.
48
- // It can sit at any ledger field; the notification in submitSignatureRequest
49
- // names its position (0 in this contract). The counter is contract-local
50
- // (it sources each request's nonce so identical requests get distinct ids);
51
- // the MPC never reads it. The generic size parameters cap the EVM calldata
52
- // words, access list entries and storage keys your requests may carry.
53
- export ledger signetRequestsIndex: SignBidirectionalRequestIndex<EVMType2TxParams<1, 0, 0>>;
54
- export ledger signetNonce: SignetNonce;
55
-
56
- // (2) Pinned at deploy time.
57
- export sealed ledger mpcPubKeyHash: Bytes<32>;
58
- sealed ledger signetNotifier: SignetNotifier;
59
-
60
- constructor(mpcPk: JubjubPoint, signetContract: SignetNotifier) {
61
- mpcPubKeyHash = disclose(persistentHash<JubjubPoint>(mpcPk));
62
- signetNotifier = disclose(signetContract);
63
- }
64
-
65
- // (3) Construct, store and announce a signature request.
66
- export circuit submitSignatureRequest(evmNonce: Uint<64>, keyVersion: Uint<32>): [] {
67
- // Decompose the EVM transaction to be signed. Build (or overwrite) every
68
- // part your contract enforces in-circuit, calldata above all; never pass
69
- // caller input through unchecked.
70
- const txParams = EVMType2TxParams<1, 0, 0> {
71
- to: pad(20, "recipient"),
72
- chainId: 31337 as Uint<64>,
73
- nonce: evmNonce,
74
- gasLimit: 100000 as Uint<64>,
75
- maxFeePerGas: 30000000000 as Uint<128>,
76
- maxPriorityFeePerGas: 1000000000 as Uint<128>,
77
- value: 0 as Uint<128>,
78
- accessListEntryCount: 0,
79
- accessList: [],
80
- calldata: none<EVMCalldata<1>>()
81
- };
82
-
83
- // The canonical request record. This variant signs with the CONTRACT's own
84
- // derived account (a path literal the contract fixes); use
85
- // constructSignBidirectionalRequest instead for caller-identity requests,
86
- // where the path is bound to the caller's identity commitment.
87
- const schema = pad(128, "[{\"name\":\"success\",\"type\":\"bool\"}]");
88
- const request = constructContractPathSignBidirectionalRequest<EVMType2TxParams<1, 0, 0>>(
89
- signetNonce as Uint<64>, // contract-local request nonce
90
- TxParamType.evmType2,
91
- txParams,
92
- pad(32, "eip155:31337"), // target chain (CAIP-2)
93
- keyVersion, // MPC root-key version (>= 1)
94
- pad(256, "my-treasury"), // contract-owned derivation path
95
- pad(32, "ecdsa"),
96
- pad(32, "ethereum"),
97
- pad(64, ""),
98
- schema,
99
- schema
100
- );
101
-
102
- // Store the request in YOUR ledger under its id, then register the
103
- // notification in the central signet contract's registry. The final
104
- // argument is the ledger field position of signetRequestsIndex, which is
105
- // how the MPC finds the index to read the request back from.
106
- const requestId = disclose(calculateRequestId<EVMType2TxParams<1, 0, 0>>(request));
107
- assert(!signetRequestsIndex.member(requestId), "Request already exists");
108
- signetNonce.increment(1);
109
- signetRequestsIndex.insert(requestId, disclose(request));
110
- signetNotifier.notifyBidirectionalSignatureRequest(requestId,
111
- constructSignBidirectionalNotificationV1(kernel.self(), requestId as Bytes<32>, 0 as Uint<8>));
112
- }
113
-
114
- // (4) Verify the MPC's Schnorr-signed attestation of the remote execution
115
- // and consume the request (double-verify protection).
116
- export circuit verifyResponse(requestId: RequestId, respondBidirectional: RespondBidirectional): [] {
117
- const rid = disclose(requestId);
118
- assert(
119
- persistentHash<JubjubPoint>(respondBidirectional.pk) == mpcPubKeyHash,
120
- "Unauthorized: attestation pk is not the MPC key"
121
- );
122
- assert(
123
- jubjubSchnorrVerify<4>(
124
- signetAttestationMessage(rid, respondBidirectional.serializedOutput, respondBidirectional.outputLen),
125
- JubjubSchnorrSignature {
126
- announcement: respondBidirectional.announcement,
127
- response: respondBidirectional.response,
128
- },
129
- respondBidirectional.pk
130
- ),
131
- "Invalid attestation signature"
132
- );
133
- assert(signetRequestsIndex.member(rid), "Request not found");
134
- signetRequestsIndex.remove(rid);
135
- }
274
+ const success = abiWordToBool(slice<32>(respondBidirectionalEvent.serializedOutput, 0));
275
+ assert(success, "Remote transfer failed");
136
276
  ```
137
277
 
138
- Between the two circuits sit the off-chain steps, which this package also covers: poll the central signet contract with `SignetRequestResponseReader` (configured with both contract addresses and the ledger field position of your request index) to collect and verify the MPC's secp256k1 signature (then broadcast the signed transaction to the destination chain), and later the Schnorr-attested execution output to feed back into `verifyResponse`.
278
+ The same builders and readers exist as TypeScript twins under identical names, for composing expected words off-chain (UIs, expected-record builders, tests). They are kept in lockstep with the compiled circuits by this package's test suite.
279
+
280
+ ## More examples
139
281
 
140
- The [signet-caller contract](https://github.com/sig-net/midnight-integration/blob/main/packages/caller-contract/src/signet-caller.compact) is the complete, runnable version of this skeleton, exercised end to end by the repository's integration suite; a fuller application (an ERC20 cross-chain vault) lives in [sig-net/midnight-examples](https://github.com/sig-net/midnight-examples).
282
+ 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.
141
283
 
142
284
  ## Related packages
143
285
 
144
286
  - [`@sig-net/midnight-contract`](https://www.npmjs.com/package/@sig-net/midnight-contract): the central signet contract this library reads from.
145
287
  - [`@sig-net/midnight-contract-deploy`](https://www.npmjs.com/package/@sig-net/midnight-contract-deploy): deploy tooling for that contract plus generic Midnight deploy/wallet plumbing.
146
288
 
147
- Developed in [sig-net/midnight-integration](https://github.com/sig-net/midnight-integration); example applications live in [sig-net/midnight-examples](https://github.com/sig-net/midnight-examples).
289
+ Developed in [sig-net/midnight-integration](https://github.com/sig-net/midnight-integration).
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./signet-requests.ts";
2
+ export * from "./signet-evtype2tx-requests.ts";
2
3
  export * from "./signature-state-reading.ts";
3
4
  export * from "./signature-requests-state-reader.ts";
4
5
  export * from "./signet-contract-state-reader.ts";
@@ -10,17 +11,9 @@ export * from "./constants.ts";
10
11
  export * from "./epsilon-derivation.ts";
11
12
  export * from "./ecdsa-attestation.ts";
12
13
  /**
13
- * Compiled pure circuits of Signet.compact (run `yarn compile` first): the
14
- * executable reference implementation of the client-agnostic circuits —
15
- * the attestation digest (`signetAttestationDigest`), response verification
16
- * (`verifyRespondBidirectionalEvent`), the deploy-time key pin
17
- * (`signetKeyHash`), and the notification packer
18
- * (`constructSignBidirectionalEventNotificationV1`). Off-chain code MUST use
19
- * these instead of re-porting the algorithms — they are the same compiled
20
- * logic the contracts prove. The generic request circuits cannot be compiled
21
- * here (type-parameterized): request construction is contract-only, and
22
- * request-id hashing has a documented-deviation TS twin
23
- * (`calculateRequestId` in signet-requests.ts).
14
+ * Compiled pure circuits of Signet.compact (run `yarn compile` first).
15
+ * Off-chain code MUST use these instead of re-porting the algorithms:
16
+ * they are the same compiled logic the contracts prove.
24
17
  */
25
18
  export { pureCircuits, type PureCircuits } from "./managed/contract/index.js";
26
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AAEvC;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  // library (wire structs, state readers, request feed/resolver, crypto) plus
3
3
  // the compiled pure circuits of the shared Compact module.
4
4
  export * from "./signet-requests.js";
5
+ export * from "./signet-evtype2tx-requests.js";
5
6
  export * from "./signature-state-reading.js";
6
7
  export * from "./signature-requests-state-reader.js";
7
8
  export * from "./signet-contract-state-reader.js";
@@ -13,17 +14,9 @@ export * from "./constants.js";
13
14
  export * from "./epsilon-derivation.js";
14
15
  export * from "./ecdsa-attestation.js";
15
16
  /**
16
- * Compiled pure circuits of Signet.compact (run `yarn compile` first): the
17
- * executable reference implementation of the client-agnostic circuits —
18
- * the attestation digest (`signetAttestationDigest`), response verification
19
- * (`verifyRespondBidirectionalEvent`), the deploy-time key pin
20
- * (`signetKeyHash`), and the notification packer
21
- * (`constructSignBidirectionalEventNotificationV1`). Off-chain code MUST use
22
- * these instead of re-porting the algorithms — they are the same compiled
23
- * logic the contracts prove. The generic request circuits cannot be compiled
24
- * here (type-parameterized): request construction is contract-only, and
25
- * request-id hashing has a documented-deviation TS twin
26
- * (`calculateRequestId` in signet-requests.ts).
17
+ * Compiled pure circuits of Signet.compact (run `yarn compile` first).
18
+ * Off-chain code MUST use these instead of re-porting the algorithms:
19
+ * they are the same compiled logic the contracts prove.
27
20
  */
28
21
  export { pureCircuits } from "./managed/contract/index.js";
29
22
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,2DAA2D;AAE3D,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,2DAA2D;AAE3D,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AAEvC;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC"}
@@ -186,6 +186,94 @@
186
186
  "type-name": "Bytes",
187
187
  "length": 32
188
188
  }
189
+ },
190
+ {
191
+ "name": "evmAddressAbiWord",
192
+ "pure": true,
193
+ "proof": false,
194
+ "arguments": [
195
+ {
196
+ "name": "addr",
197
+ "type": {
198
+ "type-name": "Bytes",
199
+ "length": 20
200
+ }
201
+ }
202
+ ],
203
+ "result-type": {
204
+ "type-name": "Bytes",
205
+ "length": 32
206
+ }
207
+ },
208
+ {
209
+ "name": "numericAbiWord",
210
+ "pure": true,
211
+ "proof": false,
212
+ "arguments": [
213
+ {
214
+ "name": "value",
215
+ "type": {
216
+ "type-name": "Uint",
217
+ "maxval": 340282366920938463463374607431768211455
218
+ }
219
+ }
220
+ ],
221
+ "result-type": {
222
+ "type-name": "Bytes",
223
+ "length": 32
224
+ }
225
+ },
226
+ {
227
+ "name": "boolAbiWord",
228
+ "pure": true,
229
+ "proof": false,
230
+ "arguments": [
231
+ {
232
+ "name": "value",
233
+ "type": {
234
+ "type-name": "Boolean"
235
+ }
236
+ }
237
+ ],
238
+ "result-type": {
239
+ "type-name": "Bytes",
240
+ "length": 32
241
+ }
242
+ },
243
+ {
244
+ "name": "abiWordToUint128",
245
+ "pure": true,
246
+ "proof": false,
247
+ "arguments": [
248
+ {
249
+ "name": "word",
250
+ "type": {
251
+ "type-name": "Bytes",
252
+ "length": 32
253
+ }
254
+ }
255
+ ],
256
+ "result-type": {
257
+ "type-name": "Uint",
258
+ "maxval": 340282366920938463463374607431768211455
259
+ }
260
+ },
261
+ {
262
+ "name": "abiWordToBool",
263
+ "pure": true,
264
+ "proof": false,
265
+ "arguments": [
266
+ {
267
+ "name": "word",
268
+ "type": {
269
+ "type-name": "Bytes",
270
+ "length": 32
271
+ }
272
+ }
273
+ ],
274
+ "result-type": {
275
+ "type-name": "Boolean"
276
+ }
189
277
  }
190
278
  ],
191
279
  "witnesses": [
@@ -7,26 +7,26 @@
7
7
  "type": "directory",
8
8
  "contract-info.json": {
9
9
  "type": "file",
10
- "size": 4397,
11
- "hash": "a9962a641c6b791f1a476adc5875d36de5cedb28b2377f016a8efb7ff644e526"
10
+ "size": 6108,
11
+ "hash": "936ac5ce6f9907eaa010e61295bf2c42cd10410458791ac8b431829876e5bf61"
12
12
  }
13
13
  },
14
14
  "contract": {
15
15
  "type": "directory",
16
16
  "index.d.ts": {
17
17
  "type": "file",
18
- "size": 4176,
19
- "hash": "6319da925c6f853b419c1794e449f732179d94d04b76b7334a634d4eed8f838d"
18
+ "size": 5153,
19
+ "hash": "8e0669479f86b45d1b561c351ca2952932c3407cb993be10a27a54db732863b3"
20
20
  },
21
21
  "index.js": {
22
22
  "type": "file",
23
- "size": 21045,
24
- "hash": "15e7ced35995de9bc5fad3bb3fb9fe070e2d63f59f205140293bdd4b896d3b83"
23
+ "size": 41463,
24
+ "hash": "0166a441ee087c3376b035286cdc2b94b4bf20f1df977c862a420a84b7912eaf"
25
25
  },
26
26
  "index.js.map": {
27
27
  "type": "file",
28
- "size": 1922,
29
- "hash": "b78095e48c3a891b91e89c87b687b420ee1ad595e7d11ac27ed4656a74cc0ea7"
28
+ "size": 3469,
29
+ "hash": "468d63e7361fae52cee908332606da3d854de3b5c4e73c49c1f049501ddb1ac2"
30
30
  }
31
31
  }
32
32
  }
@@ -27,6 +27,11 @@ export type PureCircuits = {
27
27
  },
28
28
  mpcResponseKey_0: __compactRuntime.Secp256k1Point): boolean;
29
29
  signetKeyHash(pk_0: __compactRuntime.Secp256k1Point): Uint8Array;
30
+ evmAddressAbiWord(addr_0: Uint8Array): Uint8Array;
31
+ numericAbiWord(value_0: bigint): Uint8Array;
32
+ boolAbiWord(value_0: boolean): Uint8Array;
33
+ abiWordToUint128(word_0: Uint8Array): bigint;
34
+ abiWordToBool(word_0: Uint8Array): boolean;
30
35
  }
31
36
 
32
37
  export type Circuits<PS> = {
@@ -51,6 +56,13 @@ export type Circuits<PS> = {
51
56
  mpcResponseKey_0: __compactRuntime.Secp256k1Point): Promise<__compactRuntime.CircuitResults<PS, boolean>>;
52
57
  signetKeyHash(context: __compactRuntime.CircuitContext<PS>,
53
58
  pk_0: __compactRuntime.Secp256k1Point): Promise<__compactRuntime.CircuitResults<PS, Uint8Array>>;
59
+ evmAddressAbiWord(context: __compactRuntime.CircuitContext<PS>,
60
+ addr_0: Uint8Array): Promise<__compactRuntime.CircuitResults<PS, Uint8Array>>;
61
+ numericAbiWord(context: __compactRuntime.CircuitContext<PS>, value_0: bigint): Promise<__compactRuntime.CircuitResults<PS, Uint8Array>>;
62
+ boolAbiWord(context: __compactRuntime.CircuitContext<PS>, value_0: boolean): Promise<__compactRuntime.CircuitResults<PS, Uint8Array>>;
63
+ abiWordToUint128(context: __compactRuntime.CircuitContext<PS>,
64
+ word_0: Uint8Array): Promise<__compactRuntime.CircuitResults<PS, bigint>>;
65
+ abiWordToBool(context: __compactRuntime.CircuitContext<PS>, word_0: Uint8Array): Promise<__compactRuntime.CircuitResults<PS, boolean>>;
54
66
  }
55
67
 
56
68
  export type Ledger = {