Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/cre-sdk-examples/src/workflows/on-chain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
encodeCallMsg,
getNetwork,
type HTTPSendRequester,
isChainSelectorSupported,
LAST_FINALIZED_BLOCK_NUMBER,
ok,
Runner,
Expand Down Expand Up @@ -56,6 +57,12 @@ const onCronTrigger = (runtime: Runtime<Config>) => {

// Get the first EVM configuration from the list
const evmConfig = runtime.config.evms[0]

// Make sure we try to run on supported chain
if (!isChainSelectorSupported(evmConfig.chainSelectorName)) {
throw new Error(`Chain selector name: ${evmConfig.chainSelectorName} is not supported.`)
}

const network = getNetwork({
chainFamily: 'evm',
chainSelectorName: evmConfig.chainSelectorName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ export class ClientCapability {
static readonly CAPABILITY_NAME = 'evm'
static readonly CAPABILITY_VERSION = '1.0.0'

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

constructor(private readonly chainSelector?: bigint) {}
constructor(private readonly ChainSelector: bigint) {}

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

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

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

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

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

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

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

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

const capabilityResponse = runtime.callCapability<EstimateGasRequest, EstimateGasReply>({
capabilityId,
Expand Down Expand Up @@ -311,10 +303,8 @@ export class ClientCapability {
)
}

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

const capabilityResponse = runtime.callCapability<
GetTransactionByHashRequest,
Expand Down Expand Up @@ -354,10 +344,8 @@ export class ClientCapability {
)
}

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

const capabilityResponse = runtime.callCapability<
GetTransactionReceiptRequest,
Expand Down Expand Up @@ -394,10 +382,8 @@ export class ClientCapability {
payload = fromJson(HeaderByNumberRequestSchema, input as HeaderByNumberRequestJson)
}

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

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

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

const capabilityResponse = runtime.callCapability<RegisterLogTrackingRequest, Empty>({
capabilityId,
Expand Down Expand Up @@ -471,10 +455,8 @@ export class ClientCapability {
)
}

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

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

logTrigger(config: FilterLogTriggerRequestJson): ClientLogTrigger {
// Include chainSelector in capability ID for routing when specified
const capabilityId = this.chainSelector
? `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.chainSelector}@${ClientCapability.CAPABILITY_VERSION}`
: ClientCapability.CAPABILITY_ID
return new ClientLogTrigger(config, capabilityId, 'LogTrigger')
// Include all labels in capability ID for routing when specified
const capabilityId = `${ClientCapability.CAPABILITY_NAME}:ChainSelector:${this.ChainSelector}@${ClientCapability.CAPABILITY_VERSION}`
return new ClientLogTrigger(config, capabilityId, 'LogTrigger', this.ChainSelector)
}

writeReport(
Expand All @@ -519,10 +499,8 @@ export class ClientCapability {
)
}

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

const capabilityResponse = runtime.callCapability<WriteReportRequest, WriteReportReply>({
capabilityId,
Expand Down Expand Up @@ -551,6 +529,7 @@ class ClientLogTrigger implements Trigger<Log, Log> {
config: FilterLogTriggerRequest | FilterLogTriggerRequestJson,
private readonly _capabilityId: string,
private readonly _method: string,
private readonly ChainSelector: bigint,
) {
// biome-ignore lint/suspicious/noExplicitAny: Needed for runtime type checking of protocol buffer messages
this.config = (config as any).$typeName
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { describe, expect, it } from 'bun:test'
import { Mode } from '@cre/generated/sdk/v1alpha/sdk_pb'
import { processLabels } from '../label-utils'

describe('Multi-Label Generator Test', () => {
it('should process multiple label types correctly', () => {
// Create a mock capability metadata with all 5 label types
const mockCapOption: any = {
mode: Mode.DON,
capabilityId: 'multi-label-test@1.0.0',
labels: {
ChainSelector: {
kind: {
case: 'uint64Label',
value: {
defaults: {
'ethereum-mainnet': 5009297550715157269n,
'polygon-mainnet': 4051577828743386545n,
},
},
},
},
Environment: {
kind: {
case: 'stringLabel',
value: {
defaults: {
production: 'prod',
staging: 'stage',
development: 'dev',
},
},
},
},
RegionId: {
kind: {
case: 'uint32Label',
value: {
defaults: {
'us-east-1': 1,
'eu-west-1': 2,
'ap-southeast-1': 3,
},
},
},
},
Offset: {
kind: {
case: 'int32Label',
value: {
defaults: {
'negative-offset': -100,
'zero-offset': 0,
'positive-offset': 100,
},
},
},
},
Timestamp: {
kind: {
case: 'int64Label',
value: {
defaults: {
past: -1234567890n,
epoch: 0n,
future: 1234567890n,
},
},
},
},
},
}

// Process labels
const labels = processLabels(mockCapOption)

// Verify we got all 5 labels
expect(labels).toHaveLength(5)

// Verify ChainSelector label
const chainSelector = labels.find((l) => l.name === 'ChainSelector')
expect(chainSelector).toBeDefined()
expect(chainSelector?.type).toBe('bigint')
expect(chainSelector?.tsType).toBe('bigint')
expect(chainSelector?.defaults).toEqual({
'ethereum-mainnet': 5009297550715157269n,
'polygon-mainnet': 4051577828743386545n,
})

// Verify Environment label
const environment = labels.find((l) => l.name === 'Environment')
expect(environment).toBeDefined()
expect(environment?.type).toBe('string')
expect(environment?.tsType).toBe('string')
expect(environment?.defaults).toEqual({
production: 'prod',
staging: 'stage',
development: 'dev',
})

// Verify RegionId label (uint32)
const regionId = labels.find((l) => l.name === 'RegionId')
expect(regionId).toBeDefined()
expect(regionId?.type).toBe('number')
expect(regionId?.tsType).toBe('number')
expect(regionId?.defaults).toEqual({
'us-east-1': 1,
'eu-west-1': 2,
'ap-southeast-1': 3,
})

// Verify Offset label (int32)
const offset = labels.find((l) => l.name === 'Offset')
expect(offset).toBeDefined()
expect(offset?.type).toBe('number')
expect(offset?.tsType).toBe('number')
expect(offset?.defaults).toEqual({
'negative-offset': -100,
'zero-offset': 0,
'positive-offset': 100,
})

// Verify Timestamp label (int64)
const timestamp = labels.find((l) => l.name === 'Timestamp')
expect(timestamp).toBeDefined()
expect(timestamp?.type).toBe('bigint')
expect(timestamp?.tsType).toBe('bigint')
expect(timestamp?.defaults).toEqual({
past: -1234567890n,
epoch: 0n,
future: 1234567890n,
})
})
})
14 changes: 4 additions & 10 deletions packages/cre-sdk/src/generator/generate-action.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { DescMethod } from '@bufbuild/protobuf'
import { generateCapabilityIdLogic, type ProcessedLabel } from './label-utils'
import { wrapType } from './utils'

/**
Expand All @@ -7,24 +8,17 @@ import { wrapType } from './utils'
* @param method - The method descriptor
* @param methodName - The camelCase method name
* @param capabilityClassName - The class name of the capability object
* @param hasChainSelector - Whether this capability supports chainSelector routing
* @param labels - Array of processed labels for this capability
* @returns The generated action method code
*/
export function generateActionMethod(
method: DescMethod,
methodName: string,
capabilityClassName: string,
hasChainSelector: boolean = false,
labels: ProcessedLabel[],
modePrefix: string,
): string {
const capabilityIdLogic = hasChainSelector
? `
// Include chainSelector in capability ID for routing when specified
const capabilityId = this.chainSelector
? \`\${${capabilityClassName}.CAPABILITY_NAME}:ChainSelector:\${this.chainSelector}@\${${capabilityClassName}.CAPABILITY_VERSION}\`
: ${capabilityClassName}.CAPABILITY_ID;`
: `
const capabilityId = ${capabilityClassName}.CAPABILITY_ID;`
const capabilityIdLogic = generateCapabilityIdLogic(labels, capabilityClassName)

// Check if we have wrapped types
const wrappedInputType = wrapType(method.input)
Expand Down
Loading
Loading