Skip to content

Commit cda505c

Browse files
feat(DAPP-7912): add confidential http capability
1 parent 6b35ba9 commit cda505c

File tree

9 files changed

+235
-1
lines changed

9 files changed

+235
-1
lines changed

packages/cre-sdk-examples/secrets.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ secretsNames:
33
- SECRET_ADDRESS_ALL
44
CHARACTER_ID:
55
- SECRET_CHARACTER_ID
6+
SECRET_HEADER:
7+
- SECRET_HEADER_VALUE
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"schedule": "0 */1 * * * *",
3+
"url": "https://httpbin.org/headers"
4+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import {
2+
consensusMedianAggregation,
3+
cre,
4+
type NodeRuntime,
5+
Runner,
6+
type Runtime,
7+
} from '@chainlink/cre-sdk'
8+
import { z } from 'zod'
9+
10+
const configSchema = z.object({
11+
schedule: z.string(),
12+
url: z.string(),
13+
})
14+
15+
type Config = z.infer<typeof configSchema>
16+
17+
type MyResult = {
18+
result: bigint
19+
}
20+
21+
const initWorkflow = (config: Config) => {
22+
const cron = new cre.capabilities.CronCapability()
23+
24+
return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)]
25+
}
26+
27+
const doFetch = (nodeRuntime: NodeRuntime<Config>): bigint => {
28+
const confHTTPClient = new cre.capabilities.ConfidentialHTTPClient()
29+
const { responses } = confHTTPClient
30+
.sendRequests(nodeRuntime, {
31+
requests: [
32+
{
33+
url: nodeRuntime.config.url,
34+
method: 'GET',
35+
headers: ['Secret-Header: {{.SECRET_HEADER}}'],
36+
},
37+
],
38+
vaultDonSecrets: [
39+
{
40+
key: 'SECRET_HEADER',
41+
},
42+
],
43+
})
44+
.result()
45+
46+
const bodyText = new TextDecoder().decode(responses[0].body)
47+
const val = BigInt(JSON.parse(bodyText).headers['Secret-Header'])
48+
49+
return val
50+
}
51+
52+
const onCronTrigger = (runtime: Runtime<Config>): MyResult => {
53+
runtime.log('Confidential HTTP workflow triggered.')
54+
55+
const result = runtime.runInNodeMode(doFetch, consensusMedianAggregation())().result()
56+
57+
runtime.log(`Successfully fetched result: ${result}`)
58+
59+
return {
60+
result,
61+
}
62+
}
63+
64+
export async function main() {
65+
const runner = await Runner.newRunner<Config>({ configSchema })
66+
await runner.run(initWorkflow)
67+
}
68+
main()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# ==========================================================================
2+
# CRE WORKFLOW SETTINGS FILE
3+
# ==========================================================================
4+
# This file defines environment-specific workflow settings used by the CRE CLI.
5+
#
6+
# Each top-level key is a target (e.g., `production`, `production-testnet`, etc.).
7+
# You can also define your own custom targets, such as `my-target`, and
8+
# point the CLI to it via an environment variable.
9+
#
10+
# Note: If any setting in this file conflicts with a setting in the CRE Project Settings File,
11+
# the value defined here in the workflow settings file will take precedence.
12+
#
13+
# Below is an example `my-target`:
14+
#
15+
# my-target:
16+
# user-workflow:
17+
# # Optional: The address of the workflow owner (wallet or MSIG contract).
18+
# # Used to establish ownership for encrypting the workflow's secrets.
19+
# # If omitted, defaults to an empty string.
20+
# workflow-owner-address: "0x1234567890abcdef1234567890abcdef12345678"
21+
#
22+
# # Required: The name of the workflow to register with the Workflow Registry contract.
23+
# workflow-name: "MyExampleWorkflow"
24+
25+
# ==========================================================================
26+
local-simulation:
27+
user-workflow:
28+
workflow-owner-address: "(optional) Multi-signature contract address"
29+
workflow-name: "http-confidential-fetch"
30+
workflow-artifacts:
31+
workflow-path: "./index.ts"
32+
config-path: "./config.json"
33+
34+
# ==========================================================================
35+
production-testnet:
36+
user-workflow:
37+
workflow-owner-address: "(optional) Multi-signature contract address"
38+
workflow-name: "http-confidential-fetch"
889 Bytes
Binary file not shown.

