@chainlink/cre-sdk 1.0.0 → 1.0.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.
Files changed (44) hide show
  1. package/dist/generated/capabilities/blockchain/evm/v1alpha/client_pb.d.ts +0 -192
  2. package/dist/generated/capabilities/blockchain/evm/v1alpha/client_pb.js +4 -27
  3. package/dist/generated/capabilities/networking/confidentialhttp/v1alpha/client_pb.d.ts +245 -0
  4. package/dist/generated/capabilities/networking/confidentialhttp/v1alpha/client_pb.js +47 -0
  5. package/dist/generated/capabilities/networking/http/v1alpha/client_pb.d.ts +21 -16
  6. package/dist/generated/capabilities/networking/http/v1alpha/client_pb.js +2 -1
  7. package/dist/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.d.ts +12 -13
  8. package/dist/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.js +33 -103
  9. package/dist/generated-sdk/capabilities/networking/confidentialhttp/v1alpha/client_sdk_gen.d.ts +32 -0
  10. package/dist/generated-sdk/capabilities/networking/confidentialhttp/v1alpha/client_sdk_gen.js +71 -0
  11. package/dist/pb.d.ts +1 -0
  12. package/dist/pb.js +1 -0
  13. package/dist/sdk/cre/index.d.ts +3 -0
  14. package/dist/sdk/cre/index.js +4 -0
  15. package/dist/sdk/impl/runtime-impl.d.ts +70 -1
  16. package/dist/sdk/impl/runtime-impl.js +215 -110
  17. package/dist/sdk/runtime.d.ts +26 -8
  18. package/dist/sdk/utils/capabilities/blockchain/blockchain-helpers.d.ts +43 -0
  19. package/dist/sdk/utils/capabilities/blockchain/blockchain-helpers.js +51 -1
  20. package/dist/sdk/utils/capabilities/http/http-helpers.d.ts +7 -6
  21. package/dist/sdk/utils/chain-selectors/{getNetwork.d.ts → get-network.d.ts} +2 -8
  22. package/dist/sdk/utils/chain-selectors/get-network.js +18 -0
  23. package/dist/sdk/utils/chain-selectors/index.d.ts +2 -2
  24. package/dist/sdk/utils/chain-selectors/index.js +2 -2
  25. package/dist/sdk/utils/chain-selectors/network-lookup.d.ts +31 -0
  26. package/dist/sdk/utils/chain-selectors/network-lookup.js +82 -0
  27. package/dist/sdk/utils/config/index.js +2 -1
  28. package/dist/sdk/utils/hex-utils.d.ts +17 -0
  29. package/dist/sdk/utils/hex-utils.js +29 -0
  30. package/dist/sdk/utils/index.d.ts +1 -0
  31. package/dist/sdk/utils/index.js +1 -0
  32. package/dist/sdk/wasm/index.d.ts +1 -0
  33. package/dist/sdk/wasm/index.js +1 -0
  34. package/dist/sdk/wasm/send-error-response.d.ts +16 -0
  35. package/dist/sdk/wasm/send-error-response.js +43 -0
  36. package/dist/workflows/standard_tests/host_wasm_write_errors_are_respected/test.ts +32 -0
  37. package/package.json +8 -3
  38. package/scripts/src/compile-to-js.ts +38 -19
  39. package/scripts/src/generate-sdks.ts +3 -0
  40. package/scripts/src/workflow-wrapper.test.ts +321 -0
  41. package/scripts/src/workflow-wrapper.ts +163 -0
  42. package/dist/sdk/utils/chain-selectors/getNetwork.js +0 -77
  43. /package/dist/sdk/utils/chain-selectors/{getAllNetworks.d.ts → get-all-networks.d.ts} +0 -0
  44. /package/dist/sdk/utils/chain-selectors/{getAllNetworks.js → get-all-networks.js} +0 -0
