From daed957a1391681e6b1d11a123c57bdc221e18d9 Mon Sep 17 00:00:00 2001 From: shaungliang abc Date: Sat, 4 Jan 2025 17:23:06 +0800 Subject: [PATCH 1/2] fix --- packages/core/src/types.ts | 1 + packages/plugin-goplus/.npmignore | 6 + packages/plugin-goplus/eslint.config.mjs | 3 + packages/plugin-goplus/package.json | 21 ++ packages/plugin-goplus/src/index.ts | 17 ++ .../plugin-goplus/src/lib/GoPlusManage.ts | 130 +++++++++++ .../src/services/GoplusSecurityService.ts | 98 ++++++++ packages/plugin-goplus/src/templates/index.ts | 209 ++++++++++++++++++ packages/plugin-goplus/tsconfig.json | 11 + packages/plugin-goplus/tsup.config.ts | 10 + 10 files changed, 506 insertions(+) create mode 100644 packages/plugin-goplus/.npmignore create mode 100644 packages/plugin-goplus/eslint.config.mjs create mode 100644 packages/plugin-goplus/package.json create mode 100644 packages/plugin-goplus/src/index.ts create mode 100644 packages/plugin-goplus/src/lib/GoPlusManage.ts create mode 100644 packages/plugin-goplus/src/services/GoplusSecurityService.ts create mode 100644 packages/plugin-goplus/src/templates/index.ts create mode 100644 packages/plugin-goplus/tsconfig.json create mode 100644 packages/plugin-goplus/tsup.config.ts diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index c07d3226b9..2ceb362100 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1295,6 +1295,7 @@ export enum ServiceType { AWS_S3 = "aws_s3", BUTTPLUG = "buttplug", SLACK = "slack", + GOPLUS_SECURITY = "goplus_security", } export enum LoggingLevel { diff --git a/packages/plugin-goplus/.npmignore b/packages/plugin-goplus/.npmignore new file mode 100644 index 0000000000..078562ecea --- /dev/null +++ b/packages/plugin-goplus/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-goplus/eslint.config.mjs b/packages/plugin-goplus/eslint.config.mjs new file mode 100644 index 0000000000..92fe5bbebe --- /dev/null +++ b/packages/plugin-goplus/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-goplus/package.json b/packages/plugin-goplus/package.json new file mode 100644 index 0000000000..6b9e66ccba --- /dev/null +++ b/packages/plugin-goplus/package.json @@ -0,0 +1,21 @@ +{ + "name": "@elizaos/plugin-goplus", + "version": "0.1.7-alpha.2", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "tsup": "^8.3.5", + "ws": "^8.18.0" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsx watch src/index.ts", + "lint": "eslint --fix --cache ." + }, + "devDependencies": { + "@types/ws": "^8.5.13", + "tsx": "^4.19.2" + } +} diff --git a/packages/plugin-goplus/src/index.ts b/packages/plugin-goplus/src/index.ts new file mode 100644 index 0000000000..d64fb3e905 --- /dev/null +++ b/packages/plugin-goplus/src/index.ts @@ -0,0 +1,17 @@ +import { Plugin } from "@elizaos/core"; +import GoplusSecurityService from "./services/GoplusSecurityService"; + +export * from "./services/GoplusSecurityService"; + + +export const goplusPlugin: Plugin = { + name: "goplus", + description: + "goplus Plugin for Eliza - Enables WebSocket communication for AI-driven market insights", + actions: [], + evaluators: [], + providers: [], + services: [new GoplusSecurityService()], +}; + +export default goplusPlugin; diff --git a/packages/plugin-goplus/src/lib/GoPlusManage.ts b/packages/plugin-goplus/src/lib/GoPlusManage.ts new file mode 100644 index 0000000000..1406e167ff --- /dev/null +++ b/packages/plugin-goplus/src/lib/GoPlusManage.ts @@ -0,0 +1,130 @@ + + +export const GoPlusType = { + EVMTOKEN_SECURITY_CHECK: "EVMTOKEN_SECURITY_CHECK", + SOLTOKEN_SECURITY_CHECK: "SOLTOKEN_SECURITY_CHECK", + SUITOKEN_SECURITY_CHECK: "SUITOKEN_SECURITY_CHECK", + RUGPULL_SECURITY_CHECK: "RUGPULL_SECURITY_CHECK", + NFT_SECURITY_CHECK: "NFT_SECURITY_CHECK", + ADRESS_SECURITY_CHECK: "ADRESS_SECURITY_CHECK", + APPROVAL_SECURITY_CHECK: "APPROVAL_SECURITY_CHECK", + ACCOUNT_ERC20_SECURITY_CHECK: "ACCOUNT_ERC20_SECURITY_CHECK", + ACCOUNT_ERC721_SECURITY_CHECK: "ACCOUNT_ERC721_SECURITY_CHECK", + ACCOUNT_ERC1155_SECURITY_CHECK: "ACCOUNT_ERC1155_SECURITY_CHECK", + SIGNATURE_SECURITY_CHECK: "SIGNATURE_SECURITY_CHECK", + URL_SECURITY_CHECK: "URL_SECURITY_CHECK", +} + +export type GoPlusType = (typeof GoPlusType)[keyof typeof GoPlusType] + +export type GoPlusParamType = { + "type": GoPlusType, + "network"?: string, + "token"?: string, + "contract"?: string, + "wallet"?: string, + "url"?: string, + "data"?: string, +} + +export class GoPlusManage { + private apiKey: string; + + constructor(apiKey: string = null) { + this.apiKey = apiKey; + } + + async requestGet(api: string) { + const myHeaders = new Headers(); + if (this.apiKey) { + myHeaders.append("Authorization", this.apiKey); + } + const url = `https://api.gopluslabs.io/${api}` + const res = await fetch(url, { + method: "GET", + headers: myHeaders, + redirect: "follow" + }) + + return await res.json(); + } + + async tokenSecurity(chainId: string, address: string) { + const api = `api/v1/token_security/${chainId}?contract_addresses=${address}`; + return await this.requestGet(api) + } + + async rugpullDetection(chainId: string, address: string) { + const api = `api/v1/rugpull_detecting/${chainId}?contract_addresses=${address}`; + return await this.requestGet(api) + } + + async solanaTokenSecurityUsingGET(address: string) { + const api = `api/v1/solana/token_security?contract_addresses=${address}`; + return await this.requestGet(api) + } + + async suiTokenSecurityUsingGET(address: string) { + const api = `api/v1/sui/token_security?contract_addresses=${address}`; + return await this.requestGet(api) + } + + async nftSecurity(chainId: string, address: string) { + const api = `api/v1/nft_security/${chainId}?contract_addresses=${address}`; + return await this.requestGet(api) + } + + async addressSecurity(address: string) { + const api = `api/v1/address_security/${address}`; + return await this.requestGet(api) + } + + async approvalSecurity(chainId: string, contract: string) { + const api = `api/v1/approval_security/${chainId}?contract_addresses=${contract}`; + return await this.requestGet(api) + } + + async erc20ApprovalSecurity(chainId: string, wallet: string) { + const api = `api/v2/token_approval_security/${chainId}?addresses=${wallet}`; + return await this.requestGet(api) + } + + async erc721ApprovalSecurity(chainId: string, wallet: string) { + const api = `api/v2/nft721_approval_security/${chainId}?addresses=${wallet}`; + return await this.requestGet(api) + } + + async erc1155ApprovalSecurity(chainId: string, wallet: string) { + const api = `api/v2/nft1155_approval_security/${chainId}?addresses=${wallet}`; + return await this.requestGet(api) + } + + async inputDecode(chainId: string, data: string) { + const body = JSON.stringify({ + chain_id: chainId, + data: data, + }) + const res = await fetch("https://api.gopluslabs.io/api/v1/abi/input_decode", { + "headers": { + "accept": "*/*", + "accept-language": "en,zh-CN;q=0.9,zh;q=0.8", + "content-type": "application/json" + }, + "body": body, + "method": "POST" + }); + return await res.json(); + } + + async dappSecurityAndPhishingSite(url: string) { + const api = `api/v1/dapp_security?url=${url}`; + const data1 = await this.requestGet(api) + + const api2 = `api/v1/phishing_site?url=${url}`; + const data2 = await this.requestGet(api2) + return { + data1, + data2 + } + } +} \ No newline at end of file diff --git a/packages/plugin-goplus/src/services/GoplusSecurityService.ts b/packages/plugin-goplus/src/services/GoplusSecurityService.ts new file mode 100644 index 0000000000..e23151e2be --- /dev/null +++ b/packages/plugin-goplus/src/services/GoplusSecurityService.ts @@ -0,0 +1,98 @@ +import { IAgentRuntime, ModelClass, Service, ServiceType, elizaLogger, generateObjectDeprecated, generateText } from "@elizaos/core"; +import { GoPlusManage, GoPlusParamType, GoPlusType } from "../lib/GoPlusManage"; +import { requestPrompt, responsePrompt } from "../templates"; + +export interface IGoplusSecurityService extends Service { + check(text: string): Promise; +} + +export class GoplusSecurityService extends Service implements IGoplusSecurityService { + private apiKey: string; + private runtime: IAgentRuntime; + getInstance(): GoplusSecurityService { + return this; + } + static get serviceType() { + return ServiceType.GOPLUS_SECURITY; + } + + initialize(runtime: IAgentRuntime): Promise { + this.runtime = runtime; + this.apiKey = runtime.getSetting("GOPLUS_API_KEY"); + return; + } + + + /** + * Connect to WebSocket and send a message + */ + async check(text: string): Promise { + try { + elizaLogger.log("check input text", text); + const obj = await generateObjectDeprecated({ + runtime: this.runtime, + context: requestPrompt(text), + modelClass: ModelClass.SMALL, // gpt-4o-mini + }) as GoPlusParamType; + + elizaLogger.log("check generateObjectDeprecated text", obj); + + const goPlusManage = new GoPlusManage(this.apiKey) + let checkResult: any; + switch(obj.type) { + case GoPlusType.EVMTOKEN_SECURITY_CHECK: + checkResult = await goPlusManage.tokenSecurity(obj.network, obj.token); + break; + case GoPlusType.SOLTOKEN_SECURITY_CHECK: + checkResult = await goPlusManage.solanaTokenSecurityUsingGET(obj.token); + break; + case GoPlusType.SUITOKEN_SECURITY_CHECK: + checkResult = await goPlusManage.suiTokenSecurityUsingGET(obj.token); + break; + case GoPlusType.RUGPULL_SECURITY_CHECK: + checkResult = await goPlusManage.rugpullDetection(obj.network, obj.contract); + break; + case GoPlusType.NFT_SECURITY_CHECK: + checkResult = await goPlusManage.nftSecurity(obj.network, obj.token); + break; + case GoPlusType.ADRESS_SECURITY_CHECK: + checkResult = await goPlusManage.addressSecurity(obj.wallet); + break; + case GoPlusType.APPROVAL_SECURITY_CHECK: + checkResult = await goPlusManage.approvalSecurity(obj.network, obj.contract); + break; + case GoPlusType.ACCOUNT_ERC20_SECURITY_CHECK: + checkResult = await goPlusManage.erc20ApprovalSecurity(obj.network, obj.wallet); + break; + case GoPlusType.ACCOUNT_ERC721_SECURITY_CHECK: + checkResult = await goPlusManage.erc721ApprovalSecurity(obj.network, obj.wallet); + break; + case GoPlusType.ACCOUNT_ERC1155_SECURITY_CHECK: + checkResult = await goPlusManage.erc1155ApprovalSecurity(obj.network, obj.wallet); + break; + case GoPlusType.SIGNATURE_SECURITY_CHECK: + checkResult = await goPlusManage.inputDecode(obj.network, obj.data); + break; + case GoPlusType.URL_SECURITY_CHECK: + checkResult = await goPlusManage.dappSecurityAndPhishingSite(obj.url); + break; + default: + throw new Error("type is invaild") + } + + elizaLogger.log("checkResult text", checkResult); + const checkResponse = await generateText({ + runtime: this.runtime, + context: responsePrompt(JSON.stringify(checkResult), text), + modelClass: ModelClass.SMALL, + }); + elizaLogger.log("checkResponse text", checkResponse); + return checkResponse + } catch (e) { + elizaLogger.error(e); + return "error"; + } + } +} + +export default GoplusSecurityService; diff --git a/packages/plugin-goplus/src/templates/index.ts b/packages/plugin-goplus/src/templates/index.ts new file mode 100644 index 0000000000..6886211d7f --- /dev/null +++ b/packages/plugin-goplus/src/templates/index.ts @@ -0,0 +1,209 @@ +export const requestPrompt = (text:string) => `You are a security action detector for blockchain interactions. Your task is to analyze the user's input text and determine which security checks are needed. + +Text to analyze:""" +${text} +""" +If the user is not sure which network the sent address belongs to, then according to the following logic initially determine which network the user sends the address belongs to. + +Detection Logic: +1. First check if address starts with "0x": + - If yes: + - If length is 42 -> EVM address + - If the address has a non-standard suffix (e.g., " ::s::S "), you may treat the base address (without the suffix) as the -> SUI address. , but the full address including the suffix should be placed in the "token" field. + - If no: + - If length is 44 and starts with letter -> Solana address + +2. If none of the above patterns match: + - -> EVM address +3. If detection is EVM address: + - -> EVM address + +Networks format +EVM: 0x26e550ac11b26f78a04489d5f20f24e3559f7dd9 +Solana: 9DHe3pycTuymFk4H4bbPoAJ4hQrr2kaLDF6J6aAKpump +SUI: 0xea65bb5a79ff34ca83e2995f9ff6edd0887b08da9b45bf2e31f930d3efb82866::s::S + +After determining which action to use, please reply in the json format below the action. + +Available actions: +- [EVMTOKEN_SECURITY_CHECK]: For checking ERC20 token contract security + Description: Security assessment for tokens on EVM-compatible chains (like Ethereum, BSC), including contract risks, permission configurations, transaction mechanisms + Keywords: EVM token, ETH token, BEP20, smart contract, ERC20 security, on-chain token + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "EVMTOKEN_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, Optimism:10, Cronos:25, BSC:56, Gnosis:100, HECO:128, Polygon:137, Fantom:250, KCC:321, zkSync Era:324, ETHW:10001, FON:201022, Arbitrum:42161, Avalanche:43114, Linea Mainnet:59144, Base:8453, Tron:tron, Scroll:534352, opBNB:204, Mantle:5000, ZKFair:42766, Blast:81457, Manta Pacific:169, Berachain Artio Testnet:80085, Merlin:4200, Bitlayer Mainnet:200901, zkLink Nova:810180, X Layer Mainnet:196) +"token": "" , +} +\`\`\` + + +- [SOLTOKEN_SECURITY_CHECK]: For checking SPL token contract security + Description: Security audit for Solana-based tokens, analyzing program authority settings, account states, transfer restrictions and other security factors + Keywords: Solana token, SOL token, SPL token, Solana security, SOL contract + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "SOLTOKEN_SECURITY_CHECK" +"token": "" , +} +\`\`\` + + +- [SUITOKEN_SECURITY_CHECK]: For checking Sui token contract security + Description: Security inspection for tokens on SUI blockchain, examining token contract permissions, transaction restrictions, minting mechanisms and other security configurations + Keywords: SUI token, SUI coins, MOVE token, SUI contract, SUI security + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "SUITOKEN_SECURITY_CHECK" +"token": "" , +} +\`\`\` + + +- [RUGPULL_SECURITY_CHECK]: + Description: Detection of potential rugpull risks in tokens/projects, including contract permissions, liquidity locks, team holdings and other risk factors + Keywords: rugpull risk, token security, project reliability, contract risk, liquidity, team wallet + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "RUGPULL_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, BSC:56) +"contract": "" | null, +} +\`\`\` + + +- [NFT_SECURITY_CHECK] + Description: Security analysis of NFT project smart contracts, including minting mechanisms, trading restrictions, permission settings + Keywords: NFT security, digital collectibles, minting risk, NFT trading, NFT contract + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "NFT_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, Optimism:10, Cronos:25, BSC:56, Gnosis:100, HECO:128, Polygon:137, Fantom:250, KCC:321, zkSync Era:324, FON:201022, Arbitrum:42161, Avalanche:43114, Linea Mainnet:59144, Base:8453, Mantle:5000) +"token": "" | null, +} +\`\`\` + + +- [ADRESS_SECURITY_CHECK] + Description: Analysis of specific address security status, detecting known malicious addresses, scam addresses or high-risk addresses + Keywords: wallet security, malicious address, scam address, blacklist + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "ADRESS_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, Optimism:10, Cronos:25, BSC:56, Gnosis:100, HECO:128, Polygon:137, Fantom:250, KCC:321, zkSync Era:324, FON:201022, Arbitrum:42161, Avalanche:43114, Linea Mainnet:59144, Tron:tron, Scroll:534352, opBNB:204, Base:8453, Solana:solana) +"wallet": "" | null, +} +\`\`\` + + +- [APPROVAL_SECURITY_CHECK] + Description: Examination of smart contract approval settings, evaluating risk levels of third-party authorizations + Keywords: approval check, contract authorization, spending approval, approval risk + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "APPROVAL_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, BSC: 56, OKC: 66, Heco: 128, Polygon: 137, Fantom:250, Arbitrum: 42161, Avalanche: 43114) +"contract": "" | null, +} +\`\`\` + + +- [ACCOUNT_ERC20_SECURITY_CHECK] + Description: Security assessment of account-related ERC20 token transactions and holdings + Keywords: ERC20, token account, token security, account detection + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "ACCOUNT_ERC20_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, Optimism:10, Cronos:25, BSC:56, Gnosis:100, HECO:128, Polygon:137, Fantom:250, KCC:321, zkSync Era:324, FON:201022, Arbitrum:42161, Avalanche:43114, Linea Mainnet:59144, Base:8453, Mantle:5000) +"wallet": "" | null, +} +\`\`\` + + +- [ACCOUNT_ERC721_SECURITY_CHECK] + Description: Security analysis of account's ERC721 NFT assets + Keywords: ERC721, NFT account, NFT assets, collectibles security + Respond with a JSON markdown block containing only the extracted values: +\`\`\`json +{ +"type": "ACCOUNT_ERC721_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, Optimism:10, Cronos:25, BSC:56, Gnosis:100, HECO:128, Polygon:137, Fantom:250, KCC:321, zkSync Era:324, FON:201022, Arbitrum:42161, Avalanche:43114, Linea Mainnet:59144, Base:8453, Mantle:5000) +"wallet": "" | null, +} +\`\`\` + + +- [ACCOUNT_ERC1155_SECURITY_CHECK] + Description: Security evaluation of account's ERC1155 multi-token standard assets + Keywords: ERC1155, multi-token, hybrid assets, account security + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "ACCOUNT_ERC1155_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum:1, Optimism:10, Cronos:25, BSC:56, Gnosis:100, HECO:128, Polygon:137, Fantom:250, KCC:321, zkSync Era:324, FON:201022, Arbitrum:42161, Avalanche:43114, Linea Mainnet:59144, Base:8453, Mantle:5000) +"wallet": "" | null, +} +\`\`\` + + +- [SIGNATURE_SECURITY_CHECK] + Description: Verification of signature security, preventing signature fraud risks + Keywords: signature verification, message signing, signature risk, signature fraud + Respond with a JSON markdown block containing only the extracted values: + +\`\`\`json +{ +"type": "SIGNATURE_SECURITY_CHECK" +"network": "1", //default: 1 (Ethereum: 1, Cronos:25, BSC: 56, Heco: 128, Polygon: 137, Fantom:250, KCC: 321, Arbitrum: 42161, Avalanche: 43114) +"data": "" | null, +} +\`\`\` + + +- [URL_SECURITY_CHECK] + Description: Detection of known phishing websites, malicious sites or other security risks in URLs + Keywords: link detection, phishing website, malicious URL, website security + Respond with a JSON markdown block containing only the extracted values: +\`\`\`json +{ +"type": "URL_SECURITY_CHECK" +"url": "" | null, +} +\`\`\` + +Extract the necessary information(All fields present in the json are important information) and choose the appropriate action(s) based on the text. Return the JSON response following the format above. +important: do not response anything except json` + + + +export const responsePrompt = (apiresult: string, text:string) => `You are a security action detector for blockchain interactions. Your task is to analyze the security API’s response from GoPlus and summary the API result. +API to analyze:“”" +${apiresult} +“”" +user’s request:“” +${text} +“” +Instructions: +1. **Identify the Action**: Analyze the API response to determine which specific action it relates to. +2. **Extract Relevant Information**: From the action and its parameters, extract and highlight the key details. +3. **Formulate a Clear Response**: Combine the action type, extracted information, and an analysis of the results. Provide a clear, concise response based on the security context. Focus on delivering the most relevant answer without unnecessary detail. +- Only reply with your conclusion. +- Do not discuss the safety aspects of the action; just focus on identifying and pointing out any risks. +- Tailor your response to the user’s request, focusing on their specific query.` \ No newline at end of file diff --git a/packages/plugin-goplus/tsconfig.json b/packages/plugin-goplus/tsconfig.json new file mode 100644 index 0000000000..33e9858f48 --- /dev/null +++ b/packages/plugin-goplus/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "./src", + "declaration": true + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/packages/plugin-goplus/tsup.config.ts b/packages/plugin-goplus/tsup.config.ts new file mode 100644 index 0000000000..c7bf2d61a7 --- /dev/null +++ b/packages/plugin-goplus/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm"], + dts: true, + sourcemap: true, + splitting: false, + clean: true, +}); From 9f0cc2803379b770f2e50d8ab5667c94d6617ce7 Mon Sep 17 00:00:00 2001 From: beekeeper Date: Mon, 6 Jan 2025 20:26:06 +0800 Subject: [PATCH 2/2] Update index.ts --- packages/plugin-goplus/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-goplus/src/index.ts b/packages/plugin-goplus/src/index.ts index d64fb3e905..3af4f75627 100644 --- a/packages/plugin-goplus/src/index.ts +++ b/packages/plugin-goplus/src/index.ts @@ -7,7 +7,7 @@ export * from "./services/GoplusSecurityService"; export const goplusPlugin: Plugin = { name: "goplus", description: - "goplus Plugin for Eliza - Enables WebSocket communication for AI-driven market insights", + "goplus Plugin for Eliza - Enables on-chain security checks", actions: [], evaluators: [], providers: [],