diff --git a/src/services/hypernativeApi.ts b/src/services/hypernativeApi.ts index d5e74d4..dac0afb 100644 --- a/src/services/hypernativeApi.ts +++ b/src/services/hypernativeApi.ts @@ -15,33 +15,6 @@ class HypernativeApi { this.clientSecret = clientSecret } - // Python source for the python_processing node in rate-revert agents. - // Tracks consecutive revert count in the account-wide KV store so that the - // alert only fires after 100 consecutive reverts. - private static buildRevertPythonSource(kvKey: string): string { - return `def my_function(extracted_variables): - """Your custom Python logic goes here. - The \`extracted_variables\` dictionary - contains variables from previous nodes. - The return value will be stored in the - variable defined below.""" - is_null = extracted_variables["is_null"] - key = "${kvKey}" - base = "https://api.hypernative.xyz/custom-agents/values" - - if is_null == 1: - existing = hn_api_get(f"{base}/{key}").json()["data"] - if existing is None: - count = 1 - else: - count = int(existing) + 1 - else: - count = 0 - - hn_api_put(f"{base}/{key}", {"value": str(count)}) - return count` - } - // Mapping of viem chain names to Hypernative chain strings private static chainNameToHypernativeKey: { [key: string]: string } = { 'Arbitrum One': 'arbitrum', @@ -116,11 +89,6 @@ class HypernativeApi { const customAgentRule = JSON.parse(JSON.stringify(rateProviderRateRevertRule)) const chainKey = this.getValidChainNameFromViemChain(input.chain) - // Per-agent KV key for the persistent revert counter (account-wide store) - const kvKey = `revert_count_${chainKey}_${input.contractAddress.slice(-4).toLowerCase()}` - const pythonSource = HypernativeApi.buildRevertPythonSource(kvKey) - const pythonSourceB64 = Buffer.from(pythonSource, 'utf-8').toString('base64') - // Modify the rule based on input customAgentRule.rule.chain = chainKey customAgentRule.rule.ruleString = input.ruleString @@ -129,29 +97,31 @@ class HypernativeApi { customAgentRule.agentName = input.agentName customAgentRule.rule.customDescription = input.ruleString + // Update all three gcr extractions (block offsets 0, -25, -50) with the + // target contract address & chain. const extractions = customAgentRule.rule.conditions[1].operands[0].variable_extraction - // [3] gcr node - extractions[3].contract_address = input.contractAddress.toLowerCase() - extractions[3].chain = chainKey - // [5] python_processing node — inject per-agent source - const pythonExt = extractions.find((e: any) => e.type === 'python_processing') - if (pythonExt) pythonExt.source_code = pythonSourceB64 + for (const ext of extractions) { + if (ext.type === 'gcr') { + ext.contract_address = input.contractAddress.toLowerCase() + ext.chain = chainKey + } + } customAgentRule.rule.conditions[1].operands[0].eval.custom_description = input.ruleString - customAgentRule.rule.time_based_trigger.chain = chainKey - // Look up graph nodes by type so positional shifts don't break the wiring - const nodesByType: Record = {} + // Update graph nodes — there are 3 read-contract-nodes (one per sample block). for (const node of customAgentRule.graphData.nodes) { - nodesByType[node.type] = node + if (node.type === 'time-based-node') { + node.data.chain = chainKey + } else if (node.type === 'read-contract-node') { + node.data.chain = chainKey + node.data.contractAddress = input.contractAddress + node.data.contractAddressAlias = input.contractAddress + } else if (node.type === 'send-alert-node') { + node.data.message = input.ruleString + } } - nodesByType['time-based-node'].data.chain = chainKey - nodesByType['read-contract-node'].data.chain = chainKey - nodesByType['read-contract-node'].data.contractAddress = input.contractAddress - nodesByType['read-contract-node'].data.contractAddressAlias = input.contractAddress - nodesByType['send-alert-node'].data.message = input.ruleString - nodesByType['python-function-node'].data.pythonCode = pythonSourceB64 const requestBody = customAgentRule diff --git a/src/utils/hypernative/rate-provider-rate-revert.ts b/src/utils/hypernative/rate-provider-rate-revert.ts index 4bc0b65..cd74a4e 100644 --- a/src/utils/hypernative/rate-provider-rate-revert.ts +++ b/src/utils/hypernative/rate-provider-rate-revert.ts @@ -6,7 +6,7 @@ export const rateProviderRateRevertRule = { chain: 'ethereum', triggerType: 'time_based_trigger', severity: 'medium', - contractAddress: '0x565986Cc0c7507d45062e9Bd805328596c294559', + contractAddress: '0x0000000000000000000000000000000000000000', involvedAssets: {}, secrets: {}, input: [], @@ -58,7 +58,7 @@ export const rateProviderRateRevertRule = { }, { type: 'gcr', - contract_address: '0xe1b1e024f4bc01bdde23e891e081b76a1a914ddd', + contract_address: '0x0000000000000000000000000000000000000000', operands: [], operator: 'nop', block_offset: 0, @@ -67,36 +67,70 @@ export const rateProviderRateRevertRule = { output_data_type: ['uint256'], output_index: 'output_arg_0', func_sig: 'getRate()', - chain: 'base', + chain: 'ethereum', var_name: 'getRateOutput', contract_function_object: null, idl_json: null, abi_string: null, + type_arguments: [], + generic_type_params: [], }, { - type: 'json_processing', - json_path: 'Z2V0UmF0ZU91dHB1dD1udWxsID8gMTow', - json_path_engine: 'jsonata', - var_name: 'is_null', + type: 'gcr', + contract_address: '0x0000000000000000000000000000000000000000', + operands: [], + operator: 'nop', + block_offset: -25, + input: [], + input_data_type: [], + output_data_type: ['uint256'], + output_index: 'output_arg_0', + func_sig: 'getRate()', + chain: 'ethereum', + var_name: 'getRateOutput_1', + contract_function_object: null, + idl_json: null, + abi_string: null, + type_arguments: [], + generic_type_params: [], }, { - type: 'python_processing', - source_code: '', - var_name: 'consecutive_revert_count', - entry_point: 'my_function', + type: 'gcr', + contract_address: '0x0000000000000000000000000000000000000000', + operands: [], + operator: 'nop', + block_offset: -50, + input: [], + input_data_type: [], + output_data_type: ['uint256'], + output_index: 'output_arg_0', + func_sig: 'getRate()', + chain: 'ethereum', + var_name: 'getRateOutput_2', + contract_function_object: null, + idl_json: null, + abi_string: null, + type_arguments: [], + generic_type_params: [], }, { type: 'json_processing', - json_path: 'Y29uc2VjdXRpdmVfcmV2ZXJ0X2NvdW50ID49IDEwMA==', + json_path: 'Z2V0UmF0ZU91dHB1dD1udWxsID8gMTowZ2V0UmF0ZU91dHB1dF8xPW51bGwgPyAxOjBnZXRSYXRlT3V0cHV0XzI9bnVsbCA/IDE6MA==', + var_name: 'is_null', json_path_engine: 'jsonata', + }, + { + type: 'json_processing', + json_path: 'aXNfbnVsbCA9IHRydWU=', var_name: 'condition_0', + json_path_engine: 'jsonata', }, ], eval: { sym_expression: 'condition_0', operator: 'compare_exact', operands: [true], - custom_description: 'On Base - the getRate() function reverted. contract 0xe1b1..4ddd', + custom_description: '', }, }, ], @@ -108,7 +142,7 @@ export const rateProviderRateRevertRule = { typeArguments: [], genericTypeParams: [], advanced: ['customDescription'], - customDescription: 'On Base - the getRate() function reverted. contract 0xe1b1..4ddd', + customDescription: '', ruleString: '', }, severity: 'Medium', @@ -131,24 +165,29 @@ export const rateProviderRateRevertRule = { source: '76ad1bf3-1f12-45d9-a28e-043fd99d0ca8', target: '07b6cf44-db10-47b8-8a89-5c2b43d775e6', }, - { - id: 'xy-edge__07b6cf44-db10-47b8-8a89-5c2b43d775e6-6c41586c-ced7-4db6-86cb-fe2f85f73f9e', - source: '07b6cf44-db10-47b8-8a89-5c2b43d775e6', - target: '6c41586c-ced7-4db6-86cb-fe2f85f73f9e', - }, { id: 'xy-edge__6aecd52f-8b2f-49f5-9707-12952ef36557-b6d012b6-03e1-4295-9389-a2288fbfb211', source: '6aecd52f-8b2f-49f5-9707-12952ef36557', target: 'b6d012b6-03e1-4295-9389-a2288fbfb211', }, { - id: 'xy-edge__6c41586c-ced7-4db6-86cb-fe2f85f73f9e-cf43c1f0-b099-4f21-af4c-4925c07d7ec5', - source: '6c41586c-ced7-4db6-86cb-fe2f85f73f9e', - target: 'cf43c1f0-b099-4f21-af4c-4925c07d7ec5', + id: 'xy-edge__07b6cf44-db10-47b8-8a89-5c2b43d775e6-87aaa6f8-24f8-47f1-9a59-da2d150d4976', + source: '07b6cf44-db10-47b8-8a89-5c2b43d775e6', + target: '87aaa6f8-24f8-47f1-9a59-da2d150d4976', + }, + { + id: 'xy-edge__87aaa6f8-24f8-47f1-9a59-da2d150d4976-567e4cf6-ab82-43e1-a47c-1e70abf2d99a', + source: '87aaa6f8-24f8-47f1-9a59-da2d150d4976', + target: '567e4cf6-ab82-43e1-a47c-1e70abf2d99a', }, { - id: 'xy-edge__cf43c1f0-b099-4f21-af4c-4925c07d7ec5-6aecd52f-8b2f-49f5-9707-12952ef36557', - source: 'cf43c1f0-b099-4f21-af4c-4925c07d7ec5', + id: 'xy-edge__567e4cf6-ab82-43e1-a47c-1e70abf2d99a-6c41586c-ced7-4db6-86cb-fe2f85f73f9e', + source: '567e4cf6-ab82-43e1-a47c-1e70abf2d99a', + target: '6c41586c-ced7-4db6-86cb-fe2f85f73f9e', + }, + { + id: 'xy-edge__6c41586c-ced7-4db6-86cb-fe2f85f73f9e-6aecd52f-8b2f-49f5-9707-12952ef36557', + source: '6c41586c-ced7-4db6-86cb-fe2f85f73f9e', target: '6aecd52f-8b2f-49f5-9707-12952ef36557', }, ], @@ -166,24 +205,27 @@ export const rateProviderRateRevertRule = { height: 107, }, position: { - x: 1000, - y: -227, + x: 907.4151541834707, + y: -320.85313137566, }, }, { id: '07b6cf44-db10-47b8-8a89-5c2b43d775e6', data: { alias: 'getRateOutput', - chain: 'base', + chain: 'ethereum', input: [], funcSig: 'getRate()', aliasType: 'uint256', + moduleName: '', + blockOffset: 0, description: '', outputIndex: 0, inputDataType: [], outputDataType: ['uint256'], - contractAddress: '0xe1b1e024f4bc01bdde23e891e081b76a1a914ddd', - contractAddressAlias: '0xe1..4ddd', + contractAddress: '0x0000000000000000000000000000000000000000', + genericTypeParams: [], + contractAddressAlias: '0x0000000000000000000000000000000000000000', contractFunctionObject: { name: 'getRate', type: 'function', @@ -213,7 +255,7 @@ export const rateProviderRateRevertRule = { id: '6c41586c-ced7-4db6-86cb-fe2f85f73f9e', data: { alias: 'is_null', - formula: '{{getRateOutput}}=null ? 1:0', + formula: '{{getRateOutput}}=null ? 1:0\n{{getRateOutput_1}}=null ? 1:0\n{{getRateOutput_2}}=null ? 1:0', aliasType: 'boolean', description: '', }, @@ -223,16 +265,16 @@ export const rateProviderRateRevertRule = { height: 157, }, position: { - x: 1093, - y: 68, + x: 858.058774303253, + y: 329.7940661597082, }, }, { id: '6aecd52f-8b2f-49f5-9707-12952ef36557', data: { - valueA: 'consecutive_revert_count', - valueB: '100', - condition: 'gte', + valueA: 'is_null', + valueB: 'true', + condition: 'compare_exact', description: '', valueAMultiplier: 0, valueBMultiplier: 0, @@ -244,14 +286,14 @@ export const rateProviderRateRevertRule = { height: 92, }, position: { - x: 1223, - y: 299.82419776916504, + x: 1277.5362790426132, + y: 334.06790786568956, }, }, { id: 'b6d012b6-03e1-4295-9389-a2288fbfb211', data: { - message: 'On Base - the getRate() function reverted. contract 0xe1b1..4ddd', + message: '', description: '', }, type: 'send-alert-node', @@ -260,27 +302,92 @@ export const rateProviderRateRevertRule = { height: 87, }, position: { - x: 1275, - y: 455, + x: 1277.536571118261, + y: 478.30474714902357, }, }, { - id: 'cf43c1f0-b099-4f21-af4c-4925c07d7ec5', + id: '87aaa6f8-24f8-47f1-9a59-da2d150d4976', data: { - alias: 'consecutive_revert_count', - aliasType: 'number', - entryPoint: 'my_function', - pythonCode: '', + alias: 'getRateOutput_1', + chain: 'ethereum', + input: [], + funcSig: 'getRate()', + aliasType: 'uint256', + moduleName: '', + blockOffset: 25, description: '', + outputIndex: 0, + inputDataType: [], + outputDataType: ['uint256'], + contractAddress: '0x0000000000000000000000000000000000000000', + genericTypeParams: [], + contractAddressAlias: '0x0000000000000000000000000000000000000000', + contractFunctionObject: { + name: 'getRate', + type: 'function', + inputs: [], + funcSig: 'getRate()', + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, }, - type: 'python-function-node', + type: 'read-contract-node', measured: { width: 269, - height: 111, + height: 341, + }, + position: { + x: 1032.2185887768808, + y: -92.72228338293468, + }, + }, + { + id: '567e4cf6-ab82-43e1-a47c-1e70abf2d99a', + data: { + alias: 'getRateOutput_2', + chain: 'ethereum', + input: [], + funcSig: 'getRate()', + aliasType: 'uint256', + moduleName: '', + blockOffset: 50, + description: '', + outputIndex: 0, + inputDataType: [], + outputDataType: ['uint256'], + contractAddress: '0x0000000000000000000000000000000000000000', + genericTypeParams: [], + contractAddressAlias: '0x0000000000000000000000000000000000000000', + contractFunctionObject: { + name: 'getRate', + type: 'function', + inputs: [], + funcSig: 'getRate()', + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + }, + type: 'read-contract-node', + measured: { + width: 269, + height: 341, }, position: { - x: 1414.49634369287, - y: 149.54816042047526, + x: 1348.5407460279084, + y: -89.07579005409917, }, }, ],