Skip to content

Commit 647e783

Browse files
Make generator dynamic (#141)
* Reorganize runtime to be more readable, add JSDoc * rework comment about node mode * Another comment improvement * Another wording change * problem statement * Update generator to handle labels dynamically * Make use of EVM supported chains * Drop go comment * Remove unused github action * Change ordering * Revert ordering change * Add debug log for CI * Add mock restore after testing get-network * Refactor get-network logic to be more testable * clear comment
1 parent 6bb2d34 commit 647e783

File tree

17 files changed

+1077
-553
lines changed

17 files changed

+1077
-553
lines changed

packages/cre-sdk-examples/src/workflows/on-chain/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
encodeCallMsg,
66
getNetwork,
77
type HTTPSendRequester,
8+
isChainSelectorSupported,
89
LAST_FINALIZED_BLOCK_NUMBER,
910
ok,
1011
Runner,
@@ -56,6 +57,12 @@ const onCronTrigger = (runtime: Runtime<Config>) => {
5657

5758
// Get the first EVM configuration from the list
5859
const evmConfig = runtime.config.evms[0]
60+
61+
// Make sure we try to run on supported chain
62+
if (!isChainSelectorSupported(evmConfig.chainSelectorName)) {
63+
throw new Error(`Chain selector name: ${evmConfig.chainSelectorName} is not supported.`)
64+
}
65+
5966
const network = getNetwork({
6067
chainFamily: 'evm',
6168
chainSelectorName: evmConfig.chainSelectorName,

packages/cre-sdk/src/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.ts

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ export class ClientCapability {
126126
static readonly CAPABILITY_NAME = 'evm'
127127
static readonly CAPABILITY_VERSION = '1.0.0'
128128

129-
/** Available chain selectors */
130-
static readonly SUPPORTED_CHAINS = {
129+
/** Available ChainSelector values */
130+
static readonly SUPPORTED_CHAIN_SELECTORS = {
131131
'avalanche-mainnet': 6433500567565415381n,
132132
'avalanche-testnet-fuji': 14767482510784806043n,
133133
'binance_smart_chain-mainnet-opbnb-1': 465944652040885897n,
@@ -143,7 +143,7 @@ export class ClientCapability {
143143
'polygon-testnet-amoy': 16281711391670634445n,
144144
} as const
145145

146-
constructor(private readonly chainSelector?: bigint) {}
146+
constructor(private readonly ChainSelector: bigint) {}
147147

148148
callContract(
149149
runtime: Runtime<unknown>,
@@ -160,10 +160,8 @@ export class ClientCapability {
160160
payload = fromJson(CallContractRequestSchema, input as CallContractRequestJson)
161161
}
162162

163-
// Include chainSelector in capability ID for routing when specified
164-
const capabilityId = this.chainSelector
165-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
166-
: ClientCapability.CAPABILITY_ID
163+
// Include all labels in capability ID for routing when specified
164+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
167165

168166
const capabilityResponse = runtime.callCapability<CallContractRequest, CallContractReply>({
169167
capabilityId,
@@ -197,10 +195,8 @@ export class ClientCapability {
197195
payload = fromJson(FilterLogsRequestSchema, input as FilterLogsRequestJson)
198196
}
199197

200-
// Include chainSelector in capability ID for routing when specified
201-
const capabilityId = this.chainSelector
202-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
203-
: ClientCapability.CAPABILITY_ID
198+
// Include all labels in capability ID for routing when specified
199+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
204200

205201
const capabilityResponse = runtime.callCapability<FilterLogsRequest, FilterLogsReply>({
206202
capabilityId,
@@ -234,10 +230,8 @@ export class ClientCapability {
234230
payload = fromJson(BalanceAtRequestSchema, input as BalanceAtRequestJson)
235231
}
236232

237-
// Include chainSelector in capability ID for routing when specified
238-
const capabilityId = this.chainSelector
239-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
240-
: ClientCapability.CAPABILITY_ID
233+
// Include all labels in capability ID for routing when specified
234+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
241235

242236
const capabilityResponse = runtime.callCapability<BalanceAtRequest, BalanceAtReply>({
243237
capabilityId,
@@ -271,10 +265,8 @@ export class ClientCapability {
271265
payload = fromJson(EstimateGasRequestSchema, input as EstimateGasRequestJson)
272266
}
273267

274-
// Include chainSelector in capability ID for routing when specified
275-
const capabilityId = this.chainSelector
276-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
277-
: ClientCapability.CAPABILITY_ID
268+
// Include all labels in capability ID for routing when specified
269+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
278270

279271
const capabilityResponse = runtime.callCapability<EstimateGasRequest, EstimateGasReply>({
280272
capabilityId,
@@ -311,10 +303,8 @@ export class ClientCapability {
311303
)
312304
}
313305

314-
// Include chainSelector in capability ID for routing when specified
315-
const capabilityId = this.chainSelector
316-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
317-
: ClientCapability.CAPABILITY_ID
306+
// Include all labels in capability ID for routing when specified
307+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
318308

319309
const capabilityResponse = runtime.callCapability<
320310
GetTransactionByHashRequest,
@@ -354,10 +344,8 @@ export class ClientCapability {
354344
)
355345
}
356346

357-
// Include chainSelector in capability ID for routing when specified
358-
const capabilityId = this.chainSelector
359-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
360-
: ClientCapability.CAPABILITY_ID
347+
// Include all labels in capability ID for routing when specified
348+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
361349

362350
const capabilityResponse = runtime.callCapability<
363351
GetTransactionReceiptRequest,
@@ -394,10 +382,8 @@ export class ClientCapability {
394382
payload = fromJson(HeaderByNumberRequestSchema, input as HeaderByNumberRequestJson)
395383
}
396384

397-
// Include chainSelector in capability ID for routing when specified
398-
const capabilityId = this.chainSelector
399-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
400-
: ClientCapability.CAPABILITY_ID
385+
// Include all labels in capability ID for routing when specified
386+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
401387

402388
const capabilityResponse = runtime.callCapability<HeaderByNumberRequest, HeaderByNumberReply>({
403389
capabilityId,
@@ -431,10 +417,8 @@ export class ClientCapability {
431417
payload = fromJson(RegisterLogTrackingRequestSchema, input as RegisterLogTrackingRequestJson)
432418
}
433419

434-
// Include chainSelector in capability ID for routing when specified
435-
const capabilityId = this.chainSelector
436-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
437-
: ClientCapability.CAPABILITY_ID
420+
// Include all labels in capability ID for routing when specified
421+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
438422

439423
const capabilityResponse = runtime.callCapability<RegisterLogTrackingRequest, Empty>({
440424
capabilityId,
@@ -471,10 +455,8 @@ export class ClientCapability {
471455
)
472456
}
473457

474-
// Include chainSelector in capability ID for routing when specified
475-
const capabilityId = this.chainSelector
476-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
477-
: ClientCapability.CAPABILITY_ID
458+
// Include all labels in capability ID for routing when specified
459+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
478460

479461
const capabilityResponse = runtime.callCapability<UnregisterLogTrackingRequest, Empty>({
480462
capabilityId,
@@ -494,11 +476,9 @@ export class ClientCapability {
494476
}
495477

496478
logTrigger(config: FilterLogTriggerRequestJson): ClientLogTrigger {
497-
// Include chainSelector in capability ID for routing when specified
498-
const capabilityId = this.chainSelector
499-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
500-
: ClientCapability.CAPABILITY_ID
501-
return new ClientLogTrigger(config, capabilityId, 'LogTrigger')
479+
// Include all labels in capability ID for routing when specified
480+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
481+
return new ClientLogTrigger(config, capabilityId, 'LogTrigger', this.ChainSelector)
502482
}
503483

504484
writeReport(
@@ -519,10 +499,8 @@ export class ClientCapability {
519499
)
520500
}
521501

522-
// Include chainSelector in capability ID for routing when specified
523-
const capabilityId = this.chainSelector
524-
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
525-
: ClientCapability.CAPABILITY_ID
502+
// Include all labels in capability ID for routing when specified
503+
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
526504

527505
const capabilityResponse = runtime.callCapability<WriteReportRequest, WriteReportReply>({
528506
capabilityId,
@@ -551,6 +529,7 @@ class ClientLogTrigger implements Trigger<Log, Log> {
551529
config: FilterLogTriggerRequest | FilterLogTriggerRequestJson,
552530
private readonly _capabilityId: string,
553531
private readonly _method: string,
532+
private readonly ChainSelector: bigint,
554533
) {
555534
// biome-ignore lint/suspicious/noExplicitAny: Needed for runtime type checking of protocol buffer messages
556535
this.config = (config as any).$typeName
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { describe, expect, it } from 'bun:test'
2+
import { Mode } from '@cre/generated/sdk/v1alpha/sdk_pb'
3+
import { processLabels } from '../label-utils'
4+
5+
describe('Multi-Label Generator Test', () => {
6+
it('should process multiple label types correctly', () => {
7+
// Create a mock capability metadata with all 5 label types
8+
const mockCapOption: any = {
9+
mode: Mode.DON,
10+
capabilityId: '[email protected]',
11+
labels: {
12+
ChainSelector: {
13+
kind: {
14+
case: 'uint64Label',
15+
value: {
16+
defaults: {
17+
'ethereum-mainnet': 5009297550715157269n,
18+
'polygon-mainnet': 4051577828743386545n,
19+
},
20+
},
21+
},
22+
},
23+
Environment: {
24+
kind: {
25+
case: 'stringLabel',
26+
value: {
27+
defaults: {
28+
production: 'prod',
29+
staging: 'stage',
30+
development: 'dev',
31+
},
32+
},
33+
},
34+
},
35+
RegionId: {
36+
kind: {
37+
case: 'uint32Label',
38+
value: {
39+
defaults: {
40+
'us-east-1': 1,
41+
'eu-west-1': 2,
42+
'ap-southeast-1': 3,
43+
},
44+
},
45+
},
46+
},
47+
Offset: {
48+
kind: {
49+
case: 'int32Label',
50+
value: {
51+
defaults: {
52+
'negative-offset': -100,
53+
'zero-offset': 0,
54+
'positive-offset': 100,
55+
},
56+
},
57+
},
58+
},
59+
Timestamp: {
60+
kind: {
61+
case: 'int64Label',
62+
value: {
63+
defaults: {
64+
past: -1234567890n,
65+
epoch: 0n,
66+
future: 1234567890n,
67+
},
68+
},
69+
},
70+
},
71+
},
72+
}
73+
74+
// Process labels
75+
const labels = processLabels(mockCapOption)
76+
77+
// Verify we got all 5 labels
78+
expect(labels).toHaveLength(5)
79+
80+
// Verify ChainSelector label
81+
const chainSelector = labels.find((l) => l.name === 'ChainSelector')
82+
expect(chainSelector).toBeDefined()
83+
expect(chainSelector?.type).toBe('bigint')
84+
expect(chainSelector?.tsType).toBe('bigint')
85+
expect(chainSelector?.defaults).toEqual({
86+
'ethereum-mainnet': 5009297550715157269n,
87+
'polygon-mainnet': 4051577828743386545n,
88+
})
89+
90+
// Verify Environment label
91+
const environment = labels.find((l) => l.name === 'Environment')
92+
expect(environment).toBeDefined()
93+
expect(environment?.type).toBe('string')
94+
expect(environment?.tsType).toBe('string')
95+
expect(environment?.defaults).toEqual({
96+
production: 'prod',
97+
staging: 'stage',
98+
development: 'dev',
99+
})
100+
101+
// Verify RegionId label (uint32)
102+
const regionId = labels.find((l) => l.name === 'RegionId')
103+
expect(regionId).toBeDefined()
104+
expect(regionId?.type).toBe('number')
105+
expect(regionId?.tsType).toBe('number')
106+
expect(regionId?.defaults).toEqual({
107+
'us-east-1': 1,
108+
'eu-west-1': 2,
109+
'ap-southeast-1': 3,
110+
})
111+
112+
// Verify Offset label (int32)
113+
const offset = labels.find((l) => l.name === 'Offset')
114+
expect(offset).toBeDefined()
115+
expect(offset?.type).toBe('number')
116+
expect(offset?.tsType).toBe('number')
117+
expect(offset?.defaults).toEqual({
118+
'negative-offset': -100,
119+
'zero-offset': 0,
120+
'positive-offset': 100,
121+
})
122+
123+
// Verify Timestamp label (int64)
124+
const timestamp = labels.find((l) => l.name === 'Timestamp')
125+
expect(timestamp).toBeDefined()
126+
expect(timestamp?.type).toBe('bigint')
127+
expect(timestamp?.tsType).toBe('bigint')
128+
expect(timestamp?.defaults).toEqual({
129+
past: -1234567890n,
130+
epoch: 0n,
131+
future: 1234567890n,
132+
})
133+
})
134+
})

packages/cre-sdk/src/generator/generate-action.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { DescMethod } from '@bufbuild/protobuf'
2+
import { generateCapabilityIdLogic, type ProcessedLabel } from './label-utils'
23
import { wrapType } from './utils'
34

45
/**
@@ -7,24 +8,17 @@ import { wrapType } from './utils'
78
* @param method - The method descriptor
89
* @param methodName - The camelCase method name
910
* @param capabilityClassName - The class name of the capability object
10-
* @param hasChainSelector - Whether this capability supports chainSelector routing
11+
* @param labels - Array of processed labels for this capability
1112
* @returns The generated action method code
1213
*/
1314
export function generateActionMethod(
1415
method: DescMethod,
1516
methodName: string,
1617
capabilityClassName: string,
17-
hasChainSelector: boolean = false,
18+
labels: ProcessedLabel[],
1819
modePrefix: string,
1920
): string {
20-
const capabilityIdLogic = hasChainSelector
21-
? `
22-
// Include chainSelector in capability ID for routing when specified
23-
const capabilityId = this.chainSelector
24-
? \`\${${capabilityClassName}.CAPABILITY_NAME}:ChainSelector:\${this.chainSelector}@\${${capabilityClassName}.CAPABILITY_VERSION}\`
25-
: ${capabilityClassName}.CAPABILITY_ID;`
26-
: `
27-
const capabilityId = ${capabilityClassName}.CAPABILITY_ID;`
21+
const capabilityIdLogic = generateCapabilityIdLogic(labels, capabilityClassName)
2822

2923
// Check if we have wrapped types
3024
const wrappedInputType = wrapType(method.input)

0 commit comments

Comments
 (0)