@@ -3,44 +3,113 @@ import { type AwaitCapabilitiesRequest, type AwaitCapabilitiesResponse, type Awa
3
3
  import type { BaseRuntime, CallCapabilityParams, NodeRuntime, ReportRequest, ReportRequestJson, Runtime } from '..';
4
4
  import type { Report } from '../report';
5
5
  import { type ConsensusAggregation, type PrimitiveTypes, type UnwrapOptions } from '../utils';
6
+ /**
7
+ * Base implementation shared by DON and Node runtimes.
8
+ *
9
+ * Call ID Management:
10
+ * - DON mode: IDs increment (1, 2, 3...)
11
+ * - Node mode: IDs decrement (-1, -2, -3...)
12
+ * This prevents collisions when both modes are active.
13
+ */
6
14
  export declare class BaseRuntimeImpl<C> implements BaseRuntime<C> {
7
15
  config: C;
8
16
  nextCallId: number;
9
17
  protected helpers: RuntimeHelpers;
10
18
  protected maxResponseSize: bigint;
11
19
  private mode;
20
+ /**
21
+ * When set, prevents operations that aren't allowed in current mode.
22
+ * - Set in DON mode when code tries to use NodeRuntime
23
+ * - Set in Node mode when code tries to use Runtime
24
+ */
12
25
  modeError?: Error;
13
26
  constructor(config: C, nextCallId: number, helpers: RuntimeHelpers, maxResponseSize: bigint, mode: Mode);
27
+ /**
28
+ * Calls a capability and returns a lazy result.
29
+ * The actual call happens immediately, but result retrieval is deferred.
30
+ */
14
31
  callCapability<I extends Message, O extends Message>({ capabilityId, method, payload, inputSchema, outputSchema, }: CallCapabilityParams<I, O>): {
15
32
  result: () => O;
16
33
  };
34
+ /**
35
+ * Allocates a unique callback ID for a capability request.
36
+ * DON mode increments, Node mode decrements (prevents collisions).
37
+ */
38
+ private allocateCallbackId;
39
+ /**
40
+ * Awaits capability response and unwraps the result or throws error.
41
+ */
42
+ private awaitAndUnwrapCapabilityResponse;
17
43
  getNextCallId(): number;
18
44
  now(): Date;
19
45
  log(message: string): void;
20
46
  }
47
+ /**
48
+ * It is used when a BFT guarantee cannot be provided automatically (e.g. calling a standard API).
49
+ * You tell each node to perform a task on its own.
50
+ * Each node returns its own individual answer, and you are responsible for telling the SDK how to combine them into a single, trusted result by providing an aggregation algorithm.
51
+ *
52
+ * Useful in situation where you already expect non-determinism (e.g., inherently variable HTTP responses).
53
+ * Switching from Node Mode back to DON mode requires workflow authors to handle consensus themselves.
54
+ */
21
55
  export declare class NodeRuntimeImpl<C> extends BaseRuntimeImpl<C> implements NodeRuntime<C> {
22
56
  _isNodeRuntime: true;
23
57
  constructor(config: C, nextCallId: number, helpers: RuntimeHelpers, maxResponseSize: bigint);
24
58
  }
59
+ /**
60
+ * It is used for operations that are guaranteed to be Byzantine Fault Tolerant (BFT).
61
+ * You ask the network to execute something, and CRE handles the underlying complexity to ensure you get back one final, secure, and trustworthy result.
62
+ */
25
63
  export declare class RuntimeImpl<C> extends BaseRuntimeImpl<C> implements Runtime<C> {
26
64
  private nextNodeCallId;
27
65
  constructor(config: C, nextCallId: number, helpers: RuntimeHelpers, maxResponseSize: bigint);
28
- runInNodeMode<TArgs extends unknown[], TOutput>(fn: (nodeRuntime: NodeRuntime<C>, ...args: TArgs) => TOutput, consensusAggretation: ConsensusAggregation<TOutput, true>, unwrapOptions?: TOutput extends PrimitiveTypes ? never : UnwrapOptions<TOutput>): (...args: TArgs) => {
66
+ /**
67
+ * Executes a function in Node mode on each node, then aggregates via consensus.
68
+ *
69
+ * Flow:
70
+ * 1. Switches to Node mode, preventing DON operations
71
+ * 2. Executes fn() on each node independently
72
+ * 3. Captures result or error as "observation"
73
+ * 4. Switches back to DON mode
74
+ * 5. Runs consensus to aggregate observations
75
+ * 6. Returns aggregated result
76
+ */
77
+ runInNodeMode<TArgs extends unknown[], TOutput>(fn: (nodeRuntime: NodeRuntime<C>, ...args: TArgs) => TOutput, consensusAggregation: ConsensusAggregation<TOutput, true>, unwrapOptions?: TOutput extends PrimitiveTypes ? never : UnwrapOptions<TOutput>): (...args: TArgs) => {
29
78
  result: () => TOutput;
30
79
  };
80
+ private prepareConsensusInput;
81
+ private captureObservation;
82
+ private captureError;
83
+ private restoreDonMode;
84
+ private runConsensusAndWrap;
31
85
  getSecret(request: SecretRequest | SecretRequestJson): {
32
86
  result: () => Secret;
33
87
  };
88
+ private awaitAndUnwrapSecret;
89
+ /**
90
+ * Generates a report via consensus mechanism.
91
+ */
34
92
  report(input: ReportRequest | ReportRequestJson): {
35
93
  result: () => Report;
36
94
  };
37
95
  }
96
+ /**
97
+ * Interface to the WASM host environment.
98
+ * Provides low-level access to capabilities, secrets, and utilities.
99
+ */
38
100
  export interface RuntimeHelpers {
101
+ /** Initiates a capability call. Returns false if capability not found. */
39
102
  call(request: CapabilityRequest): boolean;
103
+ /** Awaits capability responses. Blocks until responses are ready. */
40
104
  await(request: AwaitCapabilitiesRequest, maxResponseSize: bigint): AwaitCapabilitiesResponse;
105
+ /** Requests secrets from host. Returns false if host rejects request. */
41
106
  getSecrets(request: GetSecretsRequest, maxResponseSize: bigint): boolean;
107
+ /** Awaits secret responses. Blocks until secrets are ready. */
42
108
  awaitSecrets(request: AwaitSecretsRequest, maxResponseSize: bigint): AwaitSecretsResponse;
109
+ /** Switches execution mode (DON vs Node). Affects available operations. */
43
110
  switchModes(mode: Mode): void;
111
+ /** Returns current time in nanoseconds. */
44
112
  now(): number;
113
+ /** Logs a message to the host environment. */
45
114
  log(message: string): void;
46
115
  }
@@ -5,13 +5,25 @@ import { ConsensusCapability } from '../../generated-sdk/capabilities/internal/c
5
5
  import { Value, } from '../utils';
6
6
  import { CapabilityError } from '../utils/capabilities/capability-error';
7
7
  import { DonModeError, NodeModeError, SecretsError } from '../errors';
8
+ /**
9
+ * Base implementation shared by DON and Node runtimes.
10
+ *
11
+ * Call ID Management:
12
+ * - DON mode: IDs increment (1, 2, 3...)
13
+ * - Node mode: IDs decrement (-1, -2, -3...)
14
+ * This prevents collisions when both modes are active.
15
+ */
8
16
  export class BaseRuntimeImpl {
9
17
  config;
10
18
  nextCallId;
11
19
  helpers;
12
20
  maxResponseSize;
13
21
  mode;
14
- // modeError must only be set from within NodeRuntimeImpl
22
+ /**
23
+ * When set, prevents operations that aren't allowed in current mode.
24
+ * - Set in DON mode when code tries to use NodeRuntime
25
+ * - Set in Node mode when code tries to use Runtime
26
+ */
15
27
  modeError;
16
28
  constructor(config, nextCallId, helpers, maxResponseSize, mode) {
17
29
  this.config = config;
@@ -20,7 +32,12 @@ export class BaseRuntimeImpl {
20
32
  this.maxResponseSize = maxResponseSize;
21
33
  this.mode = mode;
22
34
  }
35
+ /**
36
+ * Calls a capability and returns a lazy result.
37
+ * The actual call happens immediately, but result retrieval is deferred.
38
+ */
23
39
  callCapability({ capabilityId, method, payload, inputSchema, outputSchema, }) {
40
+ // Enforce mode restrictions
24
41
  if (this.modeError) {
25
42
  return {
26
43
  result: () => {
@@ -28,22 +45,10 @@ export class BaseRuntimeImpl {
28
45
  },
29
46
  };
30
47
  }
31
- // nextCallId tracks the unique id for a request to the WASM host.
32
- // to avoid collisions of the ID in different modes, it is
33
- // incremented in DON mode and decremented in Node mode.
34
- // eg. - first call don mode: nextCallId = 1
35
- // - second call: nextCallId = 2
36
- // - first call node mode: nextCallId = -1
37
- // - second call node mode: nextCallId = -2
38
- // - etc...
48
+ // Allocate unique callback ID for this request
49
+ const callbackId = this.allocateCallbackId();
50
+ // Send request to WASM host
39
51
  const anyPayload = anyPack(inputSchema, payload);
40
- const callbackId = this.nextCallId;
41
- if (this.mode === Mode.DON) {
42
- this.nextCallId++;
43
- }
44
- else {
45
- this.nextCallId--;
46
- }
47
52
  const req = create(CapabilityRequestSchema, {
48
53
  id: capabilityId,
49
54
  method,
@@ -61,49 +66,68 @@ export class BaseRuntimeImpl {
61
66
  },
62
67
  };
63
68
  }
69
+ // Return lazy result - await and unwrap when .result() is called
64
70
  return {
65
- result: () => {
66
- const awaitRequest = create(AwaitCapabilitiesRequestSchema, {
67
- ids: [callbackId],
68
- });
69
- const awaitResponse = this.helpers.await(awaitRequest, this.maxResponseSize);
70
- const capabilityResponse = awaitResponse.responses[callbackId];
71
- if (!capabilityResponse) {
72
- throw new CapabilityError(`No response found for callback ID ${callbackId}`, {
71
+ result: () => this.awaitAndUnwrapCapabilityResponse(callbackId, capabilityId, method, outputSchema),
72
+ };
73
+ }
74
+ /**
75
+ * Allocates a unique callback ID for a capability request.
76
+ * DON mode increments, Node mode decrements (prevents collisions).
77
+ */
78
+ allocateCallbackId() {
79
+ const callbackId = this.nextCallId;
80
+ if (this.mode === Mode.DON) {
81
+ this.nextCallId++;
82
+ }
83
+ else {
84
+ this.nextCallId--;
85
+ }
86
+ return callbackId;
87
+ }
88
+ /**
89
+ * Awaits capability response and unwraps the result or throws error.
90
+ */
91
+ awaitAndUnwrapCapabilityResponse(callbackId, capabilityId, method, outputSchema) {
92
+ const awaitRequest = create(AwaitCapabilitiesRequestSchema, {
93
+ ids: [callbackId],
94
+ });
95
+ const awaitResponse = this.helpers.await(awaitRequest, this.maxResponseSize);
96
+ const capabilityResponse = awaitResponse.responses[callbackId];
97
+ if (!capabilityResponse) {
98
+ throw new CapabilityError(`No response found for callback ID ${callbackId}`, {
99
+ capabilityId,
100
+ method,
101
+ callbackId,
102
+ });
103
+ }
104
+ const response = capabilityResponse.response;
105
+ switch (response.case) {
106
+ case 'payload': {
107
+ try {
108
+ return anyUnpack(response.value, outputSchema);
109
+ }
110
+ catch {
111
+ throw new CapabilityError(`Error cannot unwrap payload`, {
73
112
  capabilityId,
74
113
  method,
75
114
  callbackId,
76
115
  });
77
116
  }
78
- const response = capabilityResponse.response;
79
- switch (response.case) {
80
- case 'payload': {
81
- try {
82
- return anyUnpack(response.value, outputSchema);
83
- }
84
- catch {
85
- throw new CapabilityError(`Error cannot unwrap payload`, {
86
- capabilityId,
87
- method,
88
- callbackId,
89
- });
90
- }
91
- }
92
- case 'error':
93
- throw new CapabilityError(`Error ${response.value}`, {
94
- capabilityId,
95
- method,
96
- callbackId,
97
- });
98
- default:
99
- throw new CapabilityError(`Error cannot unwrap ${response.case}`, {
100
- capabilityId,
101
- method,
102
- callbackId,
103
- });
104
- }
105
- },
106
- };
117
+ }
118
+ case 'error':
119
+ throw new CapabilityError(`Error ${response.value}`, {
120
+ capabilityId,
121
+ method,
122
+ callbackId,
123
+ });
124
+ default:
125
+ throw new CapabilityError(`Error cannot unwrap ${response.case}`, {
126
+ capabilityId,
127
+ method,
128
+ callbackId,
129
+ });
130
+ }
107
131
  }
108
132
  getNextCallId() {
109
133
  return this.nextCallId;
@@ -116,6 +140,14 @@ export class BaseRuntimeImpl {
116
140
  this.helpers.log(message);
117
141
  }
118
142
  }
143
+ /**
144
+ * It is used when a BFT guarantee cannot be provided automatically (e.g. calling a standard API).
145
+ * You tell each node to perform a task on its own.
146
+ * Each node returns its own individual answer, and you are responsible for telling the SDK how to combine them into a single, trusted result by providing an aggregation algorithm.
147
+ *
148
+ * Useful in situation where you already expect non-determinism (e.g., inherently variable HTTP responses).
149
+ * Switching from Node Mode back to DON mode requires workflow authors to handle consensus themselves.
150
+ */
119
151
  export class NodeRuntimeImpl extends BaseRuntimeImpl {
120
152
  _isNodeRuntime = true;
121
153
  constructor(config, nextCallId, helpers, maxResponseSize) {
@@ -123,58 +155,98 @@ export class NodeRuntimeImpl extends BaseRuntimeImpl {
123
155
  super(config, nextCallId, helpers, maxResponseSize, Mode.NODE);
124
156
  }
125
157
  }
158
+ /**
159
+ * It is used for operations that are guaranteed to be Byzantine Fault Tolerant (BFT).
160
+ * You ask the network to execute something, and CRE handles the underlying complexity to ensure you get back one final, secure, and trustworthy result.
161
+ */
126
162
  export class RuntimeImpl extends BaseRuntimeImpl {
127
163
  nextNodeCallId = -1;
128
164
  constructor(config, nextCallId, helpers, maxResponseSize) {
129
165
  helpers.switchModes(Mode.DON);
130
166
  super(config, nextCallId, helpers, maxResponseSize, Mode.DON);
131
167
  }
132
- runInNodeMode(fn, consensusAggretation, unwrapOptions) {
168
+ /**
169
+ * Executes a function in Node mode on each node, then aggregates via consensus.
170
+ *
171
+ * Flow:
172
+ * 1. Switches to Node mode, preventing DON operations
173
+ * 2. Executes fn() on each node independently
174
+ * 3. Captures result or error as "observation"
175
+ * 4. Switches back to DON mode
176
+ * 5. Runs consensus to aggregate observations
177
+ * 6. Returns aggregated result
178
+ */
179
+ runInNodeMode(fn, consensusAggregation, unwrapOptions) {
133
180
  return (...args) => {
181
+ // Step 1: Create node runtime and prevent DON operations
134
182
  this.modeError = new DonModeError();
135
183
  const nodeRuntime = new NodeRuntimeImpl(this.config, this.nextNodeCallId, this.helpers, this.maxResponseSize);
136
- const consensusInput = create(SimpleConsensusInputsSchema, {
137
- descriptors: consensusAggretation.descriptor,
138
- });
139
- if (consensusAggretation.defaultValue) {
140
- // This cast is safe, since ConsensusAggregation can only have true its second argument if T extends CreSerializable<TOutput>
141
- consensusInput.default = Value.from(consensusAggretation.defaultValue).proto();
142
- }
184
+ // Step 2: Prepare consensus input with config
185
+ const consensusInput = this.prepareConsensusInput(consensusAggregation);
186
+ // Step 3: Execute node function and capture result/error
143
187
  try {
144
188
  const observation = fn(nodeRuntime, ...args);
145
- // This cast is safe, since ConsensusAggregation can only have true its second argument if T extends CreSerializable<TOutput>
146
- consensusInput.observation = {
147
- case: 'value',
148
- value: Value.from(observation).proto(),
149
- };
189
+ this.captureObservation(consensusInput, observation, consensusAggregation.descriptor);
150
190
  }
151
191
  catch (e) {
152
- consensusInput.observation = {
153
- case: 'error',
154
- value: (e instanceof Error && e.message) || String(e),
155
- };
192
+ this.captureError(consensusInput, e);
156
193
  }
157
194
  finally {
158
- // Always restore DON mode before invoking consensus
159
- this.modeError = undefined;
160
- this.nextNodeCallId = nodeRuntime.nextCallId;
161
- nodeRuntime.modeError = new NodeModeError();
162
- this.helpers.switchModes(Mode.DON);
195
+ // Step 4: Always restore DON mode
196
+ this.restoreDonMode(nodeRuntime);
163
197
  }
164
- const consensus = new ConsensusCapability();
165
- const call = consensus.simple(this, consensusInput);
166
- return {
167
- result: () => {
168
- const result = call.result();
169
- const wrappedValue = Value.wrap(result);
170
- return unwrapOptions
171
- ? wrappedValue.unwrapToType(unwrapOptions)
172
- : wrappedValue.unwrap();
173
- },
174
- };
198
+ // Step 5: Run consensus and return lazy result
199
+ return this.runConsensusAndWrap(consensusInput, unwrapOptions);
200
+ };
201
+ }
202
+ prepareConsensusInput(consensusAggregation) {
203
+ const consensusInput = create(SimpleConsensusInputsSchema, {
204
+ descriptors: consensusAggregation.descriptor,
205
+ });
206
+ if (consensusAggregation.defaultValue) {
207
+ // Safe cast: ConsensusAggregation<T, true> implies T extends CreSerializable
208
+ const defaultValue = Value.from(consensusAggregation.defaultValue).proto();
209
+ clearIgnoredFields(defaultValue, consensusAggregation.descriptor);
210
+ consensusInput.default = defaultValue;
211
+ }
212
+ return consensusInput;
213
+ }
214
+ captureObservation(consensusInput, observation, descriptor) {
215
+ // Safe cast: ConsensusAggregation<T, true> implies T extends CreSerializable
216
+ const observationValue = Value.from(observation).proto();
217
+ clearIgnoredFields(observationValue, descriptor);
218
+ consensusInput.observation = {
219
+ case: 'value',
220
+ value: observationValue,
221
+ };
222
+ }
223
+ captureError(consensusInput, e) {
224
+ consensusInput.observation = {
225
+ case: 'error',
226
+ value: (e instanceof Error && e.message) || String(e),
227
+ };
228
+ }
229
+ restoreDonMode(nodeRuntime) {
230
+ this.modeError = undefined;
231
+ this.nextNodeCallId = nodeRuntime.nextCallId;
232
+ nodeRuntime.modeError = new NodeModeError();
233
+ this.helpers.switchModes(Mode.DON);
234
+ }
235
+ runConsensusAndWrap(consensusInput, unwrapOptions) {
236
+ const consensus = new ConsensusCapability();
237
+ const call = consensus.simple(this, consensusInput);
238
+ return {
239
+ result: () => {
240
+ const result = call.result();
241
+ const wrappedValue = Value.wrap(result);
242
+ return unwrapOptions
243
+ ? wrappedValue.unwrapToType(unwrapOptions)
244
+ : wrappedValue.unwrap();
245
+ },
175
246
  };
176
247
  }
177
248
  getSecret(request) {
249
+ // Enforce mode restrictions
178
250
  if (this.modeError) {
179
251
  return {
180
252
  result: () => {
@@ -182,9 +254,11 @@ export class RuntimeImpl extends BaseRuntimeImpl {
182
254
  },
183
255
  };
184
256
  }
257
+ // Normalize request (accept both protobuf and JSON formats)
185
258
  const secretRequest = request.$typeName
186
259
  ? request
187
260
  : create(SecretRequestSchema, request);
261
+ // Allocate callback ID and send request
188
262
  const id = this.nextCallId;
189
263
  this.nextCallId++;
190
264
  const secretsReq = create(GetSecretsRequestSchema, {
@@ -198,37 +272,68 @@ export class RuntimeImpl extends BaseRuntimeImpl {
198
272
  },
199
273
  };
200
274
  }
275
+ // Return lazy result
201
276
  return {
202
- result: () => {
203
- const awaitRequest = create(AwaitSecretsRequestSchema, { ids: [id] });
204
- const awaitResponse = this.helpers.awaitSecrets(awaitRequest, this.maxResponseSize);
205
- const secretsResponse = awaitResponse.responses[id];
206
- if (!secretsResponse) {
207
- throw new SecretsError(secretRequest, 'no response');
208
- }
209
- const responses = secretsResponse.responses;
210
- if (responses.length !== 1) {
211
- throw new SecretsError(secretRequest, 'invalid value returned from host');
212
- }
213
- const response = responses[0].response;
214
- switch (response.case) {
215
- case 'secret':
216
- return response.value;
217
- case 'error':
218
- throw new SecretsError(secretRequest, response.value.error);
219
- default:
220
- throw new SecretsError(secretRequest, 'cannot unmarshal returned value from host');
221
- }
222
- },
277
+ result: () => this.awaitAndUnwrapSecret(id, secretRequest),
223
278
  };
224
279
  }
280
+ awaitAndUnwrapSecret(id, secretRequest) {
281
+ const awaitRequest = create(AwaitSecretsRequestSchema, { ids: [id] });
282
+ const awaitResponse = this.helpers.awaitSecrets(awaitRequest, this.maxResponseSize);
283
+ const secretsResponse = awaitResponse.responses[id];
284
+ if (!secretsResponse) {
285
+ throw new SecretsError(secretRequest, 'no response');
286
+ }
287
+ const responses = secretsResponse.responses;
288
+ if (responses.length !== 1) {
289
+ throw new SecretsError(secretRequest, 'invalid value returned from host');
290
+ }
291
+ const response = responses[0].response;
292
+ switch (response.case) {
293
+ case 'secret':
294
+ return response.value;
295
+ case 'error':
296
+ throw new SecretsError(secretRequest, response.value.error);
297
+ default:
298
+ throw new SecretsError(secretRequest, 'cannot unmarshal returned value from host');
299
+ }
300
+ }
301
+ /**
302
+ * Generates a report via consensus mechanism.
303
+ */
225
304
  report(input) {
226
305
  const consensus = new ConsensusCapability();
227
306
  const call = consensus.report(this, input);
228
307
  return {
229
- result: () => {
230
- return call.result();
231
- },
308
+ result: () => call.result(),
232
309
  };
233
310
  }
234
311
  }
312
+ function clearIgnoredFields(value, descriptor) {
313
+ if (!descriptor || !value) {
314
+ return;
315
+ }
316
+ const fieldsMap = descriptor.descriptor?.case === 'fieldsMap' ? descriptor.descriptor.value : undefined;
317
+ if (!fieldsMap) {
318
+ return;
319
+ }
320
+ if (value.value?.case === 'mapValue') {
321
+ const mapValue = value.value.value;
322
+ if (!mapValue || !mapValue.fields) {
323
+ return;
324
+ }
325
+ for (const [key, val] of Object.entries(mapValue.fields)) {
326
+ const nestedDescriptor = fieldsMap.fields[key];
327
+ if (!nestedDescriptor) {
328
+ delete mapValue.fields[key];
329
+ continue;
330
+ }
331
+ const nestedFieldsMap = nestedDescriptor.descriptor?.case === 'fieldsMap'
332
+ ? nestedDescriptor.descriptor.value
333
+ : undefined;
334
+ if (nestedFieldsMap && val.value?.case === 'mapValue') {
335
+ clearIgnoredFields(val, nestedDescriptor);
336
+ }
337
+ }
338
+ }
339
+ }
@@ -1,6 +1,7 @@
1
1
  import type { Message } from '@bufbuild/protobuf';
2
2
  import type { GenMessage } from '@bufbuild/protobuf/codegenv2';
3
3
  import type { ReportRequest, ReportRequestJson } from '../generated/sdk/v1alpha/sdk_pb';
4
+ import type { Report } from './report';
4
5
  import type { ConsensusAggregation, PrimitiveTypes, UnwrapOptions } from './utils';
5
6
  import type { SecretsProvider } from '.';
6
7
  export type { ReportRequest, ReportRequestJson };
@@ -11,23 +12,40 @@ export type CallCapabilityParams<I extends Message, O extends Message> = {
11
12
  inputSchema: GenMessage<I>;
12
13
  outputSchema: GenMessage<O>;
13
14
  };
14
- import type { Report } from './report';
15
- export type BaseRuntime<C> = {
15
+ /**
16
+ * Base runtime available in both DON and Node execution modes.
17
+ * Provides core functionality for calling capabilities and logging.
18
+ */
19
+ export interface BaseRuntime<C> {
16
20
  config: C;
17
21
  callCapability<I extends Message, O extends Message>(params: CallCapabilityParams<I, O>): {
18
22
  result: () => O;
19
23
  };
20
24
  now(): Date;
21
25
  log(message: string): void;
22
- };
23
- export type Runtime<C> = BaseRuntime<C> & SecretsProvider & {
26
+ }
27
+ /**
28
+ * Runtime for Node mode execution.
29
+ */
30
+ export interface NodeRuntime<C> extends BaseRuntime<C> {
31
+ readonly _isNodeRuntime: true;
32
+ }
33
+ /**
34
+ * Runtime for DON mode execution.
35
+ */
36
+ export interface Runtime<C> extends BaseRuntime<C>, SecretsProvider {
37
+ /**
38
+ * Executes a function in Node mode and aggregates results via consensus.
39
+ *
40
+ * @param fn - Function to execute in each node (receives NodeRuntime)
41
+ * @param consensusAggregation - How to aggregate results across nodes
42
+ * @param unwrapOptions - Optional unwrapping config for complex return types
43
+ * @returns Wrapped function that returns aggregated result
44
+ */
24
45
  runInNodeMode<TArgs extends unknown[], TOutput>(fn: (nodeRuntime: NodeRuntime<C>, ...args: TArgs) => TOutput, consensusAggregation: ConsensusAggregation<TOutput, true>, unwrapOptions?: TOutput extends PrimitiveTypes ? never : UnwrapOptions<TOutput>): (...args: TArgs) => {
25
46
  result: () => TOutput;
26
47
  };
27
48
  report(input: ReportRequest | ReportRequestJson): {
28
49
  result: () => Report;
29
50
  };
30
- };
31
- export type NodeRuntime<C> = BaseRuntime<C> & {
32
- readonly _isNodeRuntime: true;
33
- };
51
+ }
@@ -1,6 +1,47 @@
1
1
  import type { CallMsgJson } from '../../../../generated/capabilities/blockchain/evm/v1alpha/client_pb';
2
2
  import type { ReportRequestJson } from '../../../../generated/sdk/v1alpha/sdk_pb';
3
+ import { type BigInt as GeneratedBigInt } from '../../../../generated/values/v1/values_pb';
3
4
  import type { Address, Hex } from 'viem';
5
+ /**
6
+ * Protobuf BigInt structure returned by SDK methods (e.g., headerByNumber).
7
+ * Uses Pick to extract just the data fields from the generated type.
8
+ */
9
+ export type ProtoBigInt = Pick<GeneratedBigInt, 'absVal' | 'sign'>;
10
+ /**
11
+ * Converts a native JS bigint to a protobuf BigInt JSON representation.
12
+ * Use this when passing bigint values to SDK methods.
13
+ *
14
+ * @example
15
+ * const response = evmClient.callContract(runtime, {
16
+ * call: encodeCallMsg({...}),
17
+ * blockNumber: bigintToProtoBigInt(9768438n)
18
+ * }).result()
19
+ *
20
+ * @param n - The native bigint, number, or string value.
21
+ * @returns The protobuf BigInt JSON representation.
22
+ */
23
+ export declare const bigintToProtoBigInt: (n: number | bigint | string) => import("../../../../generated/values/v1/values_pb").BigIntJson;
24
+ /**
25
+ * Converts a protobuf BigInt to a native JS bigint.
26
+ * Use this when extracting bigint values from SDK responses.
27
+ *
28
+ * @example
29
+ * const latestHeader = evmClient.headerByNumber(runtime, {}).result()
30
+ * const latestBlockNum = protoBigIntToBigint(latestHeader.header.blockNumber!)
31
+ * const customBlock = latestBlockNum - 500n
32
+ *
33
+ * @param pb - The protobuf BigInt object with absVal and sign fields.
34
+ * @returns The native JS bigint value.
35
+ */
36
+ export declare const protoBigIntToBigint: (pb: ProtoBigInt) => bigint;
37
+ /**
38
+ * Convenience alias for `bigintToProtoBigInt`.
39
+ * Creates a block number object for EVM capability requests.
40
+ *
41
+ * @param n - The block number.
42
+ * @returns The protobuf BigInt JSON representation.
43
+ */
44
+ export declare const blockNumber: (n: number | bigint | string) => import("../../../../generated/values/v1/values_pb").BigIntJson;
4
45
  /**
5
46
  * EVM Capability Helper.
6
47
  *
@@ -8,6 +49,7 @@ import type { Address, Hex } from 'viem';
8
49
  * That blockNumber can be:
9
50
  * - the latest mined block (`LATEST_BLOCK_NUMBER`) (default)
10
51
  * - the last finalized block (`LAST_FINALIZED_BLOCK_NUMBER`)
52
+ * - a specific block number (use `blockNumber(n)` or `bigintToProtoBigInt(n)`)
11
53
  *
12
54
  * Using this constant will indicate that the call should be executed at the last finalized block.
13
55
  */
@@ -65,3 +107,4 @@ export declare const EVM_DEFAULT_REPORT_ENCODER: {
65
107
  * @returns The prepared report request.
66
108
  */
67
109
  export declare const prepareReportRequest: (hexEncodedPayload: Hex, reportEncoder?: Exclude<ReportRequestJson, "encodedPayload">) => ReportRequestJson;
110
+ export declare const isChainSelectorSupported: (chainSelectorName: string) => boolean;