packages/cre-sdk/scripts/src/generate-sdks.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { file_capabilities_internal_basicaction_v1_basic_action } from '@cre/gen
44
import { file_capabilities_internal_basictrigger_v1_basic_trigger } from '@cre/generated/capabilities/internal/basictrigger/v1/basic_trigger_pb'
55
import { file_capabilities_internal_consensus_v1alpha_consensus } from '@cre/generated/capabilities/internal/consensus/v1alpha/consensus_pb'
66
import { file_capabilities_internal_nodeaction_v1_node_action } from '@cre/generated/capabilities/internal/nodeaction/v1/node_action_pb'
7+
import { file_capabilities_networking_confidentialhttp_v1alpha_client } from '@cre/generated/capabilities/networking/confidentialhttp/v1alpha/client_pb'
78
import { file_capabilities_networking_http_v1alpha_client } from '@cre/generated/capabilities/networking/http/v1alpha/client_pb'
89
import { file_capabilities_networking_http_v1alpha_trigger } from '@cre/generated/capabilities/networking/http/v1alpha/trigger_pb'
910
import { file_capabilities_scheduler_cron_v1_trigger } from '@cre/generated/capabilities/scheduler/cron/v1/trigger_pb'
@@ -33,4 +34,6 @@ export const main = () => {
3334
generateSdk(file_capabilities_networking_http_v1alpha_trigger, './src/generated-sdk')
3435

3536
generateSdk(file_capabilities_scheduler_cron_v1_trigger, './src/generated-sdk')
37+
38+
generateSdk(file_capabilities_networking_confidentialhttp_v1alpha_client, './src/generated-sdk')
3639
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { fromJson } from '@bufbuild/protobuf'
2+
import {
3+
type EnclaveActionInput,
4+
type EnclaveActionInputJson,
5+
EnclaveActionInputSchema,
6+
type HTTPEnclaveResponseData,
7+
HTTPEnclaveResponseDataSchema,
8+
} from '@cre/generated/capabilities/networking/confidentialhttp/v1alpha/client_pb'
9+
import { type NodeRuntime, type Runtime } from '@cre/sdk'
10+
import { Report } from '@cre/sdk/report'
11+
import type { ConsensusAggregation, PrimitiveTypes, UnwrapOptions } from '@cre/sdk/utils'
12+
13+
export class SendRequestser {
14+
constructor(
15+
private readonly runtime: NodeRuntime<unknown>,
16+
private readonly client: ClientCapability,
17+
) {}
18+
sendRequests(input: EnclaveActionInput | EnclaveActionInputJson): {
19+
result: () => HTTPEnclaveResponseData
20+
} {
21+
return this.client.sendRequests(this.runtime, input)
22+
}
23+
}
24+
25+
/**
26+
* Client Capability
27+
*
28+
* Capability ID: confidential-http@1.0.0-alpha
29+
* Capability Name: confidential-http
30+
* Capability Version: 1.0.0-alpha
31+
*/
32+
export class ClientCapability {
33+
/** The capability ID for this service */
34+
static readonly CAPABILITY_ID = 'confidential-http@1.0.0-alpha'
35+
36+
static readonly CAPABILITY_NAME = 'confidential-http'
37+
static readonly CAPABILITY_VERSION = '1.0.0-alpha'
38+
39+
sendRequests(
40+
runtime: NodeRuntime<unknown>,
41+
input: EnclaveActionInput | EnclaveActionInputJson,
42+
): { result: () => HTTPEnclaveResponseData }
43+
sendRequests<TArgs extends unknown[], TOutput>(
44+
runtime: Runtime<unknown>,
45+
fn: (sendRequestser: SendRequestser, ...args: TArgs) => TOutput,
46+
consensusAggregation: ConsensusAggregation<TOutput, true>,
47+
unwrapOptions?: TOutput extends PrimitiveTypes ? never : UnwrapOptions<TOutput>,
48+
): (...args: TArgs) => { result: () => TOutput }
49+
sendRequests(...args: unknown[]): unknown {
50+
// Check if this is the sugar syntax overload (has function parameter)
51+
if (typeof args[1] === 'function') {
52+
const [runtime, fn, consensusAggregation, unwrapOptions] = args as [
53+
Runtime<unknown>,
54+
(sendRequestser: SendRequestser, ...args: unknown[]) => unknown,
55+
ConsensusAggregation<unknown, true>,
56+
UnwrapOptions<unknown> | undefined,
57+
]
58+
return this.sendRequestsSugarHelper(runtime, fn, consensusAggregation, unwrapOptions)
59+
}
60+
// Otherwise, this is the basic call overload
61+
const [runtime, input] = args as [
62+
NodeRuntime<unknown>,
63+
EnclaveActionInput | EnclaveActionInputJson,
64+
]
65+
return this.sendRequestsCallHelper(runtime, input)
66+
}
67+
private sendRequestsCallHelper(
68+
runtime: NodeRuntime<unknown>,
69+
input: EnclaveActionInput | EnclaveActionInputJson,
70+
): { result: () => HTTPEnclaveResponseData } {
71+
// Handle input conversion - unwrap if it's a wrapped type, convert from JSON if needed
72+
let payload: EnclaveActionInput
73+
74+
if ((input as unknown as { $typeName?: string }).$typeName) {
75+
// It's the original protobuf type
76+
payload = input as EnclaveActionInput
77+
} else {
78+
// It's regular JSON, convert using fromJson
79+
payload = fromJson(EnclaveActionInputSchema, input as EnclaveActionInputJson)
80+
}
81+
82+
const capabilityId = ClientCapability.CAPABILITY_ID
83+
84+
const capabilityResponse = runtime.callCapability<EnclaveActionInput, HTTPEnclaveResponseData>({
85+
capabilityId,
86+
method: 'SendRequests',
87+
payload,
88+
inputSchema: EnclaveActionInputSchema,
89+
outputSchema: HTTPEnclaveResponseDataSchema,
90+
})
91+
92+
return {
93+
result: () => {
94+
const result = capabilityResponse.result()
95+
96+
return result
97+
},
98+
}
99+
}
100+
private sendRequestsSugarHelper<TArgs extends unknown[], TOutput>(
101+
runtime: Runtime<unknown>,
102+
fn: (sendRequestser: SendRequestser, ...args: TArgs) => TOutput,
103+
consensusAggregation: ConsensusAggregation<TOutput, true>,
104+
unwrapOptions?: TOutput extends PrimitiveTypes ? never : UnwrapOptions<TOutput>,
105+
): (...args: TArgs) => { result: () => TOutput } {
106+
const wrappedFn = (runtime: NodeRuntime<unknown>, ...args: TArgs) => {
107+
const sendRequestser = new SendRequestser(runtime, this)
108+
return fn(sendRequestser, ...args)
109+
}
110+
return runtime.runInNodeMode(wrappedFn, consensusAggregation, unwrapOptions)
111+
}
112+
}

packages/cre-sdk/src/pb.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * as EVM_PB from '@cre/generated/capabilities/blockchain/evm/v1alpha/client_pb'
2+
export * as CONFIDENTIAL_HTTP_CLIENT_PB from '@cre/generated/capabilities/networking/confidentialhttp/v1alpha/client_pb'
23
export * as HTTP_CLIENT_PB from '@cre/generated/capabilities/networking/http/v1alpha/client_pb'
34
export * as HTTP_TRIGGER_PB from '@cre/generated/capabilities/networking/http/v1alpha/trigger_pb'
45
export * as CRON_TRIGGER_PB from '@cre/generated/capabilities/scheduler/cron/v1/trigger_pb'

packages/cre-sdk/src/sdk/cre/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
import { ClientCapability as EVMClient } from '@cre/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen'
6+
import { ClientCapability as ConfidentialHTTPClient } from '@cre/generated-sdk/capabilities/networking/confidentialhttp/v1alpha/client_sdk_gen'
67
import { ClientCapability as HTTPClient } from '@cre/generated-sdk/capabilities/networking/http/v1alpha/client_sdk_gen'
78
import { HTTPCapability } from '@cre/generated-sdk/capabilities/networking/http/v1alpha/http_sdk_gen'
89
import { CronCapability } from '@cre/generated-sdk/capabilities/scheduler/cron/v1/cron_sdk_gen'
@@ -26,7 +27,11 @@ export {
2627
type WriteCreReportRequest,
2728
type WriteCreReportRequestJson,
2829
} from '@cre/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen'
29-
30+
// Confidential HTTP Capability
31+
export {
32+
ClientCapability as ConfidentialHTTPClient,
33+
type SendRequestser as ConfidentialHTTPSendRequester,
34+
} from '@cre/generated-sdk/capabilities/networking/confidentialhttp/v1alpha/client_sdk_gen'
3035
// HTTP Capability
3136
export {
3237
ClientCapability as HTTPClient,
@@ -47,6 +52,7 @@ export const cre = {
4752
capabilities: {
4853
CronCapability,
4954
HTTPCapability,
55+
ConfidentialHTTPClient,
5056
HTTPClient,
5157
EVMClient,
5258
},

0 commit comments

Comments
 (0)