├── .github ├── checkov.yml ├── cspell.json ├── eslintrc.js ├── exemptions.md ├── gitleaks.toml ├── markdown-link-check.json ├── markdownlint.json ├── proselintrc.json ├── secretlintrc.json └── workflows │ ├── mega-linter.yml │ ├── npm-audit.yml │ └── npm-test.yml ├── .gitignore ├── 47998e45-a502-4849-8fc2-b70af9681423-megalinter_file_names_cspell.txt ├── 84eef9f1-ed93-4209-9929-cf8d606120eb-megalinter_file_names_cspell.txt ├── README.md ├── asset-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ ├── Comptroller.json │ └── cErc20.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ ├── test-utils.js │ └── utils.js ├── comp-delegations-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── README.md ├── abi │ ├── CompERC20.json │ └── GovernorBravo.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ └── agent.spec.js ├── ctoken-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ ├── Comptroller.json │ └── cErc20.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ ├── test-utils.js │ └── utils.js ├── defender ├── .eslintrc.js ├── .gitignore ├── README.md ├── ctoken_monitor │ ├── abis │ │ └── sentinel-1.json.abi │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── datadog_alerts_heat_map │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── datadog_forta_bot_alerts │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── datadog_forta_detection_bot_health │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_ctoken │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_distribution │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_explorer_monitor │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_governance │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_large_borrows_governance │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_large_delegations │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_low_liquidity │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_multi_sig │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_oracle_price │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_underlying_asset │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_v2_liquidation_monitor_dev │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── forta_v3_liquidation_monitor_dev │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── gasless_voting_dev │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── governance_automation │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── governance_discord_alert │ ├── abis │ │ └── sentinel-1.json.abi │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── governance_discord_summary │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── governance_twitter_summary │ ├── autotask-1 │ │ ├── index.js │ │ └── twitter-api-v2 │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── changelog.md │ │ │ ├── lib │ │ │ ├── client-mixins │ │ │ │ ├── form-data.helper.d.ts │ │ │ │ ├── form-data.helper.js │ │ │ │ ├── oauth1.helper.d.ts │ │ │ │ ├── oauth1.helper.js │ │ │ │ ├── oauth2.helper.d.ts │ │ │ │ ├── oauth2.helper.js │ │ │ │ ├── request-handler.helper.d.ts │ │ │ │ ├── request-handler.helper.js │ │ │ │ ├── request-maker.mixin.d.ts │ │ │ │ ├── request-maker.mixin.js │ │ │ │ ├── request-param.helper.d.ts │ │ │ │ └── request-param.helper.js │ │ │ ├── client.base.d.ts │ │ │ ├── client.base.js │ │ │ ├── client.subclient.d.ts │ │ │ ├── client.subclient.js │ │ │ ├── client │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.js │ │ │ │ ├── readonly.d.ts │ │ │ │ ├── readonly.js │ │ │ │ ├── readwrite.d.ts │ │ │ │ └── readwrite.js │ │ │ ├── globals.d.ts │ │ │ ├── globals.js │ │ │ ├── helpers.d.ts │ │ │ ├── helpers.js │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ ├── paginators │ │ │ │ ├── TwitterPaginator.d.ts │ │ │ │ ├── TwitterPaginator.js │ │ │ │ ├── dm.paginator.v1.d.ts │ │ │ │ ├── dm.paginator.v1.js │ │ │ │ ├── followers.paginator.v1.d.ts │ │ │ │ ├── followers.paginator.v1.js │ │ │ │ ├── friends.paginator.v1.d.ts │ │ │ │ ├── friends.paginator.v1.js │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.js │ │ │ │ ├── list.paginator.v1.d.ts │ │ │ │ ├── list.paginator.v1.js │ │ │ │ ├── list.paginator.v2.d.ts │ │ │ │ ├── list.paginator.v2.js │ │ │ │ ├── mutes.paginator.v1.d.ts │ │ │ │ ├── mutes.paginator.v1.js │ │ │ │ ├── paginator.v1.d.ts │ │ │ │ ├── paginator.v1.js │ │ │ │ ├── tweet.paginator.v1.d.ts │ │ │ │ ├── tweet.paginator.v1.js │ │ │ │ ├── tweet.paginator.v2.d.ts │ │ │ │ ├── tweet.paginator.v2.js │ │ │ │ ├── user.paginator.v1.d.ts │ │ │ │ ├── user.paginator.v1.js │ │ │ │ ├── user.paginator.v2.d.ts │ │ │ │ ├── user.paginator.v2.js │ │ │ │ ├── v2.paginator.d.ts │ │ │ │ └── v2.paginator.js │ │ │ ├── plugins │ │ │ │ ├── helpers.d.ts │ │ │ │ └── helpers.js │ │ │ ├── settings.d.ts │ │ │ ├── settings.js │ │ │ ├── stream │ │ │ │ ├── TweetStream.d.ts │ │ │ │ ├── TweetStream.js │ │ │ │ ├── TweetStreamEventCombiner.d.ts │ │ │ │ ├── TweetStreamEventCombiner.js │ │ │ │ ├── TweetStreamParser.d.ts │ │ │ │ └── TweetStreamParser.js │ │ │ ├── test │ │ │ │ ├── utils.d.ts │ │ │ │ └── utils.js │ │ │ ├── types │ │ │ │ ├── auth.types.d.ts │ │ │ │ ├── auth.types.js │ │ │ │ ├── client.types.d.ts │ │ │ │ ├── client.types.js │ │ │ │ ├── entities.types.d.ts │ │ │ │ ├── entities.types.js │ │ │ │ ├── errors.types.d.ts │ │ │ │ ├── errors.types.js │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.js │ │ │ │ ├── plugins │ │ │ │ │ ├── client.plugins.types.d.ts │ │ │ │ │ ├── client.plugins.types.js │ │ │ │ │ ├── index.d.ts │ │ │ │ │ └── index.js │ │ │ │ ├── request-maker.mixin.types.d.ts │ │ │ │ ├── request-maker.mixin.types.js │ │ │ │ ├── responses.types.d.ts │ │ │ │ ├── responses.types.js │ │ │ │ ├── shared.types.d.ts │ │ │ │ ├── shared.types.js │ │ │ │ ├── v1 │ │ │ │ │ ├── dev-utilities.v1.types.d.ts │ │ │ │ │ ├── dev-utilities.v1.types.js │ │ │ │ │ ├── dm.v1.types.d.ts │ │ │ │ │ ├── dm.v1.types.js │ │ │ │ │ ├── entities.v1.types.d.ts │ │ │ │ │ ├── entities.v1.types.js │ │ │ │ │ ├── geo.v1.types.d.ts │ │ │ │ │ ├── geo.v1.types.js │ │ │ │ │ ├── index.d.ts │ │ │ │ │ ├── index.js │ │ │ │ │ ├── list.v1.types.d.ts │ │ │ │ │ ├── list.v1.types.js │ │ │ │ │ ├── streaming.v1.types.d.ts │ │ │ │ │ ├── streaming.v1.types.js │ │ │ │ │ ├── trends.v1.types.d.ts │ │ │ │ │ ├── trends.v1.types.js │ │ │ │ │ ├── tweet.v1.types.d.ts │ │ │ │ │ ├── tweet.v1.types.js │ │ │ │ │ ├── user.v1.types.d.ts │ │ │ │ │ └── user.v1.types.js │ │ │ │ └── v2 │ │ │ │ │ ├── index.d.ts │ │ │ │ │ ├── index.js │ │ │ │ │ ├── list.v2.types.d.ts │ │ │ │ │ ├── list.v2.types.js │ │ │ │ │ ├── shared.v2.types.d.ts │ │ │ │ │ ├── shared.v2.types.js │ │ │ │ │ ├── spaces.v2.types.d.ts │ │ │ │ │ ├── spaces.v2.types.js │ │ │ │ │ ├── streaming.v2.types.d.ts │ │ │ │ │ ├── streaming.v2.types.js │ │ │ │ │ ├── tweet.definition.v2.d.ts │ │ │ │ │ ├── tweet.definition.v2.js │ │ │ │ │ ├── tweet.v2.types.d.ts │ │ │ │ │ ├── tweet.v2.types.js │ │ │ │ │ ├── user.v2.types.d.ts │ │ │ │ │ └── user.v2.types.js │ │ │ ├── v1 │ │ │ │ ├── client.v1.d.ts │ │ │ │ ├── client.v1.js │ │ │ │ ├── client.v1.read.d.ts │ │ │ │ ├── client.v1.read.js │ │ │ │ ├── client.v1.write.d.ts │ │ │ │ ├── client.v1.write.js │ │ │ │ ├── media-helpers.v1.d.ts │ │ │ │ └── media-helpers.v1.js │ │ │ ├── v2-labs │ │ │ │ ├── client.v2.labs.d.ts │ │ │ │ ├── client.v2.labs.js │ │ │ │ ├── client.v2.labs.read.d.ts │ │ │ │ ├── client.v2.labs.read.js │ │ │ │ ├── client.v2.labs.write.d.ts │ │ │ │ └── client.v2.labs.write.js │ │ │ └── v2 │ │ │ │ ├── client.v2.d.ts │ │ │ │ ├── client.v2.js │ │ │ │ ├── client.v2.read.d.ts │ │ │ │ ├── client.v2.read.js │ │ │ │ ├── client.v2.write.d.ts │ │ │ │ ├── client.v2.write.js │ │ │ │ ├── includes.v2.helper.d.ts │ │ │ │ └── includes.v2.helper.js │ │ │ ├── package-lock.json │ │ │ └── package.json │ └── serverless.yml ├── package-lock.json ├── package.json ├── proposal_110_automatoooor │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── proposal_117_monitor_market_entered │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── proposal_117_monitor_mint │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── secret-example.yml ├── template_autotask_relay │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── template_autotask_relay_forta │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── template_autotask_relay_sentinel │ ├── abis │ │ └── sentinel-1.json.abi │ ├── autotask-1 │ │ └── index.js │ └── serverless.yml ├── tests │ ├── datadog_alerts_heat_map.spec.js │ ├── datadog_forta_bot_alerts.spec.js │ ├── datadog_forta_detection_bot_health.spec.js │ ├── forta_ctoken.spec.js │ ├── forta_distribution.spec.js │ ├── forta_explorer_monitor.spec.js │ ├── forta_governance.spec.js │ ├── forta_large_borrows_governance.spec.js │ ├── forta_large_delegations.spec.js │ ├── forta_low_liquidity.spec.js │ ├── forta_multi_sig.spec.js │ ├── forta_oracle_price.spec.js │ ├── forta_underlying_asset.spec.js │ ├── forta_v2_liquidation_monitor_dev.spec.js │ ├── forta_v3_liquidation_monitor_dev.spec.js │ ├── gasless_voting_dev.spec.js │ ├── governance_automation.spec.js │ ├── governance_discord_alert.spec.js │ ├── governance_discord_summary.spec.js │ ├── governance_twitter_summary.spec.js │ └── onChainResources │ │ └── DummyGovernor.sol └── yarn.lock ├── distribution ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ └── Comptroller.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ ├── test-utils.js │ └── utils.js ├── gnosis-safe-deploy ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── README.md ├── abi │ ├── .gitkeep │ ├── AgentRegistry.json │ └── AgentRegistryProxy.json ├── bot-config.json ├── config.json.example ├── package-lock.json ├── package.json ├── scripts │ ├── approveTransaction.js │ ├── deploySafe.js │ ├── executeTransaction.js │ ├── proposeFortaBot.js │ └── rejectTransaction.js └── src │ ├── agent.js │ ├── agent.spec.js │ ├── test-utils.js │ ├── utils.js │ └── utils.spec.js ├── governance ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ ├── .gitkeep │ └── GovernorBravo.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ ├── delegatesList.json │ ├── governance.js │ └── test-utils.js ├── large-borrows-governance ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ ├── CErc20.json │ ├── CompERC20.json │ └── GovernorBravo.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ └── agent.spec.js ├── liquidation-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── README.md ├── abi │ ├── Comptroller.json │ ├── OneInch.json │ └── cErc20.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ └── utils.js ├── low-liquidity-market-attack-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ ├── Comptroller.json │ └── cErc20.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ ├── test-utils.js │ └── utils.js ├── multisig-transactions-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── README.md ├── abi │ ├── Comet.json │ ├── Comptroller.json │ ├── GnosisSafe.json │ └── GovernorBravo.json ├── bot-config.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ ├── agent.spec.js │ └── utils.js ├── oracle-price-monitor ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSE ├── README.md ├── abi │ └── UniswapAnchoredView.json ├── package-lock.json ├── package.json └── src │ ├── agent.js │ └── agent.spec.js ├── package-lock.json └── package.json /.github/checkov.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # You can see all available properties here: https://github.com/bridgecrewio/checkov#configuration-using-a-config-file 3 | quiet: true 4 | skip-check: 5 | - CKV_DOCKER_2 6 | # Default forta bot triggers Docker3 error 7 | # ref: https://docs.bridgecrew.io/docs/ensure-that-a-user-for-the-container-has-been-created 8 | - CKV_DOCKER_3 9 | # GHA7 errors on custom Action triggers that we have in our repo. 10 | - CKV_GHA_7 11 | -------------------------------------------------------------------------------- /.github/cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePaths": [ 3 | "**/node_modules/**", 4 | "**/.git/**", 5 | "**/.github/**", 6 | "package-lock.json", 7 | "megalinter-reports/**", 8 | "cspell.json", 9 | "megalinter_file_names_spell.txt", 10 | "**/delegatesList.json" 11 | 12 | ], 13 | "language": "en", 14 | "noConfigSearch": true, 15 | "words": [ 16 | "aave", 17 | "addressofdeployedgnosissafe", 18 | "automatoooor", 19 | "autotask", 20 | "autotasks", 21 | "bignumber", 22 | "bulker", 23 | "calldatas", 24 | "cbtc", 25 | "ceth", 26 | "codespell", 27 | "collateralized", 28 | "configurator", 29 | "creds", 30 | "ctoken", 31 | "ctokenaddress", 32 | "datas", 33 | "firstaddress", 34 | "forta", 35 | "ierc", 36 | "jszip", 37 | "keyfile", 38 | "kvstore", 39 | "lastaddress", 40 | "liquidatable", 41 | "mult", 42 | "multicall", 43 | "newstake", 44 | "newtest", 45 | "nodebuffer", 46 | "offchain", 47 | "plusplus", 48 | "privatekeyforgnosissafeowner", 49 | "privatekeyforpolygonaccounttodeploysafe", 50 | "proposedtransactionhash", 51 | "proxiable", 52 | "pyspelling", 53 | "reporteraddress", 54 | "secondaddress", 55 | "ssot", 56 | "stablecoins", 57 | "stefanzweifel", 58 | "timelock", 59 | "twap", 60 | "typehash", 61 | "typoci", 62 | "underlyingtokenaddress", 63 | "unitroller", 64 | "unobfuscated", 65 | "usdp", 66 | "volatilities", 67 | "zipfile" 68 | ], 69 | "version": "0.2" 70 | } 71 | -------------------------------------------------------------------------------- /.github/eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 'latest', 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-plusplus': 'off', 21 | 'no-console': 'off', 22 | // When linting from the root directory, eslint doesn't check sub-directory modules 23 | // so this gives many false positives. 24 | 'import/no-unresolved': 'off', 25 | }, 26 | }, 27 | ], 28 | }; 29 | -------------------------------------------------------------------------------- /.github/exemptions.md: -------------------------------------------------------------------------------- 1 | # Reasons for ignoring certain checks 2 | 3 | ## Megalinter Disabled Linters 4 | 5 | - jscpy - CopyPaste scanning is disabled 6 | - JAVASCRIPT_STANDARD - We use eslint instead 7 | - REPOSITORY_TRIVY - Deufault Forta bot causes docker warnings. Trivy is unable to disable checks: 8 | 9 | ## Specific linter exemptions 10 | 11 | - cspell - "ignoreRegExpList": "/[0-9a-f]{8}.js/gi" - scripts/download.js will save files with this name 12 | - cspell - "ignoreRegExpList": "/[0-9a-f]{8}\\\_ABI.json/gi" - scripts/download.js will save files with this name 13 | - cspell - "ignoreRegExpList": "/0x[0-9a-f]{40}/gi" - ignore ETH addresses 14 | - cspell - "ignoreRegExpList": "/Qm[0-9a-zA-Z]{44}/g" - ignore IPFS CIDv0 addresses 15 | - cspell - "ignoreRegExpList": "/bafy[0-9a-zA-Z]{40}[0-9a-zA-Z]+/g" - ignore a subset of IPFS CIDv1 addresses 16 | 17 | - cspell - "words" - various industry words 18 | 19 | - markdownlint - "MD041" - Ignoring first-line-h1 First line in a file should be a top-level heading 20 | 21 | - markdown-link-check - "^" - False positives in autotasks/nft-minter-user-signed/README.md 22 | 23 | - proselint - typography.symbols 24 | 25 | - '...' is an approximation, use the ellipsis symbol '…'. 26 | - Use the multiplication symbol ×, not the letter x. (false positives on ETH addresses) 27 | - Use curly quotes “”, not straight quotes "". 28 | 29 | - gitleaks - '(.\*?)spec\.js$' - ignore our tests, which may have mocked keys and addresses 30 | - gitleaks - '(.\*?)defender-config\.json$' - ignore our defender-config, which may have UIDs 31 | 32 | - secretlint --secretlintignores "**/megalinter-reports/**" - ignore output folder 33 | 34 | - checkov - CKV_DOCKER_3 - Default forta bot triggers Docker3 error 35 | -------------------------------------------------------------------------------- /.github/gitleaks.toml: -------------------------------------------------------------------------------- 1 | 2 | title = "gitleaks config" 3 | 4 | [extend] 5 | # useDefault will extend the base configuration with the default gitleaks config: 6 | # https://github.com/zricethezav/gitleaks/blob/master/config/gitleaks.toml 7 | useDefault = true 8 | 9 | [allowlist] 10 | description = "Allowlisted files" 11 | paths = [ 12 | '''.automation/test''', 13 | '''megalinter-reports''', 14 | '''.github/linters''', 15 | '''node_modules''', 16 | '''.mypy_cache''', 17 | '''(.*?)gitleaks\.toml$''', 18 | '''(.*?)\.(png|jpg|gif|doc|docx|pdf|bin|xls|pyc|zip)$''', 19 | '''(go.mod|go.sum)$''', 20 | '''(.*?)\.spec\.js$''', 21 | ] 22 | regexes = [ 23 | '''0x[0-9a-fA-F]{40}''', 24 | ] 25 | -------------------------------------------------------------------------------- /.github/markdown-link-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^https://reqbin.com/req/" 5 | }, 6 | { 7 | "pattern": "^https://explorer-api.forta.network/graphql" 8 | } 9 | ], 10 | "retryOn429": true, 11 | "retryCount": 5, 12 | "aliveStatusCodes": [200, 203] 13 | } 14 | -------------------------------------------------------------------------------- /.github/markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD004": false, 3 | "MD007": { 4 | "indent": 2 5 | }, 6 | "MD013": { 7 | "line_length": 400 8 | }, 9 | "MD026": { 10 | "punctuation": ".,;:!。,;:" 11 | }, 12 | "MD029": false, 13 | "MD033": false, 14 | "MD036": false, 15 | "MD041": false, 16 | "blank_lines": false 17 | } 18 | -------------------------------------------------------------------------------- /.github/proselintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "typography.symbols": false 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/secretlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": [ 3 | { 4 | "id": "@secretlint/secretlint-rule-preset-recommend" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.github/workflows/npm-audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Custom workflow for running NPM audit 3 | name: NPM Vulnerability Checker 4 | # yamllint disable-line rule:truthy 5 | on: 6 | # Enabling manual test 7 | # REF: https://stackoverflow.com/questions/58933155/manual-workflow-triggers-in-github-actions 8 | workflow_dispatch: 9 | pull_request: 10 | branches: [master, main] 11 | types: [opened, reopened] 12 | schedule: 13 | - cron: "0 0 * * 0" # Hours, minutes, day of month, month, day of week. Set for weekly 14 | permissions: read-all 15 | 16 | jobs: 17 | npm-audit: 18 | runs-on: ubuntu-latest 19 | timeout-minutes: 5 20 | 21 | steps: 22 | - name: Checkout the repo 23 | uses: actions/checkout@v3 24 | 25 | - name: Use Node.js 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: lts/* 29 | 30 | # Looks for package.json in all sub-folders lists all outdated packages for refernce. Ignores error codes. 31 | - name: List outdated packages 32 | continue-on-error: true 33 | # Single command, all newlines are interpreted as a space 34 | run: > 35 | find . 36 | ! -path "*/node_modules/*" 37 | ! -path "*/additional_path/*" 38 | -name "package.json" 39 | -execdir pwd \; 40 | -execdir npm ci \; 41 | -execdir npm outdated \; 42 | 43 | # Looks for package.json in all sub-folders and looks for vulnerable packages. Fails on vulnerable packages. 44 | - name: Check for vulnerabilities 45 | if: always() 46 | # Single command, all newlines are interpreted as a space 47 | run: > 48 | find . ! 49 | -path "*/node_modules/*" 50 | ! -path "*/additional_path/*" 51 | -name "package.json" 52 | -execdir pwd \; 53 | -execdir npm audit {} + 54 | -------------------------------------------------------------------------------- /.github/workflows/npm-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Custom workflow for running NPM test 3 | name: NPM Test 4 | # yamllint disable-line rule:truthy 5 | on: 6 | workflow_dispatch: 7 | pull_request: 8 | branches: [master, main] 9 | types: [opened, reopened, labeled] 10 | push: 11 | branches: 12 | - main 13 | permissions: read-all 14 | 15 | jobs: 16 | npm-test: 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 5 19 | 20 | steps: 21 | - name: Checkout the repo 22 | uses: actions/checkout@v3 23 | - name: Use Node.js 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: lts/* 27 | # Looks for package.json in all sub-folders and runs all tests. 28 | - name: Run NPM test 29 | continue-on-error: true 30 | # Single command, all newlines are interpreted as a space 31 | run: > 32 | find . 33 | ! -path "*/node_modules/*" 34 | ! -path "*/additional_path/*" 35 | -name "package.json" 36 | -execdir echo "::group::Click to expand test results" \; 37 | -execdir npm ci \; 38 | -execdir npm test \; 39 | -execdir echo "::endgroup::" \; 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .vscode 3 | .env 4 | forta.config.json 5 | node_modules 6 | dist 7 | publish.log 8 | megalinter-reports/ 9 | -------------------------------------------------------------------------------- /asset-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /asset-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /asset-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /asset-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] -------------------------------------------------------------------------------- /asset-monitor/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Protocol Monitoring 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . -------------------------------------------------------------------------------- /asset-monitor/README.md: -------------------------------------------------------------------------------- 1 | # Compound cToken Underlying Asset Monitor 2 | 3 | ## Description 4 | 5 | This bot monitors the underlying asset of Compound Finance cToken contracts. First 6 | it determines which assets are deployed using upgradable proxy contracts and then it 7 | monitors those contracts for any upgrade events to detect when the implementation for 8 | a cToken's underlying asset may have changed. 9 | 10 | ## Alerts 11 | 12 | 13 | - AE-COMP-CTOKEN-ASSET-UPGRADED 14 | - Emitted for any proxy pattern specified in `bot-config.json` 15 | - Type is set to the pattern specific value in `bot-config.json` 16 | - Severity is set to the pattern specific value in `bot-config.json` 17 | - Metadata field contains: 18 | - cToken symbol 19 | - cToken address 20 | - underlyingAssetAddress 21 | - Arguments passed with event (e.g. for new implementation address) 22 | 23 | ## Testing 24 | 25 | - AAVE - 0xb505725d0d622207af8ad6bfbd2f9a5031795fe62de9163d54173fbfbbe655e4 26 | - TUSD - 0x125823f2914e4f14e06b9b1b30fe9dd9512b36354cc1f6c063118c4fe03d8287 27 | - USDP - 0xeea8b8f0f0b7125bda2f78ee2f62eb031418be78e09a2fae892eb58f13837ceb 28 | - USDC - 0xe2e40640ffd5f76538cd23660cf56f00bfebd5fe925ebad6b8067c4cee18a2c3 -------------------------------------------------------------------------------- /asset-monitor/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "contracts": { 6 | "Comptroller": { 7 | "address": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 8 | "abiFile": "Comptroller.json" 9 | }, 10 | "cTokens": { 11 | "abiFile": "cErc20.json" 12 | } 13 | }, 14 | "excludeAddresses": ["0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5"], 15 | "proxyPatterns": [ 16 | { 17 | "name": "OwnedUpgradeabilityProxy", 18 | "findingType": "Suspicious", 19 | "findingSeverity": "High", 20 | "functionSignatures": [ 21 | "implementation()", 22 | "upgradeTo(address)", 23 | "transferProxyOwnership(address)" 24 | ], 25 | "eventSignatures": ["event Upgraded(address indexed implementation)"] 26 | }, 27 | { 28 | "name": "OZ_TransparentUpgradableProxy", 29 | "findingType": "Suspicious", 30 | "findingSeverity": "High", 31 | "functionSignatures": [ 32 | "implementation()", 33 | "upgradeTo(address)", 34 | "upgradeToAndCall(address,bytes)" 35 | ], 36 | "eventSignatures": [ 37 | "event Upgraded(address indexed implementation)", 38 | "event Upgraded(address implementation)" 39 | ] 40 | }, 41 | { 42 | "name": "OZ_UpgradeableUsingUnstructuredStorageProxy", 43 | "findingType": "Suspicious", 44 | "findingSeverity": "High", 45 | "functionSignatures": [ 46 | "implementation()", 47 | "upgradeTo(address)", 48 | "proxiableUUID()" 49 | ], 50 | "eventSignatures": ["event Upgraded(address indexed implementation)"] 51 | }, 52 | { 53 | "name": "OZ_UpgradeableUsingInternalStorageProxy", 54 | "findingType": "Suspicious", 55 | "findingSeverity": "High", 56 | "functionSignatures": [ 57 | "implementation()", 58 | "UpgradeabilityProxy(string)", 59 | "upgradeTo(string)" 60 | ], 61 | "eventSignatures": ["event Upgraded(address indexed implementation)"] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /asset-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-comp-asset-monitor", 3 | "version": "0.0.4", 4 | "description": "This bot monitors the underlying asset of a Compound Finance cToken.", 5 | "scripts": { 6 | "start": "npm run start:dev", 7 | "start:prod": "forta-agent run --prod", 8 | "tx": "forta-agent run --tx", 9 | "block": "forta-agent run --block", 10 | "range": "forta-agent run --range", 11 | "file": "forta-agent run --file", 12 | "publish": "forta-agent publish", 13 | "push": "forta-agent push", 14 | "disable": "forta-agent disable", 15 | "enable": "forta-agent enable", 16 | "keyfile": "forta-agent keyfile", 17 | "test": "jest" 18 | }, 19 | "dependencies": { 20 | "forta-agent": "0.0.39", 21 | "web3-eth": "1.7.1" 22 | }, 23 | "devDependencies": { 24 | "eslint": "8.16.0", 25 | "eslint-config-airbnb-base": "15.0.0", 26 | "eslint-plugin-import": "2.26.0", 27 | "jest": "28.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /asset-monitor/src/utils.js: -------------------------------------------------------------------------------- 1 | function getAbi(abiName) { 2 | // eslint-disable-next-line global-require,import/no-dynamic-require 3 | const { abi } = require(`../abi/${abiName}`); 4 | return abi; 5 | } 6 | 7 | module.exports = { 8 | getAbi, 9 | }; 10 | -------------------------------------------------------------------------------- /comp-delegations-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /comp-delegations-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /comp-delegations-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /comp-delegations-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./abi ./abi 17 | COPY ./src ./src 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /comp-delegations-monitor/README.md: -------------------------------------------------------------------------------- 1 | # Compound Delegate Votes Governance Bot 2 | 3 | ## Description 4 | 5 | This bot monitors all DelegateVotesChanged events emitted by the COMP token contract to see if an address has been delegated enough COMP to pass significant governance thresholds. 6 | 7 | ## Alerts 8 | 9 | - AE-COMP-GOVERNANCE-DELEGATE-THRESHOLD 10 | - Fired when a delegate's balance is the minimum governance threshold level for `proposal` or `votingQuorum` 11 | - Type is always set to `Suspicious` 12 | - Severity is set to `Medium` for the proposal threshold alert and `High` for the voting quorum threshold alert 13 | - Metadata field contains: 14 | - Delegate Address 15 | - Governance threshold level that has been surpassed, which can be either `proposal` or `votingQuorum` 16 | - The minimum amount of COMP needed to pass the respective governance threshold 17 | - The amount of COMP owned by the delegate address -------------------------------------------------------------------------------- /comp-delegations-monitor/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "compERC20": { 6 | "address": "0xc00e94Cb662C3520282E6f5717214004A7f26888", 7 | "abi": "CompERC20.json" 8 | }, 9 | "governorBravo": { 10 | "address": "0xc0Da02939E1441F497fd74F78cE7Decb17B66529", 11 | "abi": "GovernorBravo.json" 12 | }, 13 | "delegateLevels": { 14 | "proposal": { 15 | "type": "Suspicious", 16 | "severity": "Medium" 17 | }, 18 | "votingQuorum": { 19 | "type": "Suspicious", 20 | "severity": "High" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /comp-delegations-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-comp-delegations-monitor", 3 | "version": "0.0.2", 4 | "description": "Forta Bot to monitor delegate voting power", 5 | "chainIds": [ 6 | 1 7 | ], 8 | "scripts": { 9 | "start": "npm run start:dev", 10 | "start:prod": "forta-agent run --prod", 11 | "tx": "forta-agent run --tx", 12 | "block": "forta-agent run --block", 13 | "range": "forta-agent run --range", 14 | "file": "forta-agent run --file", 15 | "publish": "forta-agent publish", 16 | "push": "forta-agent push", 17 | "disable": "forta-agent disable", 18 | "enable": "forta-agent enable", 19 | "keyfile": "forta-agent keyfile", 20 | "test": "jest" 21 | }, 22 | "dependencies": { 23 | "bignumber.js": "9.0.2", 24 | "forta-agent": "0.1.3" 25 | }, 26 | "devDependencies": { 27 | "eslint": "8.16.0", 28 | "eslint-config-airbnb-base": "15.0.0", 29 | "eslint-plugin-import": "2.26.0", 30 | "jest": "28.1.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ctoken-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /ctoken-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /ctoken-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /ctoken-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /ctoken-monitor/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Protocol Monitoring 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /ctoken-monitor/README.md: -------------------------------------------------------------------------------- 1 | # Compound cToken Event Monitor 2 | 3 | ## Description 4 | 5 | This bot monitors Compound Finance cToken contracts for common market events like Mint, Borrow, 6 | etc. Monitored events are specified in the bot-config.json file, with associated Finding types 7 | and severities for each one. 8 | 9 | This bot also checks the Compound Finance Comptroller contract on every block to compare the most 10 | recent Array of cToken addresses against the previously stored Array. If any new cTokens were 11 | added, the new cToken address(es) are placed into the Array for monitoring in that block and all 12 | subsequent blocks. 13 | 14 | ## Alerts 15 | 16 | 17 | - AE-COMP-CTOKEN-EVENT 18 | - Emitted for any event specified in `bot-config.json` 19 | - Type is set to event specific value in `bot-config.json` 20 | - Severity is set to event specific value in `bot-config.json` 21 | - Metadata field contains: 22 | - cToken symbol 23 | - cToken address 24 | - Event name 25 | - Arguments passed with event (e.g. for Borrow event, includes borrower address, borrowAmount, accountBorrows, and totalBorrows) 26 | 27 | ## Testing 28 | 29 | Borrow (ETH) - 0xcf8a30b55567c988259b08fb219d10bedc3376f612f12d536a045186a566c99c 30 | Liquidate (DAI) - 0x4316c6cb73296b6b5b603a80a267b203d394e049216d71d8e3ff4822e8d7658f 31 | Mint (USDC) - 0xfd200d6d3136ce4f4b91270f8ed7579bf9932e1ce2388b324ee4a281f58047b1 32 | Redeem (ETH) - 0x4b11cee2963cbb2c01cf2c9858a684117ef24ce62a4ffac5738557e14f0276b6 33 | Repay (USDC) - 0x3c59e9ba77e3864f2efdc49df1c9aba83fb202c59ffbbe116c133dbeb327b010 -------------------------------------------------------------------------------- /ctoken-monitor/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "contracts": { 6 | "Comptroller": { 7 | "address": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 8 | "abiFile": "Comptroller.json", 9 | "events": {} 10 | }, 11 | "cTokens": { 12 | "abiFile": "cErc20.json", 13 | "events": { 14 | "Borrow": { 15 | "type": "Info", 16 | "severity": "Info", 17 | "amountKey": "borrowAmount" 18 | }, 19 | "LiquidateBorrow": { 20 | "type": "Info", 21 | "severity": "Info", 22 | "amountKey": "repayAmount" 23 | }, 24 | "Mint": { 25 | "type": "Info", 26 | "severity": "Info", 27 | "amountKey": "mintAmount" 28 | }, 29 | "Redeem": { 30 | "type": "Info", 31 | "severity": "Info", 32 | "amountKey": "redeemAmount" 33 | }, 34 | "RepayBorrow": { 35 | "type": "Info", 36 | "severity": "Info", 37 | "amountKey": "repayAmount" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ctoken-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-comp-ctoken-events", 3 | "version": "0.0.5", 4 | "description": "This Bot monitors Compound Finance cToken contract for common market events.", 5 | "scripts": { 6 | "start": "npm run start:dev", 7 | "start:prod": "forta-agent run --prod", 8 | "tx": "forta-agent run --tx", 9 | "block": "forta-agent run --block", 10 | "range": "forta-agent run --range", 11 | "file": "forta-agent run --file", 12 | "publish": "forta-agent publish", 13 | "push": "forta-agent push", 14 | "disable": "forta-agent disable", 15 | "enable": "forta-agent enable", 16 | "keyfile": "forta-agent keyfile", 17 | "test": "jest" 18 | }, 19 | "dependencies": { 20 | "axios": "0.27.2", 21 | "bignumber.js": "9.0.2", 22 | "forta-agent": "0.0.39" 23 | }, 24 | "devDependencies": { 25 | "eslint": "8.16.0", 26 | "eslint-config-airbnb-base": "15.0.0", 27 | "eslint-plugin-import": "2.26.0", 28 | "jest": "28.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ctoken-monitor/src/utils.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('forta-agent'); 2 | 3 | function getAbi(abiName) { 4 | // eslint-disable-next-line global-require,import/no-dynamic-require 5 | const { abi } = require(`../abi/${abiName}`); 6 | return abi; 7 | } 8 | 9 | // helper function that identifies key strings in the args array obtained from log parsing 10 | // these key-value pairs will be added to the metadata as event args 11 | // all values are converted to strings so that BigNumbers are readable 12 | function extractEventArgs(args) { 13 | const eventArgs = {}; 14 | Object.keys(args).forEach((key) => { 15 | if (Number.isNaN(Number(key))) { 16 | eventArgs[key] = args[key].toString(); 17 | } 18 | }); 19 | return eventArgs; 20 | } 21 | 22 | function isAddress(valueString) { 23 | return ethers.utils.isHexString(valueString, 20); 24 | } 25 | 26 | module.exports = { 27 | getAbi, 28 | extractEventArgs, 29 | isAddress, 30 | }; 31 | -------------------------------------------------------------------------------- /defender/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 'latest', 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-plusplus': 'off', 21 | 'no-console': 'off', 22 | }, 23 | }, 24 | ], 25 | }; 26 | -------------------------------------------------------------------------------- /defender/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | 4 | # Temp 5 | demo*.js 6 | config.js 7 | 8 | # Serverless directories 9 | .serverless 10 | 11 | # Defender 12 | secrets*.yml 13 | .defender 14 | -------------------------------------------------------------------------------- /defender/datadog_alerts_heat_map/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: datadog_alerts_heat_map 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Datadog Alerts Heat Map 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Private variables pulled from external secrets.yml file 20 | datadogApiKey: ${self:custom.stackSecrets.datadogApiKey} 21 | 22 | defender: 23 | key: ${self:custom.config.keys.api} 24 | secret: ${self:custom.config.keys.secret} 25 | 26 | functions: 27 | autotask-1: 28 | name: ${self:custom.name} Serverless Autotask 29 | path: autotask-1 30 | trigger: 31 | type: schedule 32 | frequency: 60 33 | paused: false 34 | 35 | resources: 36 | Resources: 37 | policies: 38 | policy-1: 39 | gas-price-cap: 1000 40 | whitelist-receivers: 41 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 42 | eip1559-pricing: true 43 | 44 | secrets: 45 | stack: ${self:custom.defenderSecrets} 46 | 47 | relayers: 48 | 49 | plugins: 50 | - defender-serverless 51 | -------------------------------------------------------------------------------- /defender/datadog_forta_bot_alerts/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: datadog_forta_bot_alerts 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Datadog Forta Bot Alerts 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Private variables pulled from external secrets.yml file 20 | datadogApiKey: ${self:custom.stackSecrets.datadogApiKey} 21 | 22 | defender: 23 | key: ${self:custom.config.keys.api} 24 | secret: ${self:custom.config.keys.secret} 25 | 26 | functions: 27 | autotask-1: 28 | name: ${self:custom.name} Serverless Autotask 29 | path: autotask-1 30 | trigger: 31 | type: schedule 32 | frequency: 60 33 | paused: false 34 | 35 | resources: 36 | Resources: 37 | policies: 38 | policy-1: 39 | gas-price-cap: 1000 40 | whitelist-receivers: 41 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 42 | eip1559-pricing: true 43 | 44 | secrets: 45 | stack: ${self:custom.defenderSecrets} 46 | 47 | relayers: 48 | 49 | plugins: 50 | - defender-serverless 51 | -------------------------------------------------------------------------------- /defender/datadog_forta_detection_bot_health/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: datadog_forta_detection_bot_health 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Datadog Forta Detection Bot Health 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Private variables pulled from external secrets.yml file 20 | datadogApiKey: ${self:custom.stackSecrets.datadogApiKey} 21 | 22 | defender: 23 | key: ${self:custom.config.keys.api} 24 | secret: ${self:custom.config.keys.secret} 25 | 26 | functions: 27 | autotask-1: 28 | name: ${self:custom.name} Serverless Autotask 29 | path: autotask-1 30 | trigger: 31 | type: schedule 32 | frequency: 60 33 | paused: false 34 | 35 | resources: 36 | Resources: 37 | policies: 38 | policy-1: 39 | gas-price-cap: 1000 40 | whitelist-receivers: 41 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 42 | eip1559-pricing: true 43 | 44 | secrets: 45 | stack: ${self:custom.defenderSecrets} 46 | 47 | relayers: 48 | 49 | plugins: 50 | - defender-serverless 51 | -------------------------------------------------------------------------------- /defender/forta_ctoken/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_ctoken 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Forta cToken 17 | 18 | # Forta Sentinel Settings 19 | alert-ids: 20 | - AE-COMP-CTOKEN-EVENT 21 | agent-ids: 22 | - "0xab39733ddf86340b8e7940ebb933bb48506a341485c7f8c77da17bc1400fe028" 23 | 24 | # Comment out any secret that you do not want to be overwritten in Defender 25 | defenderSecrets: 26 | # Private variables pulled from external secrets.yml file 27 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 28 | 29 | defender: 30 | key: ${self:custom.config.keys.api} 31 | secret: ${self:custom.config.keys.secret} 32 | 33 | functions: 34 | autotask-1: 35 | name: ${self:custom.name} Serverless Autotask 36 | path: autotask-1 37 | trigger: 38 | type: schedule 39 | frequency: 525600000 40 | paused: false 41 | relayer: ${self:resources.Resources.relayers.relayer-1} 42 | 43 | resources: 44 | Resources: 45 | policies: 46 | policy-1: 47 | gas-price-cap: 1000 48 | whitelist-receivers: 49 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 50 | eip1559-pricing: true 51 | 52 | secrets: 53 | stack: ${self:custom.defenderSecrets} 54 | 55 | relayers: 56 | relayer-1: 57 | name: ${self:custom.name} Serverless Relay 58 | network: mainnet 59 | min-balance: 100000000000000000 60 | 61 | sentinels: 62 | sentinel-1: 63 | name: ${self:custom.name} Serverless Sentinel 64 | type: FORTA 65 | addresses: [] 66 | network: mainnet 67 | paused: true 68 | autotask-trigger: ${self:functions.autotask-1} 69 | notify-config: 70 | timeout: 0 71 | channels: [] 72 | conditions: 73 | min-scanner-count: 1 74 | severity: 1 75 | alert-ids: ${self:custom.alert-ids} 76 | agent-ids: ${self:custom.agent-ids} 77 | 78 | plugins: 79 | - defender-serverless 80 | -------------------------------------------------------------------------------- /defender/forta_distribution/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_distribution 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Forta Distribution 17 | 18 | # Forta Sentinel Settings 19 | alert-ids: 20 | - AE-COMP-DISTRIBUTION-EVENT 21 | agent-ids: 22 | - "0x34c27c43e0a45bced8f8a941b3d552f5e6feae62afd7e2e88b5024f7de5a8ba0" 23 | 24 | # Comment out any secret that you do not want to be overwritten in Defender 25 | defenderSecrets: 26 | # Private variables pulled from external secrets.yml file 27 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 28 | 29 | defender: 30 | key: ${self:custom.config.keys.api} 31 | secret: ${self:custom.config.keys.secret} 32 | 33 | functions: 34 | autotask-1: 35 | name: ${self:custom.name} Serverless Autotask 36 | path: autotask-1 37 | trigger: 38 | type: schedule 39 | frequency: 525600000 40 | paused: false 41 | 42 | resources: 43 | Resources: 44 | policies: 45 | policy-1: 46 | gas-price-cap: 1000 47 | whitelist-receivers: 48 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 49 | eip1559-pricing: true 50 | 51 | secrets: 52 | stack: ${self:custom.defenderSecrets} 53 | 54 | relayers: 55 | 56 | sentinels: 57 | sentinel-1: 58 | name: ${self:custom.name} Serverless Sentinel 59 | type: FORTA 60 | addresses: [] 61 | network: mainnet 62 | paused: true 63 | autotask-trigger: ${self:functions.autotask-1} 64 | notify-config: 65 | timeout: 0 66 | channels: [] 67 | conditions: 68 | min-scanner-count: 1 69 | severity: 1 70 | alert-ids: ${self:custom.alert-ids} 71 | agent-ids: ${self:custom.agent-ids} 72 | 73 | plugins: 74 | - defender-serverless 75 | -------------------------------------------------------------------------------- /defender/forta_explorer_monitor/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_explorer_monitor 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | 14 | # Configure this section and rename secret-example.yml to secrets.yml 15 | name: Forta Explorer Monitor 16 | 17 | defender: 18 | key: ${self:custom.config.keys.api} 19 | secret: ${self:custom.config.keys.secret} 20 | 21 | functions: 22 | autotask-1: 23 | name: ${self:custom.name} Serverless Autotask 24 | path: autotask-1 25 | trigger: 26 | type: schedule 27 | cron: "0 * * * *" # Every hour on the hour 28 | paused: false 29 | 30 | resources: 31 | Resources: 32 | policies: 33 | policy-1: 34 | gas-price-cap: 1000 35 | whitelist-receivers: 36 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 37 | eip1559-pricing: true 38 | 39 | secrets: 40 | 41 | relayers: 42 | 43 | plugins: 44 | - defender-serverless 45 | -------------------------------------------------------------------------------- /defender/forta_large_borrows_governance/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_large_borrows_governance 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 15 | name: Forta Large Borrows Governance 16 | 17 | defender: 18 | key: ${self:custom.config.keys.api} 19 | secret: ${self:custom.config.keys.secret} 20 | 21 | functions: 22 | autotask-1: 23 | name: ${self:custom.name} Action 24 | path: autotask-1 25 | trigger: 26 | type: schedule 27 | frequency: 0 28 | paused: true 29 | 30 | resources: 31 | Resources: 32 | notifications: 33 | discord: 34 | type: discord 35 | name: ${self:custom.name} Discord 36 | config: 37 | url: ${self:custom.discordWebhook} 38 | paused: false 39 | sentinels: 40 | monitor: 41 | name: ${self:custom.name} Monitor 42 | type: FORTA 43 | network: mainnet 44 | paused: false 45 | autotask-trigger: ${self:functions.autotask-1} 46 | notify-config: 47 | timeout: 0 48 | message: [TX]({{ metadata.transactionLink }}) {{ metadata.message }} 49 | message-subject: Defender Alert: ${self:custom.name} 50 | channels: 51 | - ${self:resources.Resources.notifications.discord} 52 | conditions: 53 | min-scanner-count: 1 54 | severity: 1 55 | alert-ids: 56 | - AE-COMP-GOVERNANCE-THRESHOLD 57 | agent-ids: 58 | - 0xb6bdedbae67cc82e60aad02a8ffab3ccbefeaa876ca7e4f291c07c798a95e339 59 | 60 | plugins: 61 | - defender-serverless -------------------------------------------------------------------------------- /defender/forta_large_delegations/autotask-1/index.js: -------------------------------------------------------------------------------- 1 | function getUrl(scopedSecrets, source) { 2 | if (!scopedSecrets || !source) return; 3 | const { block, transactionHash } = source; 4 | if (!block || !transactionHash) return; 5 | const { chainId } = block; 6 | if (!chainId) return; 7 | // eslint-disable-next-line dot-notation 8 | let mapping = scopedSecrets['NetworkBlockexplorerMapping']; 9 | if (!mapping) return; 10 | try { 11 | mapping = JSON.parse(mapping); 12 | } catch (e) { return; } 13 | const path = mapping?.[chainId]; 14 | if (!path) return; 15 | // eslint-disable-next-line consistent-return 16 | return `${path}${transactionHash}`; 17 | } 18 | 19 | // eslint-disable-next-line func-names 20 | exports.handler = async function (payload) { 21 | const matches = []; 22 | payload.request.body.events?.forEach((event) => { 23 | const { source, metadata, hash } = event.alert; 24 | const transactionLink = getUrl(payload.secrets, source) ?? `https://explorer.forta.network/alert/${hash}`; 25 | if (metadata === undefined) { 26 | throw new Error('metadata undefined'); 27 | } 28 | 29 | // Start of usual modifications to the autotask script 30 | // extract the metadata 31 | const { 32 | delegateAddress, 33 | levelName, 34 | } = metadata; 35 | if (delegateAddress === undefined) { 36 | throw new Error('delegateAddress undefined'); 37 | } 38 | const delegateFormatted = delegateAddress.slice(0, 6); 39 | 40 | const message = `${transactionLink} 💸 **${delegateFormatted}** has been delegated enough **COMP** tokens to pass min threshold for the governance event: **${levelName}**`; 41 | matches.push({ 42 | hash: event.hash, 43 | metadata: { message, transactionLink }, 44 | }); 45 | }); 46 | return { matches }; 47 | }; -------------------------------------------------------------------------------- /defender/forta_large_delegations/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: 3 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_large_delegations 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 15 | name: Forta Large Delegations 16 | 17 | defender: 18 | key: ${self:custom.config.keys.api} 19 | secret: ${self:custom.config.keys.secret} 20 | 21 | functions: 22 | filter: 23 | name: ${self:custom.name} Filter 24 | trigger: 25 | type: schedule 26 | frequency: 0 27 | paused: true 28 | path: autotask-1 29 | 30 | resources: 31 | Resources: 32 | notifications: 33 | discord: 34 | type: discord 35 | name: ${self:custom.name} Discord 36 | config: 37 | url: ${self:custom.discordWebhook} 38 | paused: false 39 | sentinels: 40 | monitor: 41 | name: ${self:custom.name} Monitor 42 | type: FORTA 43 | network: mainnet 44 | paused: false 45 | notify-config: 46 | timeout: 0 47 | message: [TX]({{ metadata.transactionLink }}) {{ metadata.message }} 48 | message-subject: Defender Alert: ${self:custom.name} 49 | channels: 50 | - ${self:resources.Resources.notifications.discord} 51 | autotask-condition: ${self:functions.filter} 52 | conditions: 53 | min-scanner-count: 1 54 | severity: 1 55 | alert-ids: 56 | - AE-COMP-GOVERNANCE-DELEGATE-THRESHOLD 57 | agent-ids: 58 | - 0x0d3cdcc2757cd7837e3b302a9889c854044a80835562dc8060d7c163fbb69d53 59 | plugins: 60 | - defender-serverless 61 | -------------------------------------------------------------------------------- /defender/forta_low_liquidity/autotask-1/index.js: -------------------------------------------------------------------------------- 1 | function getUrl(scopedSecrets, source) { 2 | if (!scopedSecrets || !source) return; 3 | const { block, transactionHash } = source; 4 | if (!block || !transactionHash) return; 5 | const { chainId } = block; 6 | if (!chainId) return; 7 | let mapping = scopedSecrets['NetworkBlockexplorerMapping']; 8 | if (!mapping) return; 9 | try { 10 | mapping = JSON.parse(mapping); 11 | } catch (e) { return; } 12 | const path = mapping?.[chainId]; 13 | if (!path) return; 14 | return `${path}${transactionHash}`; 15 | } 16 | exports.handler = async function (payload) { 17 | const matches = []; 18 | payload.request.body.events?.forEach(event => { 19 | const { alertId, source, metadata, hash } = event.alert; 20 | const transactionLink = getUrl(payload.secrets, source) ?? `https://explorer.forta.network/alert/${hash}`; 21 | if (metadata === undefined) { 22 | throw new Error('metadata undefined'); 23 | } 24 | // Start of usual modifications to the autotask script 25 | // extract the metadata 26 | const { 27 | compTokenSymbol, 28 | maliciousAddress, 29 | protocolVersion, 30 | } = metadata; 31 | if (maliciousAddress === undefined) { 32 | throw new Error('maliciousAddress undefined'); 33 | } 34 | // Handle older alerts which don't specify the protocol version 35 | let versionString = ''; 36 | if (protocolVersion !== undefined) { 37 | versionString = ` (Compound v${protocolVersion})`; 38 | } 39 | const maliciousAddressFormatted = maliciousAddress.slice(0, 6); 40 | const message = `The address ${maliciousAddressFormatted} is potentially manipulating the cToken ${compTokenSymbol} market${versionString}`; 41 | matches.push({ 42 | hash: event.hash, 43 | metadata: { message, transactionLink } 44 | }); 45 | }); 46 | return { matches }; 47 | }; -------------------------------------------------------------------------------- /defender/forta_low_liquidity/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_low_liquidity 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 15 | name: Forta Low Liquidity 16 | 17 | defender: 18 | key: ${self:custom.config.keys.api} 19 | secret: ${self:custom.config.keys.secret} 20 | 21 | functions: 22 | filter: 23 | name: ${self:custom.name} Filter 24 | path: autotask-1 25 | trigger: 26 | type: schedule 27 | frequency: 525600000 28 | paused: false 29 | 30 | resources: 31 | Resources: 32 | notifications: 33 | discord: 34 | type: discord 35 | name: "${self:custom.name} Discord Channel" 36 | config: 37 | url: ${self:custom.discordWebhook} 38 | paused: false 39 | sentinels: 40 | monitor: 41 | name: ${self:custom.name} Monitor 42 | type: FORTA 43 | network: mainnet 44 | paused: false 45 | notify-config: 46 | timeout: 0 47 | message: "[TX]({{ metadata.transactionLink }}) {{ metadata.message }}" 48 | message-subject: Defender Alert: ${self:custom.name} 49 | channels: 50 | - ${self:resources.Resources.notifications.discord} 51 | autotask-condition: ${self:functions.filter} 52 | conditions: 53 | min-scanner-count: 1 54 | severity: 1 55 | alert-ids: 56 | - AE-COMP-MARKET-ATTACK-EVENT 57 | agent-ids: 58 | - 0xe49ab07879658c258d5007ac6b88428a2b88cc5cfef206222ad94690840be87a 59 | plugins: 60 | - defender-serverless -------------------------------------------------------------------------------- /defender/forta_oracle_price/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_oracle_price 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | name: Forta Oracle Price 14 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 15 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 16 | 17 | agent-ids: "0x32facccd163300ad76c7fe88b559b812dca9050a569417b42fced95594dda08e" 18 | 19 | defender: 20 | key: ${self:custom.config.keys.api} 21 | secret: ${self:custom.config.keys.secret} 22 | 23 | functions: 24 | autotask-1: 25 | name: ${self:custom.name} Filter 26 | path: autotask-1 27 | trigger: 28 | type: schedule 29 | frequency: 0 30 | paused: true 31 | 32 | resources: 33 | Resources: 34 | notifications: 35 | discord: 36 | type: discord 37 | name: "${self:custom.name} Discord Channel" 38 | config: 39 | url: ${self:custom.discordWebhook} 40 | paused: false 41 | sentinels: 42 | forta-oracle-price-sentinel: 43 | name: "${self:custom.name} Sentinel" 44 | type: "FORTA" 45 | network: "mainnet" 46 | addresses: [] 47 | paused: false 48 | notify-config: 49 | timeout: 0 50 | message: "[TX]({{ metadata.transactionLink }}) {{ metadata.message }}" 51 | message-subject: "Compound Monitoring: Forta Oracle Price Sentinel triggered" 52 | channels: 53 | - ${self:resources.Resources.notifications.discord} 54 | conditions: 55 | min-scanner-count: 1 56 | severity: 1 57 | autotask-condition: ${self:functions.autotask-1} 58 | agent-ids: ${self:custom.agent-ids} 59 | plugins: 60 | - '@openzeppelin/defender-serverless' -------------------------------------------------------------------------------- /defender/forta_underlying_asset/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_underlying_asset 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Forta Underlying Asset 17 | 18 | # Forta Sentinel Settings 19 | alert-ids: 20 | - AE-COMP-CTOKEN-ASSET-UPGRADED 21 | agent-ids: 22 | - "0xfa3044aa08927163ff8578fb5c108978dfde3a12e0b21834e53111e2859f3a59" 23 | 24 | # Comment out any secret that you do not want to be overwritten in Defender 25 | defenderSecrets: 26 | # Private variables pulled from external secrets.yml file 27 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 28 | 29 | defender: 30 | key: ${self:custom.config.keys.api} 31 | secret: ${self:custom.config.keys.secret} 32 | 33 | functions: 34 | autotask-1: 35 | name: ${self:custom.name} Serverless Autotask 36 | path: autotask-1 37 | trigger: 38 | type: schedule 39 | frequency: 0 40 | paused: true 41 | 42 | resources: 43 | Resources: 44 | notifications: 45 | discord: 46 | type: discord 47 | name: "${self:custom.name} Security Alerts" 48 | config: 49 | url: ${self:custom.defenderSecrets.discordWebhook} 50 | paused: false 51 | sentinels: 52 | forta-multisig-sentinel: 53 | name: "${self:custom.name} Sentinel" 54 | type: "FORTA" 55 | network: "mainnet" 56 | addresses: [] 57 | paused: false 58 | notify-config: 59 | timeout: 0 60 | message: "[TX]({{ metadata.transactionLink }}) {{ metadata.message }}" 61 | message-subject: "Defender Sentinel: ${self:custom.name} triggered" 62 | channels: 63 | - ${self:resources.Resources.notifications.discord} 64 | conditions: 65 | min-scanner-count: 1 66 | severity: 1 67 | autotask-condition: ${self:functions.autotask-1} 68 | agent-ids: ${self:custom.agent-ids} 69 | 70 | plugins: 71 | - defender-serverless -------------------------------------------------------------------------------- /defender/forta_v2_liquidation_monitor_dev/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_v2_liquidation_monitor_dev 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Forta v2 Liquidation Monitor DEV 17 | 18 | # Forta Sentinel Settings 19 | alert-ids: [] # Accept all alerts 20 | agent-ids: 21 | - "0x3c61101f1d349661298a58ba59a58fbce5a3626c5c7af10b091796969e0d6c59" 22 | 23 | # Comment out any secret that you do not want to be overwritten in Defender 24 | defenderSecrets: 25 | # Private variables pulled from external secrets.yml file 26 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 27 | 28 | defender: 29 | key: ${self:custom.config.keys.api} 30 | secret: ${self:custom.config.keys.secret} 31 | 32 | functions: 33 | autotask-1: 34 | name: ${self:custom.name} Serverless Autotask 35 | path: autotask-1 36 | trigger: 37 | type: schedule 38 | frequency: 525600000 39 | paused: false 40 | 41 | resources: 42 | Resources: 43 | policies: 44 | policy-1: 45 | gas-price-cap: 1000 46 | whitelist-receivers: 47 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 48 | eip1559-pricing: true 49 | 50 | secrets: 51 | stack: ${self:custom.defenderSecrets} 52 | 53 | relayers: 54 | 55 | sentinels: 56 | sentinel-1: 57 | name: ${self:custom.name} Serverless Sentinel 58 | type: FORTA 59 | addresses: [] 60 | network: mainnet 61 | paused: false 62 | autotask-trigger: ${self:functions.autotask-1} 63 | notify-config: 64 | timeout: 0 65 | channels: [] 66 | conditions: 67 | min-scanner-count: 1 68 | severity: 1 69 | alert-ids: ${self:custom.alert-ids} 70 | agent-ids: ${self:custom.agent-ids} 71 | 72 | plugins: 73 | - defender-serverless 74 | -------------------------------------------------------------------------------- /defender/forta_v3_liquidation_monitor_dev/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: forta_v3_liquidation_monitor_dev 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Forta v3 Liquidation Monitor DEV 17 | 18 | # Forta Sentinel Settings 19 | alert-ids: [] # Accept all alerts 20 | agent-ids: 21 | - "0x52b24dd829bf3aa7b18a74f23947377af6203f09b6553ef054df7c633f961210" 22 | 23 | # Comment out any secret that you do not want to be overwritten in Defender 24 | defenderSecrets: 25 | # Private variables pulled from external secrets.yml file 26 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 27 | 28 | defender: 29 | key: ${self:custom.config.keys.api} 30 | secret: ${self:custom.config.keys.secret} 31 | 32 | functions: 33 | autotask-1: 34 | name: ${self:custom.name} Serverless Autotask 35 | path: autotask-1 36 | trigger: 37 | type: schedule 38 | frequency: 525600000 39 | paused: false 40 | 41 | resources: 42 | Resources: 43 | policies: 44 | policy-1: 45 | gas-price-cap: 1000 46 | whitelist-receivers: 47 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 48 | eip1559-pricing: true 49 | 50 | secrets: 51 | stack: ${self:custom.defenderSecrets} 52 | 53 | relayers: 54 | 55 | sentinels: 56 | sentinel-1: 57 | name: ${self:custom.name} Serverless Sentinel 58 | type: FORTA 59 | addresses: [] 60 | network: mainnet 61 | paused: false 62 | autotask-trigger: ${self:functions.autotask-1} 63 | notify-config: 64 | timeout: 0 65 | channels: [] 66 | conditions: 67 | min-scanner-count: 1 68 | severity: 1 69 | alert-ids: ${self:custom.alert-ids} 70 | agent-ids: ${self:custom.agent-ids} 71 | 72 | plugins: 73 | - defender-serverless 74 | -------------------------------------------------------------------------------- /defender/gasless_voting_dev/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: gasless_voting_dev 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | 14 | # Configure this section and rename secret-example.yml to secrets.yml 15 | name: Gasless Voting DEV 16 | 17 | defender: 18 | key: ${self:custom.config.keys.api} 19 | secret: ${self:custom.config.keys.secret} 20 | 21 | functions: 22 | autotask-1: 23 | name: ${self:custom.name} Serverless Autotask 24 | path: autotask-1 25 | trigger: 26 | type: webhook 27 | paused: false 28 | relayer: ${self:resources.Resources.relayers.relayer-1} 29 | 30 | resources: 31 | Resources: 32 | policies: 33 | policy-1: 34 | gas-price-cap: 1000 35 | whitelist-receivers: 36 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 37 | eip1559-pricing: true 38 | 39 | secrets: 40 | 41 | relayers: 42 | relayer-1: 43 | name: ${self:custom.name} Serverless Relay 44 | network: mainnet 45 | min-balance: 100000000000000000 46 | 47 | plugins: 48 | - defender-serverless 49 | -------------------------------------------------------------------------------- /defender/governance_automation/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: governance_automation 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | 14 | # Configure this section and rename secret-example.yml to secrets.yml 15 | name: Governance Automation 16 | # Comment out any secret that you do not want to be overwritten in Defender 17 | defenderSecrets: 18 | # Public Variables 19 | # Compound Governance Address 20 | governanceAddress: "0xc0Da02939E1441F497fd74F78cE7Decb17B66529" 21 | 22 | defender: 23 | key: ${self:custom.config.keys.api} 24 | secret: ${self:custom.config.keys.secret} 25 | 26 | functions: 27 | autotask-1: 28 | name: ${self:custom.name} Serverless Autotask 29 | path: autotask-1 30 | trigger: 31 | type: schedule 32 | frequency: 1 33 | paused: false 34 | relayer: ${self:resources.Resources.relayers.relayer-1} 35 | 36 | resources: 37 | Resources: 38 | policies: 39 | policy-1: 40 | gas-price-cap: 1000 41 | whitelist-receivers: 42 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 43 | eip1559-pricing: true 44 | 45 | secrets: 46 | stack: ${self:custom.defenderSecrets} 47 | 48 | relayers: 49 | relayer-1: 50 | name: ${self:custom.name} Serverless Relay 51 | network: mainnet 52 | min-balance: 100000000000000000 53 | 54 | plugins: 55 | - defender-serverless 56 | -------------------------------------------------------------------------------- /defender/governance_discord_summary/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: governance_discord_summary 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Governance Discord Summary 17 | defenderSecrets: 18 | # Public Variables 19 | # Compound Governance Address 20 | governanceAddress: "0xc0Da02939E1441F497fd74F78cE7Decb17B66529" 21 | # Private variables pulled from external secrets.yml file 22 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 23 | 24 | defender: 25 | key: ${self:custom.config.keys.api} 26 | secret: ${self:custom.config.keys.secret} 27 | 28 | functions: 29 | autotask-1: 30 | name: ${self:custom.name} Serverless Autotask 31 | path: autotask-1 32 | trigger: 33 | type: schedule 34 | frequency: 1440 35 | paused: false 36 | relayer: ${self:resources.Resources.relayers.relayer-1} 37 | 38 | resources: 39 | Resources: 40 | policies: 41 | policy-1: 42 | gas-price-cap: 1000 43 | whitelist-receivers: 44 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 45 | eip1559-pricing: true 46 | 47 | secrets: 48 | stack: ${self:custom.defenderSecrets} 49 | 50 | relayers: 51 | relayer-1: 52 | name: ${self:custom.name} Serverless Relay 53 | network: mainnet 54 | min-balance: 100000000000000000 55 | 56 | plugins: 57 | - defender-serverless 58 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client-mixins/form-data.helper.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare type TStringable = { 3 | toString(): string; 4 | }; 5 | export declare class FormDataHelper { 6 | protected _boundary: string; 7 | protected _chunks: Buffer[]; 8 | protected _footerChunk?: Buffer; 9 | protected static readonly LINE_BREAK = "\r\n"; 10 | protected static readonly DEFAULT_CONTENT_TYPE = "application/octet-stream"; 11 | protected bodyAppend(...values: (Buffer | string)[]): void; 12 | append(field: string, value: Buffer | string | TStringable, contentType?: string): void; 13 | getHeaders(): { 14 | 'content-type': string; 15 | }; 16 | /** Length of form-data (including footer length). */ 17 | protected getLength(): number; 18 | getBuffer(): Buffer; 19 | protected getBoundary(): string; 20 | protected generateBoundary(): void; 21 | protected getMultipartHeader(field: string, value: string | Buffer, contentType?: string): string; 22 | protected getMultipartFooter(): Buffer; 23 | } 24 | export {}; 25 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client-mixins/oauth1.helper.d.ts: -------------------------------------------------------------------------------- 1 | export interface OAuth1Tokens { 2 | key: string; 3 | secret: string; 4 | } 5 | export interface OAuth1MakerArgs { 6 | consumerKeys: OAuth1Tokens; 7 | } 8 | export interface OAuth1RequestOptions { 9 | url: string; 10 | method: string; 11 | data?: any; 12 | } 13 | export interface OAuth1AuthInfo { 14 | oauth_consumer_key: string; 15 | oauth_nonce: string; 16 | oauth_signature_method: string; 17 | oauth_timestamp: number; 18 | oauth_version: string; 19 | oauth_token: string; 20 | oauth_signature: string; 21 | } 22 | export declare class OAuth1Helper { 23 | nonceLength: number; 24 | protected consumerKeys: OAuth1Tokens; 25 | constructor(options: OAuth1MakerArgs); 26 | static percentEncode(str: string): string; 27 | protected hash(base: string, key: string): string; 28 | authorize(request: OAuth1RequestOptions, accessTokens?: Partial): OAuth1AuthInfo; 29 | toHeader(oauthInfo: OAuth1AuthInfo): { 30 | Authorization: string; 31 | }; 32 | protected getNonce(): string; 33 | protected getTimestamp(): number; 34 | protected getSignature(request: OAuth1RequestOptions, tokenSecret: string | undefined, oauthInfo: OAuth1AuthInfo): string; 35 | protected getSigningKey(tokenSecret: string | undefined): string; 36 | protected getBaseString(request: OAuth1RequestOptions, oauthInfo: OAuth1AuthInfo): string; 37 | protected getParameterString(request: OAuth1RequestOptions, oauthInfo: OAuth1AuthInfo): string; 38 | protected getBaseUrl(url: string): string; 39 | } 40 | export default OAuth1Helper; 41 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client-mixins/oauth2.helper.d.ts: -------------------------------------------------------------------------------- 1 | export declare class OAuth2Helper { 2 | static getCodeVerifier(): string; 3 | static getCodeChallengeFromVerifier(verifier: string): string; 4 | static getAuthHeader(clientId: string, clientSecret: string): string; 5 | static generateRandomString(length: number): string; 6 | private static escapeBase64Url; 7 | } 8 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client-mixins/request-param.helper.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { RequestOptions } from 'https'; 3 | import type { TBodyMode, TRequestBody, TRequestQuery, TRequestStringQuery } from '../types/request-maker.mixin.types'; 4 | export declare class RequestParamHelpers { 5 | static readonly JSON_1_1_ENDPOINTS: Set; 6 | static formatQueryToString(query: TRequestQuery): TRequestStringQuery; 7 | static autoDetectBodyType(url: URL): TBodyMode; 8 | static addQueryParamsToUrl(url: URL, query: TRequestQuery): void; 9 | static constructBodyParams(body: TRequestBody, headers: Record, mode: TBodyMode): string | Buffer; 10 | static setBodyLengthHeader(options: RequestOptions, body: string | Buffer): void; 11 | static isOAuthSerializable(item: any): boolean; 12 | static mergeQueryAndBodyForOAuth(query: TRequestQuery, body: TRequestBody): any; 13 | static moveUrlQueryParamsIntoObject(url: URL, query: TRequestQuery): URL; 14 | /** 15 | * Replace URL parameters available in pathname, like `:id`, with data given in `parameters`: 16 | * `https://twitter.com/:id.json` + `{ id: '20' }` => `https://twitter.com/20.json` 17 | */ 18 | static applyRequestParametersToUrl(url: URL, parameters: TRequestQuery): URL; 19 | } 20 | export default RequestParamHelpers; 21 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client.subclient.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiBase from './client.base'; 2 | /** 3 | * Base subclient for every v1 and v2 client. 4 | */ 5 | export default abstract class TwitterApiSubClient extends TwitterApiBase { 6 | constructor(instance: TwitterApiBase); 7 | } 8 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client.subclient.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const client_base_1 = __importDefault(require("./client.base")); 7 | /** 8 | * Base subclient for every v1 and v2 client. 9 | */ 10 | class TwitterApiSubClient extends client_base_1.default { 11 | constructor(instance) { 12 | if (!(instance instanceof client_base_1.default)) { 13 | throw new Error('You must instance SubTwitterApi instance from existing TwitterApi instance.'); 14 | } 15 | super(instance); 16 | } 17 | } 18 | exports.default = TwitterApiSubClient; 19 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client/index.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiv1 from '../v1/client.v1'; 2 | import TwitterApiv2 from '../v2/client.v2'; 3 | import TwitterApiReadWrite from './readwrite'; 4 | /** 5 | * Twitter v1.1 and v2 API client. 6 | */ 7 | export declare class TwitterApi extends TwitterApiReadWrite { 8 | protected _v1?: TwitterApiv1; 9 | protected _v2?: TwitterApiv2; 10 | get v1(): TwitterApiv1; 11 | get v2(): TwitterApiv2; 12 | /** 13 | * Get a client with read/write rights. 14 | */ 15 | get readWrite(): TwitterApiReadWrite; 16 | static getErrors(error: any): (import("../types").ErrorV1 | import("../types").ErrorV2)[]; 17 | /** Extract another image size than obtained in a `profile_image_url` or `profile_image_url_https` field of a user object. */ 18 | static getProfileImageInSize(profileImageUrl: string, size: 'normal' | 'bigger' | 'mini' | 'original'): string; 19 | } 20 | export { default as TwitterApiReadWrite } from './readwrite'; 21 | export { default as TwitterApiReadOnly } from './readonly'; 22 | export default TwitterApi; 23 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client/readwrite.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiv1ReadWrite from '../v1/client.v1.write'; 2 | import TwitterApiv2ReadWrite from '../v2/client.v2.write'; 3 | import TwitterApiReadOnly from './readonly'; 4 | /** 5 | * Twitter v1.1 and v2 API client. 6 | */ 7 | export default class TwitterApiReadWrite extends TwitterApiReadOnly { 8 | protected _v1?: TwitterApiv1ReadWrite; 9 | protected _v2?: TwitterApiv2ReadWrite; 10 | get v1(): TwitterApiv1ReadWrite; 11 | get v2(): TwitterApiv2ReadWrite; 12 | /** 13 | * Get a client with read only rights. 14 | */ 15 | get readOnly(): TwitterApiReadOnly; 16 | } 17 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/client/readwrite.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const client_v1_write_1 = __importDefault(require("../v1/client.v1.write")); 7 | const client_v2_write_1 = __importDefault(require("../v2/client.v2.write")); 8 | const readonly_1 = __importDefault(require("./readonly")); 9 | /** 10 | * Twitter v1.1 and v2 API client. 11 | */ 12 | class TwitterApiReadWrite extends readonly_1.default { 13 | /* Direct access to subclients */ 14 | get v1() { 15 | if (this._v1) 16 | return this._v1; 17 | return this._v1 = new client_v1_write_1.default(this); 18 | } 19 | get v2() { 20 | if (this._v2) 21 | return this._v2; 22 | return this._v2 = new client_v2_write_1.default(this); 23 | } 24 | /** 25 | * Get a client with read only rights. 26 | */ 27 | get readOnly() { 28 | return this; 29 | } 30 | } 31 | exports.default = TwitterApiReadWrite; 32 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/globals.d.ts: -------------------------------------------------------------------------------- 1 | export declare const API_V2_PREFIX = "https://api.twitter.com/2/"; 2 | export declare const API_V2_LABS_PREFIX = "https://api.twitter.com/labs/2/"; 3 | export declare const API_V1_1_PREFIX = "https://api.twitter.com/1.1/"; 4 | export declare const API_V1_1_UPLOAD_PREFIX = "https://upload.twitter.com/1.1/"; 5 | export declare const API_V1_1_STREAM_PREFIX = "https://stream.twitter.com/1.1/"; 6 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/globals.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.API_V1_1_STREAM_PREFIX = exports.API_V1_1_UPLOAD_PREFIX = exports.API_V1_1_PREFIX = exports.API_V2_LABS_PREFIX = exports.API_V2_PREFIX = void 0; 4 | exports.API_V2_PREFIX = 'https://api.twitter.com/2/'; 5 | exports.API_V2_LABS_PREFIX = 'https://api.twitter.com/labs/2/'; 6 | exports.API_V1_1_PREFIX = 'https://api.twitter.com/1.1/'; 7 | exports.API_V1_1_UPLOAD_PREFIX = 'https://upload.twitter.com/1.1/'; 8 | exports.API_V1_1_STREAM_PREFIX = 'https://stream.twitter.com/1.1/'; 9 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/helpers.d.ts: -------------------------------------------------------------------------------- 1 | export interface SharedPromise { 2 | value: T | undefined; 3 | promise: Promise; 4 | } 5 | export declare function sharedPromise(getter: () => Promise): SharedPromise; 6 | export declare function arrayWrap(value: T | T[]): T[]; 7 | export declare function trimUndefinedProperties(object: any): void; 8 | export declare function isTweetStreamV2ErrorPayload(payload: any): boolean; 9 | export declare function hasMultipleItems(item: string | string[]): boolean; 10 | export interface IDeprecationWarning { 11 | instance: string; 12 | method: string; 13 | problem: string; 14 | resolution: string; 15 | } 16 | export declare function safeDeprecationWarning(message: IDeprecationWarning): void; 17 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export { default as default } from './client'; 2 | export * from './client'; 3 | export * from './v1/client.v1'; 4 | export * from './v2/client.v2'; 5 | export * from './v2/includes.v2.helper'; 6 | export * from './v2-labs/client.v2.labs'; 7 | export * from './types'; 8 | export * from './paginators'; 9 | export * from './stream/TweetStream'; 10 | export * from './settings'; 11 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | var __importDefault = (this && this.__importDefault) || function (mod) { 17 | return (mod && mod.__esModule) ? mod : { "default": mod }; 18 | }; 19 | Object.defineProperty(exports, "__esModule", { value: true }); 20 | exports.default = void 0; 21 | var client_1 = require("./client"); 22 | Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(client_1).default; } }); 23 | __exportStar(require("./client"), exports); 24 | __exportStar(require("./v1/client.v1"), exports); 25 | __exportStar(require("./v2/client.v2"), exports); 26 | __exportStar(require("./v2/includes.v2.helper"), exports); 27 | __exportStar(require("./v2-labs/client.v2.labs"), exports); 28 | __exportStar(require("./types"), exports); 29 | __exportStar(require("./paginators"), exports); 30 | __exportStar(require("./stream/TweetStream"), exports); 31 | __exportStar(require("./settings"), exports); 32 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/dm.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import type { GetDmListV1Args, ReceivedDMEventsV1, TReceivedDMEvent, TwitterResponse, ReceivedWelcomeDMCreateEventV1, WelcomeDirectMessageListV1Result } from '../types'; 2 | import { CursoredV1Paginator } from './paginator.v1'; 3 | export declare class DmEventsV1Paginator extends CursoredV1Paginator { 4 | protected _endpoint: string; 5 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 6 | protected getPageLengthFromRequest(result: TwitterResponse): number; 7 | protected getItemArray(): import("../types").DirectMessageCreateV1[]; 8 | /** 9 | * Events returned by paginator. 10 | */ 11 | get events(): import("../types").DirectMessageCreateV1[]; 12 | } 13 | export declare class WelcomeDmV1Paginator extends CursoredV1Paginator { 14 | protected _endpoint: string; 15 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 16 | protected getPageLengthFromRequest(result: TwitterResponse): number; 17 | protected getItemArray(): ReceivedWelcomeDMCreateEventV1[]; 18 | get welcomeMessages(): ReceivedWelcomeDMCreateEventV1[]; 19 | } 20 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/dm.paginator.v1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.WelcomeDmV1Paginator = exports.DmEventsV1Paginator = void 0; 4 | const paginator_v1_1 = require("./paginator.v1"); 5 | class DmEventsV1Paginator extends paginator_v1_1.CursoredV1Paginator { 6 | constructor() { 7 | super(...arguments); 8 | this._endpoint = 'direct_messages/events/list.json'; 9 | } 10 | refreshInstanceFromResult(response, isNextPage) { 11 | const result = response.data; 12 | this._rateLimit = response.rateLimit; 13 | if (isNextPage) { 14 | this._realData.events.push(...result.events); 15 | this._realData.next_cursor = result.next_cursor; 16 | } 17 | } 18 | getPageLengthFromRequest(result) { 19 | return result.data.events.length; 20 | } 21 | getItemArray() { 22 | return this.events; 23 | } 24 | /** 25 | * Events returned by paginator. 26 | */ 27 | get events() { 28 | return this._realData.events; 29 | } 30 | } 31 | exports.DmEventsV1Paginator = DmEventsV1Paginator; 32 | class WelcomeDmV1Paginator extends paginator_v1_1.CursoredV1Paginator { 33 | constructor() { 34 | super(...arguments); 35 | this._endpoint = 'direct_messages/welcome_messages/list.json'; 36 | } 37 | refreshInstanceFromResult(response, isNextPage) { 38 | const result = response.data; 39 | this._rateLimit = response.rateLimit; 40 | if (isNextPage) { 41 | this._realData.welcome_messages.push(...result.welcome_messages); 42 | this._realData.next_cursor = result.next_cursor; 43 | } 44 | } 45 | getPageLengthFromRequest(result) { 46 | return result.data.welcome_messages.length; 47 | } 48 | getItemArray() { 49 | return this.welcomeMessages; 50 | } 51 | get welcomeMessages() { 52 | return this._realData.welcome_messages; 53 | } 54 | } 55 | exports.WelcomeDmV1Paginator = WelcomeDmV1Paginator; 56 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/followers.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import { CursoredV1Paginator } from './paginator.v1'; 2 | import type { UserFollowerIdsV1Params, UserFollowerIdsV1Result, UserFollowerListV1Params, UserFollowerListV1Result, TwitterResponse, UserV1 } from '../types'; 3 | export declare class UserFollowerListV1Paginator extends CursoredV1Paginator { 4 | protected _endpoint: string; 5 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 6 | protected getPageLengthFromRequest(result: TwitterResponse): number; 7 | protected getItemArray(): UserV1[]; 8 | /** 9 | * Users returned by paginator. 10 | */ 11 | get users(): UserV1[]; 12 | } 13 | export declare class UserFollowerIdsV1Paginator extends CursoredV1Paginator { 14 | protected _endpoint: string; 15 | protected _maxResultsWhenFetchLast: number; 16 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 17 | protected getPageLengthFromRequest(result: TwitterResponse): number; 18 | protected getItemArray(): string[]; 19 | /** 20 | * Users IDs returned by paginator. 21 | */ 22 | get ids(): string[]; 23 | } 24 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/followers.paginator.v1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.UserFollowerIdsV1Paginator = exports.UserFollowerListV1Paginator = void 0; 4 | const paginator_v1_1 = require("./paginator.v1"); 5 | class UserFollowerListV1Paginator extends paginator_v1_1.CursoredV1Paginator { 6 | constructor() { 7 | super(...arguments); 8 | this._endpoint = 'followers/list.json'; 9 | } 10 | refreshInstanceFromResult(response, isNextPage) { 11 | const result = response.data; 12 | this._rateLimit = response.rateLimit; 13 | if (isNextPage) { 14 | this._realData.users.push(...result.users); 15 | this._realData.next_cursor = result.next_cursor; 16 | } 17 | } 18 | getPageLengthFromRequest(result) { 19 | return result.data.users.length; 20 | } 21 | getItemArray() { 22 | return this.users; 23 | } 24 | /** 25 | * Users returned by paginator. 26 | */ 27 | get users() { 28 | return this._realData.users; 29 | } 30 | } 31 | exports.UserFollowerListV1Paginator = UserFollowerListV1Paginator; 32 | class UserFollowerIdsV1Paginator extends paginator_v1_1.CursoredV1Paginator { 33 | constructor() { 34 | super(...arguments); 35 | this._endpoint = 'followers/ids.json'; 36 | this._maxResultsWhenFetchLast = 5000; 37 | } 38 | refreshInstanceFromResult(response, isNextPage) { 39 | const result = response.data; 40 | this._rateLimit = response.rateLimit; 41 | if (isNextPage) { 42 | this._realData.ids.push(...result.ids); 43 | this._realData.next_cursor = result.next_cursor; 44 | } 45 | } 46 | getPageLengthFromRequest(result) { 47 | return result.data.ids.length; 48 | } 49 | getItemArray() { 50 | return this.ids; 51 | } 52 | /** 53 | * Users IDs returned by paginator. 54 | */ 55 | get ids() { 56 | return this._realData.ids; 57 | } 58 | } 59 | exports.UserFollowerIdsV1Paginator = UserFollowerIdsV1Paginator; 60 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/friends.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import { CursoredV1Paginator } from './paginator.v1'; 2 | import type { UserFollowerIdsV1Params, UserFollowerIdsV1Result, UserFriendListV1Params, UserFriendListV1Result, UserV1, TwitterResponse } from '../types'; 3 | export declare class UserFriendListV1Paginator extends CursoredV1Paginator { 4 | protected _endpoint: string; 5 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 6 | protected getPageLengthFromRequest(result: TwitterResponse): number; 7 | protected getItemArray(): UserV1[]; 8 | /** 9 | * Users returned by paginator. 10 | */ 11 | get users(): UserV1[]; 12 | } 13 | export declare class UserFollowersIdsV1Paginator extends CursoredV1Paginator { 14 | protected _endpoint: string; 15 | protected _maxResultsWhenFetchLast: number; 16 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 17 | protected getPageLengthFromRequest(result: TwitterResponse): number; 18 | protected getItemArray(): string[]; 19 | /** 20 | * Users IDs returned by paginator. 21 | */ 22 | get ids(): string[]; 23 | } 24 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/friends.paginator.v1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.UserFollowersIdsV1Paginator = exports.UserFriendListV1Paginator = void 0; 4 | const paginator_v1_1 = require("./paginator.v1"); 5 | class UserFriendListV1Paginator extends paginator_v1_1.CursoredV1Paginator { 6 | constructor() { 7 | super(...arguments); 8 | this._endpoint = 'friends/list.json'; 9 | } 10 | refreshInstanceFromResult(response, isNextPage) { 11 | const result = response.data; 12 | this._rateLimit = response.rateLimit; 13 | if (isNextPage) { 14 | this._realData.users.push(...result.users); 15 | this._realData.next_cursor = result.next_cursor; 16 | } 17 | } 18 | getPageLengthFromRequest(result) { 19 | return result.data.users.length; 20 | } 21 | getItemArray() { 22 | return this.users; 23 | } 24 | /** 25 | * Users returned by paginator. 26 | */ 27 | get users() { 28 | return this._realData.users; 29 | } 30 | } 31 | exports.UserFriendListV1Paginator = UserFriendListV1Paginator; 32 | class UserFollowersIdsV1Paginator extends paginator_v1_1.CursoredV1Paginator { 33 | constructor() { 34 | super(...arguments); 35 | this._endpoint = 'friends/ids.json'; 36 | this._maxResultsWhenFetchLast = 5000; 37 | } 38 | refreshInstanceFromResult(response, isNextPage) { 39 | const result = response.data; 40 | this._rateLimit = response.rateLimit; 41 | if (isNextPage) { 42 | this._realData.ids.push(...result.ids); 43 | this._realData.next_cursor = result.next_cursor; 44 | } 45 | } 46 | getPageLengthFromRequest(result) { 47 | return result.data.ids.length; 48 | } 49 | getItemArray() { 50 | return this.ids; 51 | } 52 | /** 53 | * Users IDs returned by paginator. 54 | */ 55 | get ids() { 56 | return this._realData.ids; 57 | } 58 | } 59 | exports.UserFollowersIdsV1Paginator = UserFollowersIdsV1Paginator; 60 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './tweet.paginator.v2'; 2 | export * from './TwitterPaginator'; 3 | export * from './dm.paginator.v1'; 4 | export * from './mutes.paginator.v1'; 5 | export * from './tweet.paginator.v1'; 6 | export * from './user.paginator.v1'; 7 | export * from './user.paginator.v2'; 8 | export * from './list.paginator.v1'; 9 | export * from './list.paginator.v2'; 10 | export * from './friends.paginator.v1'; 11 | export * from './followers.paginator.v1'; 12 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./tweet.paginator.v2"), exports); 18 | __exportStar(require("./TwitterPaginator"), exports); 19 | __exportStar(require("./dm.paginator.v1"), exports); 20 | __exportStar(require("./mutes.paginator.v1"), exports); 21 | __exportStar(require("./tweet.paginator.v1"), exports); 22 | __exportStar(require("./user.paginator.v1"), exports); 23 | __exportStar(require("./user.paginator.v2"), exports); 24 | __exportStar(require("./list.paginator.v1"), exports); 25 | __exportStar(require("./list.paginator.v2"), exports); 26 | __exportStar(require("./friends.paginator.v1"), exports); 27 | __exportStar(require("./followers.paginator.v1"), exports); 28 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/list.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import { DoubleEndedListsCursorV1Result, DoubleEndedUsersCursorV1Result, ListMembersV1Params, ListOwnershipsV1Params, ListV1, TwitterResponse, UserV1 } from '../types'; 2 | import { CursoredV1Paginator } from './paginator.v1'; 3 | declare abstract class ListListsV1Paginator extends CursoredV1Paginator { 4 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 5 | protected getPageLengthFromRequest(result: TwitterResponse): number; 6 | protected getItemArray(): ListV1[]; 7 | /** 8 | * Lists returned by paginator. 9 | */ 10 | get lists(): ListV1[]; 11 | } 12 | export declare class ListMembershipsV1Paginator extends ListListsV1Paginator { 13 | protected _endpoint: string; 14 | } 15 | export declare class ListOwnershipsV1Paginator extends ListListsV1Paginator { 16 | protected _endpoint: string; 17 | } 18 | export declare class ListSubscriptionsV1Paginator extends ListListsV1Paginator { 19 | protected _endpoint: string; 20 | } 21 | declare abstract class ListUsersV1Paginator extends CursoredV1Paginator { 22 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 23 | protected getPageLengthFromRequest(result: TwitterResponse): number; 24 | protected getItemArray(): UserV1[]; 25 | /** 26 | * Users returned by paginator. 27 | */ 28 | get users(): UserV1[]; 29 | } 30 | export declare class ListMembersV1Paginator extends ListUsersV1Paginator { 31 | protected _endpoint: string; 32 | } 33 | export declare class ListSubscribersV1Paginator extends ListUsersV1Paginator { 34 | protected _endpoint: string; 35 | } 36 | export {}; 37 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/list.paginator.v2.d.ts: -------------------------------------------------------------------------------- 1 | import type { GetListTimelineV2Params, ListTimelineV2Result, ListV2 } from '../types'; 2 | import { TimelineV2Paginator } from './v2.paginator'; 3 | declare abstract class ListTimelineV2Paginator extends TimelineV2Paginator { 4 | protected getItemArray(): ListV2[]; 5 | /** 6 | * Lists returned by paginator. 7 | */ 8 | get lists(): ListV2[]; 9 | get meta(): TResult["meta"]; 10 | } 11 | export declare class UserOwnedListsV2Paginator extends ListTimelineV2Paginator { 14 | protected _endpoint: string; 15 | } 16 | export declare class UserListMembershipsV2Paginator extends ListTimelineV2Paginator { 19 | protected _endpoint: string; 20 | } 21 | export declare class UserListFollowedV2Paginator extends ListTimelineV2Paginator { 24 | protected _endpoint: string; 25 | } 26 | export {}; 27 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/list.paginator.v2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.UserListFollowedV2Paginator = exports.UserListMembershipsV2Paginator = exports.UserOwnedListsV2Paginator = void 0; 4 | const v2_paginator_1 = require("./v2.paginator"); 5 | class ListTimelineV2Paginator extends v2_paginator_1.TimelineV2Paginator { 6 | getItemArray() { 7 | return this.lists; 8 | } 9 | /** 10 | * Lists returned by paginator. 11 | */ 12 | get lists() { 13 | var _a; 14 | return (_a = this._realData.data) !== null && _a !== void 0 ? _a : []; 15 | } 16 | get meta() { 17 | return super.meta; 18 | } 19 | } 20 | class UserOwnedListsV2Paginator extends ListTimelineV2Paginator { 21 | constructor() { 22 | super(...arguments); 23 | this._endpoint = 'users/:id/owned_lists'; 24 | } 25 | } 26 | exports.UserOwnedListsV2Paginator = UserOwnedListsV2Paginator; 27 | class UserListMembershipsV2Paginator extends ListTimelineV2Paginator { 28 | constructor() { 29 | super(...arguments); 30 | this._endpoint = 'users/:id/list_memberships'; 31 | } 32 | } 33 | exports.UserListMembershipsV2Paginator = UserListMembershipsV2Paginator; 34 | class UserListFollowedV2Paginator extends ListTimelineV2Paginator { 35 | constructor() { 36 | super(...arguments); 37 | this._endpoint = 'users/:id/followed_lists'; 38 | } 39 | } 40 | exports.UserListFollowedV2Paginator = UserListFollowedV2Paginator; 41 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/mutes.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import { CursoredV1Paginator } from './paginator.v1'; 2 | import type { MuteUserIdsV1Params, MuteUserIdsV1Result, MuteUserListV1Params, MuteUserListV1Result, TwitterResponse, UserV1 } from '../types'; 3 | export declare class MuteUserListV1Paginator extends CursoredV1Paginator { 4 | protected _endpoint: string; 5 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 6 | protected getPageLengthFromRequest(result: TwitterResponse): number; 7 | protected getItemArray(): UserV1[]; 8 | /** 9 | * Users returned by paginator. 10 | */ 11 | get users(): UserV1[]; 12 | } 13 | export declare class MuteUserIdsV1Paginator extends CursoredV1Paginator { 14 | protected _endpoint: string; 15 | protected _maxResultsWhenFetchLast: number; 16 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 17 | protected getPageLengthFromRequest(result: TwitterResponse): number; 18 | protected getItemArray(): string[]; 19 | /** 20 | * Users IDs returned by paginator. 21 | */ 22 | get ids(): string[]; 23 | } 24 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/mutes.paginator.v1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.MuteUserIdsV1Paginator = exports.MuteUserListV1Paginator = void 0; 4 | const paginator_v1_1 = require("./paginator.v1"); 5 | class MuteUserListV1Paginator extends paginator_v1_1.CursoredV1Paginator { 6 | constructor() { 7 | super(...arguments); 8 | this._endpoint = 'mutes/users/list.json'; 9 | } 10 | refreshInstanceFromResult(response, isNextPage) { 11 | const result = response.data; 12 | this._rateLimit = response.rateLimit; 13 | if (isNextPage) { 14 | this._realData.users.push(...result.users); 15 | this._realData.next_cursor = result.next_cursor; 16 | } 17 | } 18 | getPageLengthFromRequest(result) { 19 | return result.data.users.length; 20 | } 21 | getItemArray() { 22 | return this.users; 23 | } 24 | /** 25 | * Users returned by paginator. 26 | */ 27 | get users() { 28 | return this._realData.users; 29 | } 30 | } 31 | exports.MuteUserListV1Paginator = MuteUserListV1Paginator; 32 | class MuteUserIdsV1Paginator extends paginator_v1_1.CursoredV1Paginator { 33 | constructor() { 34 | super(...arguments); 35 | this._endpoint = 'mutes/users/ids.json'; 36 | this._maxResultsWhenFetchLast = 5000; 37 | } 38 | refreshInstanceFromResult(response, isNextPage) { 39 | const result = response.data; 40 | this._rateLimit = response.rateLimit; 41 | if (isNextPage) { 42 | this._realData.ids.push(...result.ids); 43 | this._realData.next_cursor = result.next_cursor; 44 | } 45 | } 46 | getPageLengthFromRequest(result) { 47 | return result.data.ids.length; 48 | } 49 | getItemArray() { 50 | return this.ids; 51 | } 52 | /** 53 | * Users IDs returned by paginator. 54 | */ 55 | get ids() { 56 | return this._realData.ids; 57 | } 58 | } 59 | exports.MuteUserIdsV1Paginator = MuteUserIdsV1Paginator; 60 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import { TwitterResponse } from '../types'; 2 | import TwitterPaginator from './TwitterPaginator'; 3 | export declare abstract class CursoredV1Paginator extends TwitterPaginator { 9 | protected getNextQueryParams(maxResults?: number): Partial; 10 | protected isFetchLastOver(result: TwitterResponse): boolean; 11 | protected canFetchNextPage(result: TApiResult): boolean; 12 | private isNextCursorInvalid; 13 | } 14 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/paginator.v1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.CursoredV1Paginator = void 0; 7 | const TwitterPaginator_1 = __importDefault(require("./TwitterPaginator")); 8 | class CursoredV1Paginator extends TwitterPaginator_1.default { 9 | getNextQueryParams(maxResults) { 10 | var _a; 11 | return { 12 | ...this._queryParams, 13 | cursor: (_a = this._realData.next_cursor_str) !== null && _a !== void 0 ? _a : this._realData.next_cursor, 14 | ...(maxResults ? { count: maxResults } : {}), 15 | }; 16 | } 17 | isFetchLastOver(result) { 18 | // If we cant fetch next page 19 | return !this.canFetchNextPage(result.data); 20 | } 21 | canFetchNextPage(result) { 22 | // If one of cursor is valid 23 | return !this.isNextCursorInvalid(result.next_cursor) || !this.isNextCursorInvalid(result.next_cursor_str); 24 | } 25 | isNextCursorInvalid(value) { 26 | return value === undefined 27 | || value === 0 28 | || value === -1 29 | || value === '0' 30 | || value === '-1'; 31 | } 32 | } 33 | exports.CursoredV1Paginator = CursoredV1Paginator; 34 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/tweet.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterPaginator from './TwitterPaginator'; 2 | import { TwitterResponse, TweetV1, TweetV1TimelineResult, TweetV1TimelineParams, TweetV1UserTimelineParams, ListStatusesV1Params } from '../types'; 3 | /** A generic TwitterPaginator able to consume TweetV1 timelines. */ 4 | declare abstract class TweetTimelineV1Paginator extends TwitterPaginator { 5 | protected hasFinishedFetch: boolean; 6 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 7 | protected getNextQueryParams(maxResults?: number): { 8 | max_results?: number | undefined; 9 | } & Partial & { 10 | max_id: string; 11 | }; 12 | protected getPageLengthFromRequest(result: TwitterResponse): number; 13 | protected isFetchLastOver(result: TwitterResponse): boolean; 14 | protected canFetchNextPage(result: TResult): boolean; 15 | protected getItemArray(): TResult; 16 | /** 17 | * Tweets returned by paginator. 18 | */ 19 | get tweets(): TResult; 20 | get done(): boolean; 21 | } 22 | export declare class HomeTimelineV1Paginator extends TweetTimelineV1Paginator { 23 | protected _endpoint: string; 24 | } 25 | export declare class MentionTimelineV1Paginator extends TweetTimelineV1Paginator { 26 | protected _endpoint: string; 27 | } 28 | export declare class UserTimelineV1Paginator extends TweetTimelineV1Paginator { 29 | protected _endpoint: string; 30 | } 31 | export declare class ListTimelineV1Paginator extends TweetTimelineV1Paginator { 32 | protected _endpoint: string; 33 | } 34 | export declare class UserFavoritesV1Paginator extends TweetTimelineV1Paginator { 35 | protected _endpoint: string; 36 | } 37 | export {}; 38 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/user.paginator.v1.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterPaginator from './TwitterPaginator'; 2 | import { FriendshipsIncomingV1Params, FriendshipsIncomingV1Result, TwitterResponse, UserSearchV1Params, UserV1 } from '../types'; 3 | import { CursoredV1Paginator } from './paginator.v1'; 4 | /** A generic TwitterPaginator able to consume TweetV1 timelines. */ 5 | export declare class UserSearchV1Paginator extends TwitterPaginator { 6 | _endpoint: string; 7 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 8 | protected getNextQueryParams(maxResults?: number): { 9 | count?: number | undefined; 10 | page: number; 11 | q?: string | undefined; 12 | include_entities?: boolean | undefined; 13 | tweet_mode?: "extended" | undefined; 14 | }; 15 | protected getPageLengthFromRequest(result: TwitterResponse): number; 16 | protected isFetchLastOver(result: TwitterResponse): boolean; 17 | protected canFetchNextPage(result: UserV1[]): boolean; 18 | protected getItemArray(): UserV1[]; 19 | /** 20 | * Users returned by paginator. 21 | */ 22 | get users(): UserV1[]; 23 | } 24 | export declare class FriendshipsIncomingV1Paginator extends CursoredV1Paginator { 25 | protected _endpoint: string; 26 | protected _maxResultsWhenFetchLast: number; 27 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: true): void; 28 | protected getPageLengthFromRequest(result: TwitterResponse): number; 29 | protected getItemArray(): string[]; 30 | /** 31 | * Users IDs returned by paginator. 32 | */ 33 | get ids(): string[]; 34 | } 35 | export declare class FriendshipsOutgoingV1Paginator extends FriendshipsIncomingV1Paginator { 36 | protected _endpoint: string; 37 | } 38 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/user.paginator.v2.d.ts: -------------------------------------------------------------------------------- 1 | import { UserV2, UserV2TimelineParams, UserV2TimelineResult } from '../types'; 2 | import { TimelineV2Paginator } from './v2.paginator'; 3 | /** A generic PreviousableTwitterPaginator able to consume UserV2 timelines. */ 4 | declare abstract class UserTimelineV2Paginator extends TimelineV2Paginator { 5 | protected getItemArray(): UserV2[]; 6 | /** 7 | * Users returned by paginator. 8 | */ 9 | get users(): UserV2[]; 10 | get meta(): TResult["meta"]; 11 | } 12 | export declare class UserBlockingUsersV2Paginator extends UserTimelineV2Paginator { 15 | protected _endpoint: string; 16 | } 17 | export declare class UserMutingUsersV2Paginator extends UserTimelineV2Paginator { 20 | protected _endpoint: string; 21 | } 22 | export declare class UserFollowersV2Paginator extends UserTimelineV2Paginator { 25 | protected _endpoint: string; 26 | } 27 | export declare class UserFollowingV2Paginator extends UserTimelineV2Paginator { 30 | protected _endpoint: string; 31 | } 32 | export declare class UserListMembersV2Paginator extends UserTimelineV2Paginator { 35 | protected _endpoint: string; 36 | } 37 | export declare class UserListFollowersV2Paginator extends UserTimelineV2Paginator { 40 | protected _endpoint: string; 41 | } 42 | export declare class TweetLikingUsersV2Paginator extends UserTimelineV2Paginator { 45 | protected _endpoint: string; 46 | } 47 | export declare class TweetRetweetersUsersV2Paginator extends UserTimelineV2Paginator { 50 | protected _endpoint: string; 51 | } 52 | export {}; 53 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/paginators/v2.paginator.d.ts: -------------------------------------------------------------------------------- 1 | import type { TwitterResponse } from '../types'; 2 | import type { DataMetaAndIncludeV2 } from '../types/v2/shared.v2.types'; 3 | import { TwitterV2IncludesHelper } from '../v2/includes.v2.helper'; 4 | import { PreviousableTwitterPaginator } from './TwitterPaginator'; 5 | /** A generic PreviousableTwitterPaginator with common v2 helper methods. */ 6 | export declare abstract class TwitterV2Paginator, TParams extends object, TItem, TShared = any> extends PreviousableTwitterPaginator { 7 | protected _includesInstance?: TwitterV2IncludesHelper; 8 | protected updateIncludes(data: TResult): void; 9 | /** Throw if the current paginator is not usable. */ 10 | protected assertUsable(): void; 11 | get meta(): any; 12 | get includes(): TwitterV2IncludesHelper; 13 | get errors(): import("../types").InlineErrorV2[]; 14 | /** `true` if this paginator only contains error payload and no metadata found to consume data. */ 15 | get unusable(): boolean; 16 | } 17 | /** A generic TwitterV2Paginator able to consume v2 timelines that use max_results and pagination tokens. */ 18 | export declare abstract class TimelineV2Paginator, TParams extends { 19 | max_results?: number; 20 | pagination_token?: string; 21 | }, TItem, TShared = any> extends TwitterV2Paginator { 22 | protected refreshInstanceFromResult(response: TwitterResponse, isNextPage: boolean): void; 23 | protected getNextQueryParams(maxResults?: number): { 24 | max_results?: number | undefined; 25 | } & Partial & { 26 | pagination_token: any; 27 | }; 28 | protected getPreviousQueryParams(maxResults?: number): { 29 | max_results?: number | undefined; 30 | } & Partial & { 31 | pagination_token: any; 32 | }; 33 | protected getPageLengthFromRequest(result: TwitterResponse): any; 34 | protected isFetchLastOver(result: TwitterResponse): boolean; 35 | protected canFetchNextPage(result: TResult): boolean; 36 | } 37 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/plugins/helpers.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { ClientRequestArgs } from 'http'; 3 | import type { ClientRequestMaker } from '../client-mixins/request-maker.mixin'; 4 | import { IGetHttpRequestArgs } from '../types'; 5 | import type { IComputedHttpRequestArgs } from '../types/request-maker.mixin.types'; 6 | export declare function hasRequestErrorPlugins(client: ClientRequestMaker): boolean; 7 | export declare function applyResponseHooks(this: ClientRequestMaker, requestParams: IGetHttpRequestArgs, computedParams: IComputedHttpRequestArgs, requestOptions: Partial, error: any): Promise; 8 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/plugins/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.applyResponseHooks = exports.hasRequestErrorPlugins = void 0; 4 | const types_1 = require("../types"); 5 | /* Plugin helpers */ 6 | function hasRequestErrorPlugins(client) { 7 | var _a; 8 | if (!((_a = client.clientSettings.plugins) === null || _a === void 0 ? void 0 : _a.length)) { 9 | return false; 10 | } 11 | for (const plugin of client.clientSettings.plugins) { 12 | if (plugin.onRequestError || plugin.onResponseError) { 13 | return true; 14 | } 15 | } 16 | return false; 17 | } 18 | exports.hasRequestErrorPlugins = hasRequestErrorPlugins; 19 | async function applyResponseHooks(requestParams, computedParams, requestOptions, error) { 20 | let override; 21 | if (error instanceof types_1.ApiRequestError || error instanceof types_1.ApiPartialResponseError) { 22 | override = await this.applyPluginMethod('onRequestError', { 23 | client: this, 24 | url: this.getUrlObjectFromUrlString(requestParams.url), 25 | params: requestParams, 26 | computedParams, 27 | requestOptions, 28 | error, 29 | }); 30 | } 31 | else if (error instanceof types_1.ApiResponseError) { 32 | override = await this.applyPluginMethod('onResponseError', { 33 | client: this, 34 | url: this.getUrlObjectFromUrlString(requestParams.url), 35 | params: requestParams, 36 | computedParams, 37 | requestOptions, 38 | error, 39 | }); 40 | } 41 | if (override && override instanceof types_1.TwitterApiPluginResponseOverride) { 42 | return override.value; 43 | } 44 | return Promise.reject(error); 45 | } 46 | exports.applyResponseHooks = applyResponseHooks; 47 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/settings.d.ts: -------------------------------------------------------------------------------- 1 | export interface ITwitterApiV2Settings { 2 | debug: boolean; 3 | deprecationWarnings: boolean; 4 | logger: ITwitterApiV2SettingsLogger; 5 | } 6 | export interface ITwitterApiV2SettingsLogger { 7 | log(message: string, payload?: any): void; 8 | } 9 | export declare const TwitterApiV2Settings: ITwitterApiV2Settings; 10 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/settings.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.TwitterApiV2Settings = void 0; 4 | exports.TwitterApiV2Settings = { 5 | debug: false, 6 | deprecationWarnings: true, 7 | logger: { log: console.log.bind(console) }, 8 | }; 9 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/stream/TweetStreamEventCombiner.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { EventEmitter } from 'events'; 3 | import type TweetStream from './TweetStream'; 4 | export declare class TweetStreamEventCombiner extends EventEmitter { 5 | private stream; 6 | private stack; 7 | private onceNewEvent; 8 | constructor(stream: TweetStream); 9 | /** Returns a new `Promise` that will `resolve` on next event (`data` or any sort of error). */ 10 | nextEvent(): Promise<{ 11 | type: "error"; 12 | payload?: any; 13 | } | { 14 | type: "data"; 15 | payload: T; 16 | }>; 17 | /** Returns `true` if there's something in the stack. */ 18 | hasStack(): boolean; 19 | /** Returns stacked data events, and clean the stack. */ 20 | popStack(): T[]; 21 | /** Cleanup all the listeners attached on stream. */ 22 | destroy(): void; 23 | private emitEvent; 24 | private onStreamError; 25 | private onStreamData; 26 | } 27 | export default TweetStreamEventCombiner; 28 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/stream/TweetStreamParser.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { EventEmitter } from 'events'; 3 | export default class TweetStreamParser extends EventEmitter { 4 | protected currentMessage: string; 5 | push(chunk: string): void; 6 | /** Reset the currently stored message (f.e. on connection reset) */ 7 | reset(): void; 8 | } 9 | export declare enum EStreamParserEvent { 10 | ParsedData = "parsed data", 11 | ParseError = "parse error" 12 | } 13 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/stream/TweetStreamParser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.EStreamParserEvent = void 0; 4 | const events_1 = require("events"); 5 | class TweetStreamParser extends events_1.EventEmitter { 6 | constructor() { 7 | super(...arguments); 8 | this.currentMessage = ''; 9 | } 10 | // Code partially belongs to twitter-stream-api for this 11 | // https://github.com/trygve-lie/twitter-stream-api/blob/master/lib/parser.js 12 | push(chunk) { 13 | this.currentMessage += chunk; 14 | chunk = this.currentMessage; 15 | const size = chunk.length; 16 | let start = 0; 17 | let offset = 0; 18 | while (offset < size) { 19 | // Take [offset, offset+1] inside a new string 20 | if (chunk.slice(offset, offset + 2) === '\r\n') { 21 | // If chunk contains \r\n after current offset, 22 | // parse [start, ..., offset] as a tweet 23 | const piece = chunk.slice(start, offset); 24 | start = offset += 2; 25 | // If empty object 26 | if (!piece.length) { 27 | continue; 28 | } 29 | try { 30 | const payload = JSON.parse(piece); 31 | if (payload) { 32 | this.emit(EStreamParserEvent.ParsedData, payload); 33 | continue; 34 | } 35 | } 36 | catch (error) { 37 | this.emit(EStreamParserEvent.ParseError, error); 38 | } 39 | } 40 | offset++; 41 | } 42 | this.currentMessage = chunk.slice(start, size); 43 | } 44 | /** Reset the currently stored message (f.e. on connection reset) */ 45 | reset() { 46 | this.currentMessage = ''; 47 | } 48 | } 49 | exports.default = TweetStreamParser; 50 | var EStreamParserEvent; 51 | (function (EStreamParserEvent) { 52 | EStreamParserEvent["ParsedData"] = "parsed data"; 53 | EStreamParserEvent["ParseError"] = "parse error"; 54 | })(EStreamParserEvent = exports.EStreamParserEvent || (exports.EStreamParserEvent = {})); 55 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/test/utils.d.ts: -------------------------------------------------------------------------------- 1 | import { TwitterApi } from '..'; 2 | /** User OAuth 1.0a client */ 3 | export declare function getUserClient(this: any): TwitterApi; 4 | export declare function getUserKeys(): { 5 | appKey: string; 6 | appSecret: string; 7 | accessToken: string; 8 | accessSecret: string; 9 | }; 10 | export declare function sleepTest(ms: number): Promise; 11 | /** User-unlogged OAuth 1.0a client */ 12 | export declare function getRequestClient(): TwitterApi; 13 | export declare function getRequestKeys(): { 14 | appKey: string; 15 | appSecret: string; 16 | }; 17 | export declare function getAuthLink(callback: string): Promise<{ 18 | oauth_token: string; 19 | oauth_token_secret: string; 20 | oauth_callback_confirmed: "true"; 21 | url: string; 22 | }>; 23 | export declare function getAccessClient(verifier: string): Promise; 24 | /** App OAuth 2.0 client */ 25 | export declare function getAppClient(): Promise; 26 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/auth.types.d.ts: -------------------------------------------------------------------------------- 1 | import type TwitterApi from '../client'; 2 | import { TypeOrArrayOf } from './shared.types'; 3 | export declare type TOAuth2Scope = 'tweet.read' | 'tweet.write' | 'tweet.moderate.write' | 'users.read' | 'follows.read' | 'follows.write' | 'offline.access' | 'space.read' | 'mute.read' | 'mute.write' | 'like.read' | 'like.write' | 'list.read' | 'list.write' | 'block.read' | 'block.write' | 'bookmark.read' | 'bookmark.write'; 4 | export interface BuildOAuth2RequestLinkArgs { 5 | scope?: TypeOrArrayOf | TypeOrArrayOf; 6 | state?: string; 7 | } 8 | export interface AccessOAuth2TokenArgs { 9 | /** The same URI given to generate link at previous step. */ 10 | redirectUri: string; 11 | /** The code obtained in link generation step. */ 12 | codeVerifier: string; 13 | /** The code given by Twitter in query string, after redirection to your callback URL. */ 14 | code: string; 15 | } 16 | export interface AccessOAuth2TokenResult { 17 | token_type: 'bearer'; 18 | expires_in: number; 19 | access_token: string; 20 | scope: string; 21 | refresh_token?: string; 22 | } 23 | export interface RequestTokenArgs { 24 | authAccessType: 'read' | 'write'; 25 | linkMode: 'authenticate' | 'authorize'; 26 | forceLogin: boolean; 27 | screenName: string; 28 | } 29 | export interface RequestTokenResult { 30 | oauth_token: string; 31 | oauth_token_secret: string; 32 | oauth_callback_confirmed: 'true'; 33 | } 34 | export interface IOAuth2RequestTokenResult { 35 | url: string; 36 | state: string; 37 | codeVerifier: string; 38 | codeChallenge: string; 39 | } 40 | export interface AccessTokenResult { 41 | oauth_token: string; 42 | oauth_token_secret: string; 43 | user_id: string; 44 | screen_name: string; 45 | } 46 | export interface BearerTokenResult { 47 | token_type: 'bearer'; 48 | access_token: string; 49 | } 50 | export interface LoginResult { 51 | userId: string; 52 | screenName: string; 53 | accessToken: string; 54 | accessSecret: string; 55 | client: TwitterApi; 56 | } 57 | export interface IParsedOAuth2TokenResult { 58 | client: TwitterApi; 59 | expiresIn: number; 60 | accessToken: string; 61 | scope: TOAuth2Scope[]; 62 | refreshToken?: string; 63 | } 64 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/auth.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/client.types.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { Agent } from 'http'; 3 | import type { ITwitterApiClientPlugin } from './plugins'; 4 | import type { TRequestCompressionLevel } from './request-maker.mixin.types'; 5 | export declare enum ETwitterStreamEvent { 6 | Connected = "connected", 7 | ConnectError = "connect error", 8 | ConnectionError = "connection error", 9 | ConnectionClosed = "connection closed", 10 | ConnectionLost = "connection lost", 11 | ReconnectAttempt = "reconnect attempt", 12 | Reconnected = "reconnected", 13 | ReconnectError = "reconnect error", 14 | ReconnectLimitExceeded = "reconnect limit exceeded", 15 | DataKeepAlive = "data keep-alive", 16 | Data = "data event content", 17 | DataError = "data twitter error", 18 | TweetParseError = "data tweet parse error", 19 | Error = "stream error" 20 | } 21 | export interface TwitterApiTokens { 22 | appKey: string; 23 | appSecret: string; 24 | accessToken?: string; 25 | accessSecret?: string; 26 | } 27 | export interface TwitterApiOAuth2Init { 28 | clientId: string; 29 | clientSecret?: string; 30 | } 31 | export interface TwitterApiBasicAuth { 32 | username: string; 33 | password: string; 34 | } 35 | export interface IClientTokenBearer { 36 | bearerToken: string; 37 | type: 'oauth2'; 38 | } 39 | export interface IClientOAuth2UserClient { 40 | clientId: string; 41 | type: 'oauth2-user'; 42 | } 43 | export interface IClientTokenBasic { 44 | token: string; 45 | type: 'basic'; 46 | } 47 | export interface IClientTokenOauth { 48 | appKey: string; 49 | appSecret: string; 50 | accessToken?: string; 51 | accessSecret?: string; 52 | type: 'oauth-1.0a'; 53 | } 54 | export interface IClientTokenNone { 55 | type: 'none'; 56 | } 57 | export declare type TClientTokens = IClientTokenNone | IClientTokenBearer | IClientTokenOauth | IClientTokenBasic | IClientOAuth2UserClient; 58 | export interface IClientSettings { 59 | /** Used to send HTTPS requests. This is mostly used to make requests work behind a proxy. */ 60 | httpAgent: Agent; 61 | plugins: ITwitterApiClientPlugin[]; 62 | compression: TRequestCompressionLevel; 63 | } 64 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/client.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ETwitterStreamEvent = void 0; 4 | var ETwitterStreamEvent; 5 | (function (ETwitterStreamEvent) { 6 | ETwitterStreamEvent["Connected"] = "connected"; 7 | ETwitterStreamEvent["ConnectError"] = "connect error"; 8 | ETwitterStreamEvent["ConnectionError"] = "connection error"; 9 | ETwitterStreamEvent["ConnectionClosed"] = "connection closed"; 10 | ETwitterStreamEvent["ConnectionLost"] = "connection lost"; 11 | ETwitterStreamEvent["ReconnectAttempt"] = "reconnect attempt"; 12 | ETwitterStreamEvent["Reconnected"] = "reconnected"; 13 | ETwitterStreamEvent["ReconnectError"] = "reconnect error"; 14 | ETwitterStreamEvent["ReconnectLimitExceeded"] = "reconnect limit exceeded"; 15 | ETwitterStreamEvent["DataKeepAlive"] = "data keep-alive"; 16 | ETwitterStreamEvent["Data"] = "data event content"; 17 | ETwitterStreamEvent["DataError"] = "data twitter error"; 18 | ETwitterStreamEvent["TweetParseError"] = "data tweet parse error"; 19 | ETwitterStreamEvent["Error"] = "stream error"; 20 | })(ETwitterStreamEvent = exports.ETwitterStreamEvent || (exports.ETwitterStreamEvent = {})); 21 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/entities.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Entity { 2 | start: number; 3 | end: number; 4 | } 5 | export interface UrlEntity extends Entity { 6 | url: string; 7 | expanded_url: string; 8 | display_url: string; 9 | } 10 | export interface HashtagEntity extends Entity { 11 | hashtag: string; 12 | } 13 | export interface CashtagEntity extends Entity { 14 | cashtag: string; 15 | } 16 | export interface MentionEntity extends Entity { 17 | username: string; 18 | } 19 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/entities.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './v1'; 2 | export * from './v2'; 3 | export * from './errors.types'; 4 | export * from './responses.types'; 5 | export * from './client.types'; 6 | export * from './auth.types'; 7 | export * from './plugins'; 8 | export { IGetHttpRequestArgs } from './request-maker.mixin.types'; 9 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./v1"), exports); 18 | __exportStar(require("./v2"), exports); 19 | __exportStar(require("./errors.types"), exports); 20 | __exportStar(require("./responses.types"), exports); 21 | __exportStar(require("./client.types"), exports); 22 | __exportStar(require("./auth.types"), exports); 23 | __exportStar(require("./plugins"), exports); 24 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/plugins/client.plugins.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.TwitterApiPluginResponseOverride = void 0; 4 | class TwitterApiPluginResponseOverride { 5 | constructor(value) { 6 | this.value = value; 7 | } 8 | } 9 | exports.TwitterApiPluginResponseOverride = TwitterApiPluginResponseOverride; 10 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/plugins/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './client.plugins.types'; 2 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/plugins/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./client.plugins.types"), exports); 18 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/request-maker.mixin.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/responses.types.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { IncomingHttpHeaders } from 'http'; 3 | export interface TwitterResponse { 4 | headers: IncomingHttpHeaders; 5 | data: T; 6 | rateLimit?: TwitterRateLimit; 7 | } 8 | export interface TwitterRateLimit { 9 | limit: number; 10 | reset: number; 11 | remaining: number; 12 | } 13 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/responses.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/shared.types.d.ts: -------------------------------------------------------------------------------- 1 | export declare type NumberString = number | string; 2 | export declare type BooleanString = boolean | string; 3 | export declare type TypeOrArrayOf = T | T[]; 4 | export declare type PromiseOrType = T | Promise; 5 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/shared.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/dev-utilities.v1.types.d.ts: -------------------------------------------------------------------------------- 1 | export declare type TAppRateLimitResourceV1 = 'help' | 'statuses' | 'friends' | 'followers' | 'users' | 'search' | 'trends' | 'favorites' | 'friendships' | 'direct_messages' | 'lists' | 'geo' | 'account' | 'application' | 'account_activity'; 2 | export interface AppRateLimitV1Result { 3 | rate_limit_context: { 4 | access_token: string; 5 | }; 6 | resources: { 7 | [TResourceName in TAppRateLimitResourceV1]?: { 8 | [resourceEndpoint: string]: AppRateLimitEndpointV1; 9 | }; 10 | }; 11 | } 12 | export interface AppRateLimitEndpointV1 { 13 | limit: number; 14 | remaining: number; 15 | reset: number; 16 | } 17 | export interface HelpLanguageV1Result { 18 | code: string; 19 | status: string; 20 | name: string; 21 | } 22 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/dev-utilities.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/dm.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.EDirectMessageEventTypeV1 = void 0; 4 | // Creation of DMs 5 | var EDirectMessageEventTypeV1; 6 | (function (EDirectMessageEventTypeV1) { 7 | EDirectMessageEventTypeV1["Create"] = "message_create"; 8 | EDirectMessageEventTypeV1["WelcomeCreate"] = "welcome_message"; 9 | })(EDirectMessageEventTypeV1 = exports.EDirectMessageEventTypeV1 || (exports.EDirectMessageEventTypeV1 = {})); 10 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/entities.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/geo.v1.types.d.ts: -------------------------------------------------------------------------------- 1 | import { PlaceV1 } from './entities.v1.types'; 2 | export interface ReverseGeoCodeV1Params { 3 | lat: number; 4 | long: number; 5 | accuracy?: string; 6 | granularity?: 'city' | 'neighborhood' | 'country' | 'admin'; 7 | max_results?: number; 8 | } 9 | export interface ReverseGeoCodeV1Result { 10 | query: { 11 | params: Partial; 12 | type: string; 13 | url: string; 14 | }; 15 | result: { 16 | places: PlaceV1[]; 17 | }; 18 | } 19 | export interface SearchGeoV1Params extends Partial { 20 | ip?: string; 21 | query?: string; 22 | } 23 | export interface SearchGeoV1Result { 24 | query: { 25 | params: SearchGeoV1Params; 26 | type: string; 27 | url: string; 28 | }; 29 | result: { 30 | places: PlaceV1[]; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/geo.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './streaming.v1.types'; 2 | export * from './tweet.v1.types'; 3 | export * from './entities.v1.types'; 4 | export * from './user.v1.types'; 5 | export * from './dev-utilities.v1.types'; 6 | export * from './geo.v1.types'; 7 | export * from './trends.v1.types'; 8 | export * from './dm.v1.types'; 9 | export * from './list.v1.types'; 10 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./streaming.v1.types"), exports); 18 | __exportStar(require("./tweet.v1.types"), exports); 19 | __exportStar(require("./entities.v1.types"), exports); 20 | __exportStar(require("./user.v1.types"), exports); 21 | __exportStar(require("./dev-utilities.v1.types"), exports); 22 | __exportStar(require("./geo.v1.types"), exports); 23 | __exportStar(require("./trends.v1.types"), exports); 24 | __exportStar(require("./dm.v1.types"), exports); 25 | __exportStar(require("./list.v1.types"), exports); 26 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/list.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/streaming.v1.types.d.ts: -------------------------------------------------------------------------------- 1 | import type { TypeOrArrayOf } from '../shared.types'; 2 | export interface AskTweetStreamV1Params { 3 | tweet_mode?: 'extended' | 'compat'; 4 | /** Specifies whether stall warnings should be delivered. */ 5 | stall_warnings: boolean; 6 | } 7 | /** 8 | * See https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/guides/basic-stream-parameters 9 | * for detailed documentation. 10 | */ 11 | export interface FilterStreamV1Params extends AskTweetStreamV1Params { 12 | /** A list of user IDs, indicating the users to return statuses for in the stream. */ 13 | follow: TypeOrArrayOf<(string | BigInt)>; 14 | /** Keywords to track. */ 15 | track: TypeOrArrayOf; 16 | /** Specifies a set of bounding boxes to track. */ 17 | locations: TypeOrArrayOf<{ 18 | lng: string; 19 | lat: string; 20 | }>; 21 | /** Specifies whether stall warnings should be delivered. */ 22 | stall_warnings: boolean; 23 | [otherParameter: string]: any; 24 | } 25 | export interface SampleStreamV1Params extends AskTweetStreamV1Params { 26 | [otherParameter: string]: any; 27 | } 28 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/streaming.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/trends.v1.types.d.ts: -------------------------------------------------------------------------------- 1 | import { TrendLocationV1, TrendV1 } from './entities.v1.types'; 2 | export interface TrendsPlaceV1Params { 3 | exclude: string; 4 | } 5 | export interface TrendMatchV1 { 6 | trends: TrendV1[]; 7 | as_of: string; 8 | created_at: string; 9 | locations: TrendLocationV1[]; 10 | } 11 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/trends.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/tweet.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.EUploadMimeType = void 0; 4 | var EUploadMimeType; 5 | (function (EUploadMimeType) { 6 | EUploadMimeType["Jpeg"] = "image/jpeg"; 7 | EUploadMimeType["Mp4"] = "video/mp4"; 8 | EUploadMimeType["Gif"] = "image/gif"; 9 | EUploadMimeType["Png"] = "image/png"; 10 | EUploadMimeType["Srt"] = "text/plain"; 11 | EUploadMimeType["Webp"] = "image/webp"; 12 | })(EUploadMimeType = exports.EUploadMimeType || (exports.EUploadMimeType = {})); 13 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v1/user.v1.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './streaming.v2.types'; 2 | export * from './tweet.v2.types'; 3 | export * from './tweet.definition.v2'; 4 | export * from './user.v2.types'; 5 | export * from './spaces.v2.types'; 6 | export * from './list.v2.types'; 7 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./streaming.v2.types"), exports); 18 | __exportStar(require("./tweet.v2.types"), exports); 19 | __exportStar(require("./tweet.definition.v2"), exports); 20 | __exportStar(require("./user.v2.types"), exports); 21 | __exportStar(require("./spaces.v2.types"), exports); 22 | __exportStar(require("./list.v2.types"), exports); 23 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/list.v2.types.d.ts: -------------------------------------------------------------------------------- 1 | import type { TypeOrArrayOf } from '../shared.types'; 2 | import type { DataAndIncludeV2, DataMetaAndIncludeV2, DataV2 } from './shared.v2.types'; 3 | import type { TTweetv2UserField } from './tweet.v2.types'; 4 | import type { UserV2 } from './user.v2.types'; 5 | export declare type TListV2Field = 'created_at' | 'follower_count' | 'member_count' | 'private' | 'description' | 'owner_id'; 6 | export declare type TListV2Expansion = 'owner_id'; 7 | export declare type TListV2Includes = { 8 | users?: UserV2[]; 9 | }; 10 | export interface ListV2 { 11 | id: string; 12 | name: string; 13 | created_at?: string; 14 | private?: boolean; 15 | follower_count?: number; 16 | member_count?: number; 17 | owner_id?: string; 18 | description?: string; 19 | } 20 | export interface ListCreateV2Params { 21 | name: string; 22 | description?: string; 23 | private?: boolean; 24 | } 25 | export interface GetListV2Params { 26 | expansions: TypeOrArrayOf | string; 27 | 'list.fields': TypeOrArrayOf | string; 28 | 'user.fields': TypeOrArrayOf | string; 29 | } 30 | export interface GetListTimelineV2Params extends Partial { 31 | max_results?: number; 32 | pagination_token?: string; 33 | } 34 | export declare type ListGetV2Result = DataAndIncludeV2; 35 | export declare type ListTimelineV2Result = DataMetaAndIncludeV2; 40 | export declare type ListCreateV2Result = DataV2<{ 41 | id: string; 42 | name: string; 43 | }>; 44 | export declare type ListUpdateV2Params = Omit & { 45 | name?: string; 46 | }; 47 | export declare type ListUpdateV2Result = DataV2<{ 48 | updated: true; 49 | }>; 50 | export declare type ListDeleteV2Result = DataV2<{ 51 | deleted: true; 52 | }>; 53 | export declare type ListMemberV2Result = DataV2<{ 54 | is_member: boolean; 55 | }>; 56 | export declare type ListFollowV2Result = DataV2<{ 57 | following: boolean; 58 | }>; 59 | export declare type ListPinV2Result = DataV2<{ 60 | pinned: boolean; 61 | }>; 62 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/list.v2.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/shared.v2.types.d.ts: -------------------------------------------------------------------------------- 1 | import type { InlineErrorV2 } from '../errors.types'; 2 | export declare type MetaV2 = { 3 | meta: M; 4 | errors?: InlineErrorV2[]; 5 | }; 6 | export declare type DataV2 = { 7 | data: D; 8 | errors?: InlineErrorV2[]; 9 | }; 10 | export declare type IncludeV2 = { 11 | includes?: I; 12 | errors?: InlineErrorV2[]; 13 | }; 14 | export declare type DataAndMetaV2 = { 15 | data: D; 16 | meta: M; 17 | errors?: InlineErrorV2[]; 18 | }; 19 | export declare type DataAndIncludeV2 = { 20 | data: D; 21 | includes?: I; 22 | errors?: InlineErrorV2[]; 23 | }; 24 | export declare type DataMetaAndIncludeV2 = { 25 | data: D; 26 | meta: M; 27 | includes?: I; 28 | errors?: InlineErrorV2[]; 29 | }; 30 | export interface SentMeta { 31 | /** The time when the request body was returned. */ 32 | sent: string; 33 | } 34 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/shared.v2.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/spaces.v2.types.d.ts: -------------------------------------------------------------------------------- 1 | import type { TypeOrArrayOf } from '../shared.types'; 2 | import type { DataAndIncludeV2, DataMetaAndIncludeV2 } from './shared.v2.types'; 3 | import type { TTweetv2UserField } from './tweet.v2.types'; 4 | import type { UsersV2Params, UsersV2Result, UserV2 } from './user.v2.types'; 5 | export interface SpaceV2FieldsParams { 6 | expansions: TypeOrArrayOf | string; 7 | 'space.fields': TypeOrArrayOf | string; 8 | 'user.fields': TypeOrArrayOf | string; 9 | } 10 | export declare type TSpaceV2Expansion = 'invited_user_ids' | 'speaker_ids' | 'creator_id' | 'host_ids'; 11 | export declare type TSpaceV2SpaceField = 'host_ids' | 'created_at' | 'creator_id' | 'id' | 'lang' | 'invited_user_ids' | 'participant_count' | 'speaker_ids' | 'started_at' | 'state' | 'title' | 'updated_at' | 'scheduled_start' | 'is_ticketed' | 'topic_ids' | 'ended_at'; 12 | export declare type TSpaceV2State = 'live' | 'scheduled'; 13 | export interface SpaceV2CreatorLookupParams extends SpaceV2FieldsParams { 14 | max_results?: number; 15 | } 16 | export interface SpaceV2SearchParams extends Partial { 17 | query: string; 18 | state: TSpaceV2State; 19 | max_results?: number; 20 | } 21 | export interface SpaceV2BuyersParams extends Partial { 22 | } 23 | declare type SpaceV2Includes = { 24 | users?: UserV2[]; 25 | }; 26 | export declare type SpaceV2SingleResult = DataAndIncludeV2; 27 | export declare type SpaceV2LookupResult = DataMetaAndIncludeV2; 30 | export declare type SpaceV2BuyersResult = UsersV2Result; 31 | export interface SpaceV2 { 32 | id: string; 33 | state: TSpaceV2State; 34 | created_at?: string; 35 | host_ids?: string[]; 36 | lang?: string; 37 | is_ticketed?: boolean; 38 | invited_user_ids?: string[]; 39 | participant_count?: number; 40 | scheduled_start?: string; 41 | speaker_ids?: string[]; 42 | started_at?: string; 43 | title?: string; 44 | creator_id?: string; 45 | updated_at?: string; 46 | topic_ids?: string[]; 47 | ended_at?: string; 48 | } 49 | export {}; 50 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/spaces.v2.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/streaming.v2.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // --------------- 3 | // -- Streaming -- 4 | // --------------- 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/tweet.definition.v2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/tweet.v2.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | ; 4 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/types/v2/user.v2.types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v1/media-helpers.v1.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as fs from 'fs'; 3 | import type { TUploadableMedia, TUploadTypeV1 } from '../types'; 4 | import { EUploadMimeType } from '../types'; 5 | export declare type TFileHandle = fs.promises.FileHandle | number | Buffer; 6 | export declare function readFileIntoBuffer(file: TUploadableMedia): Promise; 7 | export declare function getFileHandle(file: TUploadableMedia): number | Buffer | fs.promises.FileHandle | Promise; 8 | export declare function getFileSizeFromFileHandle(fileHandle: TFileHandle): Promise; 9 | export declare function getMimeType(file: TUploadableMedia, type?: TUploadTypeV1 | string, mimeType?: EUploadMimeType | string): string; 10 | export declare function getMediaCategoryByMime(name: string, target: 'tweet' | 'dm'): "TweetVideo" | "DmVideo" | "TweetGif" | "DmGif" | "Subtitles" | "TweetImage" | "DmImage"; 11 | export declare function sleepSecs(seconds: number): Promise; 12 | export declare function readNextPartOf(file: TFileHandle, chunkLength: number, bufferOffset?: number, buffer?: Buffer): Promise<[Buffer, number]>; 13 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2-labs/client.v2.labs.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiv2LabsReadWrite from './client.v2.labs.write'; 2 | /** 3 | * Twitter v2 labs client with all rights (read/write/DMs) 4 | */ 5 | export declare class TwitterApiv2Labs extends TwitterApiv2LabsReadWrite { 6 | protected _prefix: string; 7 | /** 8 | * Get a client with read/write rights. 9 | */ 10 | get readWrite(): TwitterApiv2LabsReadWrite; 11 | } 12 | export default TwitterApiv2Labs; 13 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2-labs/client.v2.labs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.TwitterApiv2Labs = void 0; 7 | const globals_1 = require("../globals"); 8 | const client_v2_labs_write_1 = __importDefault(require("./client.v2.labs.write")); 9 | /** 10 | * Twitter v2 labs client with all rights (read/write/DMs) 11 | */ 12 | class TwitterApiv2Labs extends client_v2_labs_write_1.default { 13 | constructor() { 14 | super(...arguments); 15 | this._prefix = globals_1.API_V2_LABS_PREFIX; 16 | } 17 | /** 18 | * Get a client with read/write rights. 19 | */ 20 | get readWrite() { 21 | return this; 22 | } 23 | } 24 | exports.TwitterApiv2Labs = TwitterApiv2Labs; 25 | exports.default = TwitterApiv2Labs; 26 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2-labs/client.v2.labs.read.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiSubClient from '../client.subclient'; 2 | /** 3 | * Base Twitter v2 labs client with only read right. 4 | */ 5 | export default class TwitterApiv2LabsReadOnly extends TwitterApiSubClient { 6 | protected _prefix: string; 7 | } 8 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2-labs/client.v2.labs.read.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const client_subclient_1 = __importDefault(require("../client.subclient")); 7 | const globals_1 = require("../globals"); 8 | /** 9 | * Base Twitter v2 labs client with only read right. 10 | */ 11 | class TwitterApiv2LabsReadOnly extends client_subclient_1.default { 12 | constructor() { 13 | super(...arguments); 14 | this._prefix = globals_1.API_V2_LABS_PREFIX; 15 | } 16 | } 17 | exports.default = TwitterApiv2LabsReadOnly; 18 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2-labs/client.v2.labs.write.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiv2LabsReadOnly from './client.v2.labs.read'; 2 | /** 3 | * Base Twitter v2 labs client with read/write rights. 4 | */ 5 | export default class TwitterApiv2LabsReadWrite extends TwitterApiv2LabsReadOnly { 6 | protected _prefix: string; 7 | /** 8 | * Get a client with only read rights. 9 | */ 10 | get readOnly(): TwitterApiv2LabsReadOnly; 11 | } 12 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2-labs/client.v2.labs.write.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const globals_1 = require("../globals"); 7 | const client_v2_labs_read_1 = __importDefault(require("./client.v2.labs.read")); 8 | /** 9 | * Base Twitter v2 labs client with read/write rights. 10 | */ 11 | class TwitterApiv2LabsReadWrite extends client_v2_labs_read_1.default { 12 | constructor() { 13 | super(...arguments); 14 | this._prefix = globals_1.API_V2_LABS_PREFIX; 15 | } 16 | /** 17 | * Get a client with only read rights. 18 | */ 19 | get readOnly() { 20 | return this; 21 | } 22 | } 23 | exports.default = TwitterApiv2LabsReadWrite; 24 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2/client.v2.d.ts: -------------------------------------------------------------------------------- 1 | import TwitterApiv2ReadWrite from './client.v2.write'; 2 | import TwitterApiv2Labs from '../v2-labs/client.v2.labs'; 3 | /** 4 | * Twitter v2 client with all rights (read/write/DMs) 5 | */ 6 | export declare class TwitterApiv2 extends TwitterApiv2ReadWrite { 7 | protected _prefix: string; 8 | protected _labs?: TwitterApiv2Labs; 9 | /** 10 | * Get a client with read/write rights. 11 | */ 12 | get readWrite(): TwitterApiv2ReadWrite; 13 | /** 14 | * Get a client for v2 labs endpoints. 15 | */ 16 | get labs(): TwitterApiv2Labs; 17 | } 18 | export default TwitterApiv2; 19 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/lib/v2/client.v2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.TwitterApiv2 = void 0; 7 | const globals_1 = require("../globals"); 8 | const client_v2_write_1 = __importDefault(require("./client.v2.write")); 9 | const client_v2_labs_1 = __importDefault(require("../v2-labs/client.v2.labs")); 10 | /** 11 | * Twitter v2 client with all rights (read/write/DMs) 12 | */ 13 | class TwitterApiv2 extends client_v2_write_1.default { 14 | constructor() { 15 | super(...arguments); 16 | this._prefix = globals_1.API_V2_PREFIX; 17 | } 18 | /* Sub-clients */ 19 | /** 20 | * Get a client with read/write rights. 21 | */ 22 | get readWrite() { 23 | return this; 24 | } 25 | /** 26 | * Get a client for v2 labs endpoints. 27 | */ 28 | get labs() { 29 | if (this._labs) 30 | return this._labs; 31 | return this._labs = new client_v2_labs_1.default(this); 32 | } 33 | } 34 | exports.TwitterApiv2 = TwitterApiv2; 35 | exports.default = TwitterApiv2; 36 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/autotask-1/twitter-api-v2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitter-api-v2", 3 | "version": "1.12.9", 4 | "description": "Strongly typed, full-featured, light, versatile yet powerful Twitter API v1.1 and v2 client for Node.js.", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "keywords": [ 8 | "twitter", 9 | "api", 10 | "typed", 11 | "types", 12 | "v2", 13 | "v1.1" 14 | ], 15 | "scripts": { 16 | "build": "tsc", 17 | "build-doc": "typedoc src/index.ts --out tsdocs", 18 | "lint": "eslint --ext \".ts\" --ignore-path .gitignore .", 19 | "mocha": "mocha -r ts-node/register --timeout 10000", 20 | "test": "npm run mocha 'test/**/*.test.ts'", 21 | "test-tweet": "npm run mocha 'test/tweet.*.test.ts'", 22 | "test-user": "npm run mocha 'test/user.*.test.ts'", 23 | "test-stream": "npm run mocha test/stream.test.ts", 24 | "test-media": "npm run mocha test/media-upload.test.ts", 25 | "test-auth": "npm run mocha test/auth.test.ts", 26 | "test-dm": "npm run mocha test/dm.*.test.ts", 27 | "test-list": "npm run mocha test/list.*.test.ts", 28 | "test-space": "npm run mocha test/space.v2.test.ts", 29 | "test-account": "npm run mocha test/account.*.test.ts", 30 | "test-plugin": "npm run mocha test/plugin.test.ts", 31 | "prepublish": "npm run build" 32 | }, 33 | "repository": "github:plhery/node-twitter-api-v2", 34 | "author": "Paul-Louis Hery (https://twitter.com/plhery)", 35 | "license": "Apache-2.0", 36 | "files": [ 37 | "lib" 38 | ], 39 | "devDependencies": { 40 | "@types/chai": "4.2.16", 41 | "@types/mocha": "9.0.0", 42 | "@types/node": "14.14.37", 43 | "@typescript-eslint/eslint-plugin": "4.28.5", 44 | "@typescript-eslint/parser": "4.28.5", 45 | "chai": "4.3.4", 46 | "dotenv": "8.2.0", 47 | "eslint": "7.31.0", 48 | "mocha": "10.0.0", 49 | "ts-node": "9.1.1", 50 | "typedoc": "0.22.15", 51 | "typescript": "4.2.4" 52 | }, 53 | "bugs": { 54 | "url": "https://github.com/plhery/node-twitter-api/issues" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /defender/governance_twitter_summary/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: governance_twitter_summary 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Governance Twitter Summary 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Public Variables 20 | # Compound Governance Address 21 | governanceAddress: "0xc0Da02939E1441F497fd74F78cE7Decb17B66529" 22 | # Private Variables pulled from external secrets.yml file 23 | appKey: ${self:custom.stackSecrets.appKey} 24 | appSecret: ${self:custom.stackSecrets.appSecret} 25 | accessToken: ${self:custom.stackSecrets.accessToken} 26 | accessSecret: ${self:custom.stackSecrets.accessSecret} 27 | 28 | defender: 29 | key: ${self:custom.config.keys.api} 30 | secret: ${self:custom.config.keys.secret} 31 | 32 | functions: 33 | autotask-1: 34 | name: ${self:custom.name} Serverless Autotask 35 | path: autotask-1 36 | trigger: 37 | type: schedule 38 | cron: "0 0 * * *" # Daily at 0000 UTC 39 | paused: false 40 | relayer: ${self:resources.Resources.relayers.relayer-1} 41 | 42 | resources: 43 | Resources: 44 | policies: 45 | policy-1: 46 | gas-price-cap: 1000 47 | whitelist-receivers: 48 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 49 | eip1559-pricing: true 50 | 51 | secrets: 52 | stack: ${self:custom.defenderSecrets} 53 | 54 | relayers: 55 | relayer-1: 56 | name: ${self:custom.name} Serverless Relay 57 | network: mainnet 58 | min-balance: 100000000000000000 59 | 60 | plugins: 61 | - defender-serverless 62 | -------------------------------------------------------------------------------- /defender/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "defender-compound-monitoring", 3 | "version": "1.0.0", 4 | "description": "", 5 | "jest": { 6 | "testTimeout": 50000 7 | }, 8 | "scripts": { 9 | "download": "node download.js", 10 | "deploy": "node deploy.js", 11 | "wipe": "node wipeAccount.js", 12 | "test": "jest" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "dependencies": { 18 | "axios": "0.21.2", 19 | "axios-retry": "3.1.9", 20 | "defender-autotask-client": "1.37.0-rc.2", 21 | "defender-kvstore-client": "1.37.0-rc.2", 22 | "defender-relay-client": "1.37.0-rc.2", 23 | "defender-sentinel-client": "1.37.0-rc.2", 24 | "defender-serverless": "1.0.3", 25 | "dotenv": "10.0.0", 26 | "ethers": "5.5.3", 27 | "fetch": "^1.1.0", 28 | "forta-agent": "0.1.6", 29 | "jszip": "3.10.0", 30 | "okhttp": "^1.1.0", 31 | "request": "^2.88.2", 32 | "serverless": "3.24.1" 33 | }, 34 | "devDependencies": { 35 | "eslint": "8.9.0", 36 | "eslint-config-airbnb-base": "15.0.0", 37 | "eslint-plugin-import": "2.25.4", 38 | "jest": "28.1.0", 39 | "unirest": "^0.6.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /defender/proposal_110_automatoooor/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: proposal_110_automatoooor 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | 14 | # Configure this section and rename secret-example.yml to secrets.yml 15 | name: Proposal 110 Automatoooor 16 | 17 | defender: 18 | key: ${self:custom.config.keys.api} 19 | secret: ${self:custom.config.keys.secret} 20 | 21 | functions: 22 | autotask-1: 23 | name: ${self:custom.name} Serverless Autotask 24 | path: autotask-1 25 | trigger: 26 | type: schedule 27 | frequency: 5 28 | paused: true 29 | relayer: ${self:resources.Resources.relayers.relayer-1} 30 | 31 | resources: 32 | Resources: 33 | policies: 34 | policy-1: 35 | gas-price-cap: 1000 36 | whitelist-receivers: 37 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 38 | eip1559-pricing: true 39 | 40 | secrets: 41 | 42 | relayers: 43 | relayer-1: 44 | name: ${self:custom.name} Serverless Relay 45 | network: mainnet 46 | min-balance: 100000000000000000 47 | 48 | plugins: 49 | - defender-serverless 50 | -------------------------------------------------------------------------------- /defender/proposal_117_monitor_market_entered/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: proposal_117_monitor_market_entered 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Proposal 117 Monitor Market Entered 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Private variables pulled from external secrets.yml file 20 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 21 | slackWebhook: ${self:custom.stackSecrets.slackWebhook} 22 | 23 | defender: 24 | key: ${self:custom.config.keys.api} 25 | secret: ${self:custom.config.keys.secret} 26 | 27 | functions: 28 | autotask-1: 29 | name: ${self:custom.name} Serverless Autotask 30 | path: autotask-1 31 | trigger: 32 | type: schedule 33 | frequency: 525600000 34 | paused: true 35 | relayer: ${self:resources.Resources.relayers.relayer-1} 36 | 37 | resources: 38 | Resources: 39 | policies: 40 | policy-1: 41 | gas-price-cap: 1000 42 | whitelist-receivers: 43 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 44 | eip1559-pricing: true 45 | 46 | secrets: 47 | stack: ${self:custom.defenderSecrets} 48 | 49 | relayers: 50 | relayer-1: 51 | name: ${self:custom.name} Serverless Relay 52 | network: mainnet 53 | min-balance: 100000000000000000 54 | 55 | plugins: 56 | - defender-serverless 57 | -------------------------------------------------------------------------------- /defender/proposal_117_monitor_mint/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: proposal_117_monitor_mint 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: Proposal 117 Monitor Mint 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Private variables pulled from external secrets.yml file 20 | discordWebhook: ${self:custom.stackSecrets.discordWebhook} 21 | slackWebhook: ${self:custom.stackSecrets.slackWebhook} 22 | 23 | defender: 24 | key: ${self:custom.config.keys.api} 25 | secret: ${self:custom.config.keys.secret} 26 | 27 | functions: 28 | autotask-1: 29 | name: ${self:custom.name} Serverless Autotask 30 | path: autotask-1 31 | trigger: 32 | type: schedule 33 | frequency: 525600000 34 | paused: true 35 | relayer: ${self:resources.Resources.relayers.relayer-1} 36 | 37 | resources: 38 | Resources: 39 | policies: 40 | policy-1: 41 | gas-price-cap: 1000 42 | whitelist-receivers: 43 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 44 | eip1559-pricing: true 45 | 46 | secrets: 47 | stack: ${self:custom.defenderSecrets} 48 | 49 | relayers: 50 | relayer-1: 51 | name: ${self:custom.name} Serverless Relay 52 | network: mainnet 53 | min-balance: 100000000000000000 54 | 55 | plugins: 56 | - defender-serverless 57 | -------------------------------------------------------------------------------- /defender/secret-example.yml: -------------------------------------------------------------------------------- 1 | keys: 2 | api: 3 | secret: 4 | 5 | # WARNING: When deploying stacks, the secrets listed below will overwrite the ones in Defender. 6 | # If secrets do not need to be updated, comment them out in your serverless.yml files. 7 | # Note: The overwrite is limited to the stack that you are deploying. 8 | secrets: 9 | ctoken_monitor: 10 | discordWebhook: "" 11 | datadog_alerts_heat_map: 12 | datadogApiKey: "" 13 | datadog_alerts_heat_map_dev: 14 | datadogApiKey: "" 15 | datadog_forta_bot_alerts: 16 | datadogApiKey: "" 17 | datadog_forta_bot_alerts_dev: 18 | datadogApiKey: "" 19 | datadog_forta_detection_bot_health: 20 | datadogApiKey: "" 21 | forta_ctoken: 22 | discordWebhook: "" 23 | forta_distribution: 24 | discordWebhook: "" 25 | forta_governance: 26 | discordWebhook: "" 27 | forta_large_borrows_governance: 28 | discordWebhook: "" 29 | forta_large_delegations: 30 | discordWebhook: "" 31 | forta_low_liquidity: 32 | discordWebhook: "" 33 | forta_multi_sig: 34 | discordWebhook: "" 35 | forta_oracle_price: 36 | discordWebhook: "" 37 | forta_underlying_asset: 38 | discordWebhook: "" 39 | forta_v2_liquidation_monitor_dev: 40 | discordWebhook: "" 41 | forta_v3_liquidation_monitor_dev: 42 | discordWebhook: "" 43 | governance_discord_alert: 44 | discordWebhook: "" 45 | governance_discord_summary: 46 | discordWebhook: "" 47 | governance_twitter_summary: 48 | # Twitter Keys 49 | # Consumer Keys from an elevated developer account 50 | appKey: "" 51 | appSecret: "" 52 | # Authentication Tokens (must have write permissions) 53 | accessToken: "" 54 | accessSecret: "" 55 | proposal_117_monitor_market_entered: 56 | discordWebhook: "" 57 | slackWebhook: "" 58 | proposal_117_monitor_mint: 59 | discordWebhook: "" 60 | slackWebhook: "" 61 | -------------------------------------------------------------------------------- /defender/template_autotask_relay/autotask-1/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/compound-monitoring/ad6f30e676b23219b4b26ff547958022e7fee8e2/defender/template_autotask_relay/autotask-1/index.js -------------------------------------------------------------------------------- /defender/template_autotask_relay/serverless.yml: -------------------------------------------------------------------------------- 1 | service: generated-service 2 | configValidationMode: error 3 | frameworkVersion: "3" 4 | 5 | provider: 6 | name: defender 7 | stage: dev 8 | stackName: CHANGE_ME 9 | ssot: false 10 | 11 | custom: 12 | config: ${file(../secrets.yml)} 13 | stackSecrets: ${self:custom.config.secrets.${self:provider.stackName}} 14 | 15 | # Configure this section and rename secret-example.yml to secrets.yml 16 | name: CHANGE_ME 17 | # Comment out any secret that you do not want to be overwritten in Defender 18 | defenderSecrets: 19 | # Public Variables 20 | publicVariable: "Nothing Sensitive" 21 | # Private variables pulled from external secrets.yml file 22 | privateVariable: ${self:custom.stackSecrets.privateVariable} 23 | 24 | defender: 25 | key: ${self:custom.config.keys.api} 26 | secret: ${self:custom.config.keys.secret} 27 | 28 | functions: 29 | autotask-1: 30 | name: ${self:custom.name} Serverless Autotask 31 | path: autotask-1 32 | trigger: 33 | type: schedule 34 | cron: "0 * * * *" 35 | paused: false 36 | relayer: ${self:resources.Resources.relayers.relayer-1} 37 | 38 | resources: 39 | Resources: 40 | policies: 41 | policy-1: 42 | gas-price-cap: 1000 43 | whitelist-receivers: 44 | - "0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2" 45 | eip1559-pricing: true 46 | 47 | secrets: 48 | stack: ${self:custom.defenderSecrets} 49 | 50 | relayers: 51 | relayer-1: 52 | name: ${self:custom.name} Serverless Relay 53 | network: mainnet 54 | min-balance: 100000000000000000 55 | 56 | plugins: 57 | - defender-serverless 58 | -------------------------------------------------------------------------------- /defender/template_autotask_relay_forta/autotask-1/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/compound-monitoring/ad6f30e676b23219b4b26ff547958022e7fee8e2/defender/template_autotask_relay_forta/autotask-1/index.js -------------------------------------------------------------------------------- /defender/template_autotask_relay_sentinel/abis/sentinel-1.json.abi: -------------------------------------------------------------------------------- 1 | # Delete this and paste you ABI JSON in here -------------------------------------------------------------------------------- /defender/template_autotask_relay_sentinel/autotask-1/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/compound-monitoring/ad6f30e676b23219b4b26ff547958022e7fee8e2/defender/template_autotask_relay_sentinel/autotask-1/index.js -------------------------------------------------------------------------------- /distribution/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /distribution/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /distribution/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /distribution/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /distribution/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Large Distribution Event Forta Bot 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /distribution/README.md: -------------------------------------------------------------------------------- 1 | # Compound Distribution Monitor 2 | 3 | ## Description 4 | 5 | This bot monitors the Compound Finance Comptroller contract for distribution events and 6 | if an amount of COMP is distributed that exceeds a configurable maximum amount an alert is generated. 7 | 8 | ## Alerts 9 | 10 | 11 | - AE-COMP-EXCEEDS-SANE-DISTRIBUTION-EVENT 12 | - Type is always set to `Info` 13 | - Severity is always set to `Info` 14 | - Metadata field contains: 15 | - Amount of COMP distributed 16 | - COMP index 17 | 18 | ## Testing 19 | 20 | The following transactions can be used to test the operation of this bot. 21 | 22 | 0xf4bfef1655f2092cf062c008153a5be66069b2b1fedcacbf4037c1f3cc8a9f45 23 | 0xbc246c878326f2c128462d08a0b74048b1dbee733adde8863f569c949c06422a 24 | 25 | To run, use: 26 | `npm run tx {transactionHash}` -------------------------------------------------------------------------------- /distribution/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "contracts": { 6 | "Comptroller": { 7 | "address": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 8 | "abiFile": "Comptroller.json" 9 | }, 10 | "CompoundToken": { 11 | "address": "0xc00e94cb662c3520282e6f5717214004a7f26888" 12 | } 13 | }, 14 | "maximumSaneDistributionAmount": "1000" 15 | } 16 | -------------------------------------------------------------------------------- /distribution/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-comp-distribution-bugs", 3 | "version": "0.0.4", 4 | "description": "This Bot monitors Compound distribution bugs.", 5 | "scripts": { 6 | "start": "npm run start:dev", 7 | "start:prod": "forta-agent run --prod", 8 | "tx": "forta-agent run --tx", 9 | "block": "forta-agent run --block", 10 | "range": "forta-agent run --range", 11 | "file": "forta-agent run --file", 12 | "publish": "forta-agent publish", 13 | "push": "forta-agent push", 14 | "disable": "forta-agent disable", 15 | "enable": "forta-agent enable", 16 | "keyfile": "forta-agent keyfile", 17 | "test": "jest" 18 | }, 19 | "dependencies": { 20 | "bignumber.js": "9.0.2", 21 | "forta-agent": "0.1.4" 22 | }, 23 | "devDependencies": { 24 | "eslint": "8.16.0", 25 | "eslint-config-airbnb-base": "15.0.0", 26 | "eslint-plugin-import": "2.26.0", 27 | "jest": "28.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /distribution/src/utils.js: -------------------------------------------------------------------------------- 1 | function getAbi(abiName) { 2 | // eslint-disable-next-line global-require,import/no-dynamic-require 3 | const { abi } = require(`../abi/${abiName}`); 4 | return abi; 5 | } 6 | 7 | module.exports = { 8 | getAbi, 9 | }; 10 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/.gitignore: -------------------------------------------------------------------------------- 1 | config.json 2 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | # if using obfuscated code from build stage: 13 | # COPY --from=builder /app/dist ./src 14 | # else if using unobfuscated code: 15 | LABEL "network.forta.settings.agent-logs.enable"="true" 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/abi/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/compound-monitoring/ad6f30e676b23219b4b26ff547958022e7fee8e2/gnosis-safe-deploy/abi/.gitkeep -------------------------------------------------------------------------------- /gnosis-safe-deploy/abi/AgentRegistryProxy.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [ 5 | { 6 | "internalType": "address", 7 | "name": "_logic", 8 | "type": "address" 9 | }, 10 | { 11 | "internalType": "bytes", 12 | "name": "_data", 13 | "type": "bytes" 14 | } 15 | ], 16 | "stateMutability": "payable", 17 | "type": "constructor" 18 | }, 19 | { 20 | "anonymous": false, 21 | "inputs": [ 22 | { 23 | "indexed": false, 24 | "internalType": "address", 25 | "name": "previousAdmin", 26 | "type": "address" 27 | }, 28 | { 29 | "indexed": false, 30 | "internalType": "address", 31 | "name": "newAdmin", 32 | "type": "address" 33 | } 34 | ], 35 | "name": "AdminChanged", 36 | "type": "event" 37 | }, 38 | { 39 | "anonymous": false, 40 | "inputs": [ 41 | { 42 | "indexed": true, 43 | "internalType": "address", 44 | "name": "beacon", 45 | "type": "address" 46 | } 47 | ], 48 | "name": "BeaconUpgraded", 49 | "type": "event" 50 | }, 51 | { 52 | "anonymous": false, 53 | "inputs": [ 54 | { 55 | "indexed": true, 56 | "internalType": "address", 57 | "name": "implementation", 58 | "type": "address" 59 | } 60 | ], 61 | "name": "Upgraded", 62 | "type": "event" 63 | }, 64 | { 65 | "stateMutability": "payable", 66 | "type": "fallback" 67 | }, 68 | { 69 | "stateMutability": "payable", 70 | "type": "receive" 71 | } 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Forta", 4 | "protocolAbbreviation": "FORTA", 5 | "contracts": { 6 | "AgentRegistryProxy": { 7 | "address": "0x61447385B019187daa48e91c55c02AF1F1f3F863", 8 | "abiFile": "AgentRegistryProxy.json", 9 | "proxy": "AgentRegistry" 10 | }, 11 | "AgentRegistry": { 12 | "address": "0xA8A26969f7Be888D020B595340c490c02ec445dD", 13 | "abiFile": "AgentRegistry.json", 14 | "events": { 15 | "AccessManagerUpdated": { 16 | "type": "Info", 17 | "severity": "Info" 18 | }, 19 | "AdminChanged": { 20 | "type": "Info", 21 | "severity": "Info" 22 | }, 23 | "AgentCommitted": { 24 | "type": "Info", 25 | "severity": "Info" 26 | }, 27 | "AgentEnabled": { 28 | "type": "Info", 29 | "severity": "Info" 30 | }, 31 | "AgentUpdated": { 32 | "type": "Info", 33 | "severity": "Info" 34 | }, 35 | "Approval": { 36 | "type": "Info", 37 | "severity": "Info" 38 | }, 39 | "ApprovalForAll": { 40 | "type": "Info", 41 | "severity": "Info" 42 | }, 43 | "BeaconUpgraded": { 44 | "type": "Info", 45 | "severity": "Info" 46 | }, 47 | "RouterUpdated": { 48 | "type": "Info", 49 | "severity": "Info" 50 | }, 51 | "FrontRunningDelaySet": { 52 | "type": "Info", 53 | "severity": "Info" 54 | }, 55 | "StakeControllerUpdated": { 56 | "type": "Info", 57 | "severity": "Info" 58 | }, 59 | "StakeThresholdChanged": { 60 | "type": "Info", 61 | "severity": "Info" 62 | }, 63 | "Transfer": { 64 | "type": "Info", 65 | "severity": "Info" 66 | }, 67 | "Upgraded": { 68 | "type": "Info", 69 | "severity": "Info" 70 | } 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "safeAccountConfig": { 3 | "owners": [ 4 | "0xADDRESSOWNERONE", 5 | "0xADDRESSOWNERTWO", 6 | "0xADDRESSOWNERTHREE" 7 | ], 8 | "threshold": 2 9 | }, 10 | "safeVersion": "1.3.0" 11 | } 12 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gnosis-safe-deploy", 3 | "version": "1.0.0", 4 | "description": "Example deployment of a Forta Bot using a Gnosis Safe smart contract.", 5 | "chainIds": [ 6 | 137 7 | ], 8 | "scripts": { 9 | "start": "npm run start:dev", 10 | "start:prod": "forta-agent run --prod", 11 | "tx": "forta-agent run --tx", 12 | "block": "forta-agent run --block", 13 | "range": "forta-agent run --range", 14 | "file": "forta-agent run --file", 15 | "test": "jest", 16 | "deploy": "node scripts/deploySafe.js", 17 | "propose": "node scripts/proposeFortaBot.js", 18 | "approve": "node scripts/approveTransaction.js", 19 | "execute": "node scripts/executeTransaction.js", 20 | "reject": "node scripts/rejectTransaction.js" 21 | }, 22 | "dependencies": { 23 | "@gnosis.pm/safe-core-sdk": "2.0.0", 24 | "@gnosis.pm/safe-ethers-lib": "1.1.0", 25 | "@gnosis.pm/safe-service-client": "1.1.2", 26 | "bignumber.js": "9.0.2", 27 | "dotenv": "16.0.0", 28 | "ethers": "5.6.2", 29 | "forta-agent": "0.1.3" 30 | }, 31 | "devDependencies": { 32 | "eslint": "8.16.0", 33 | "eslint-config-airbnb-base": "15.0.0", 34 | "eslint-plugin-import": "2.26.0", 35 | "jest": "28.1.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /gnosis-safe-deploy/scripts/approveTransaction.js: -------------------------------------------------------------------------------- 1 | const EthersAdapter = require('@gnosis.pm/safe-ethers-lib').default; 2 | const Safe = require('@gnosis.pm/safe-core-sdk').default; 3 | const SafeServiceClient = require('@gnosis.pm/safe-service-client').default; 4 | const ethers = require('ethers'); 5 | 6 | // load values from the .env file 7 | require('dotenv').config(); 8 | 9 | // load the Gnosis Safe proxy contract address 10 | const polygonSafeAddress = process.env.POLYGON_SAFE_ADDRESS; 11 | 12 | // load the JSON-RPC endpoint URL 13 | const polygonEndpoint = process.env.POLYGON_ENDPOINT; 14 | 15 | // load the private key for the account that will be signing the transaction 16 | const ownerPrivateKey = process.env.APPROVER_PRIVATE_KEY; 17 | 18 | // load the transaction hash to approve 19 | const safeTxHash = process.env.SAFE_TX_HASH; 20 | 21 | async function main() { 22 | // create an ethers.js provider 23 | const provider = new ethers.providers.JsonRpcProvider(polygonEndpoint); 24 | 25 | // create an ethers.js wallet (signer) and connect it to the provider 26 | const safeWallet = new ethers.Wallet(ownerPrivateKey, provider); 27 | const signer = safeWallet.connect(provider); 28 | 29 | // create an ethAdapter Object 30 | const ethAdapter = new EthersAdapter({ 31 | ethers, 32 | signer, 33 | provider, 34 | }); 35 | 36 | // initialize the Safe Service Client 37 | const transactionServiceUrl = 'https://safe-transaction.polygon.gnosis.io/'; 38 | const safeService = new SafeServiceClient({ 39 | txServiceUrl: transactionServiceUrl, 40 | ethAdapter, 41 | }); 42 | 43 | console.log('Getting deployed Gnosis Safe Contract'); 44 | const safeSdk = await Safe.create({ 45 | ethAdapter, 46 | safeAddress: polygonSafeAddress, 47 | }); 48 | 49 | // sign the transaction hash and provide confirmation to the Safe Service Client 50 | const signature = await safeSdk.signTransactionHash(safeTxHash); 51 | await safeService.confirmTransaction(safeTxHash, signature.data); 52 | console.log('Transaction confirmed'); 53 | } 54 | 55 | main() 56 | .then(() => process.exit(0)) 57 | .catch((error) => { 58 | console.error(error); 59 | process.exit(1); 60 | }); 61 | -------------------------------------------------------------------------------- /governance/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /governance/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /governance/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /governance/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /governance/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Protocol Monitoring 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /governance/abi/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/compound-monitoring/ad6f30e676b23219b4b26ff547958022e7fee8e2/governance/abi/.gitkeep -------------------------------------------------------------------------------- /governance/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "governance": { 6 | "address": "0xc0Da02939E1441F497fd74F78cE7Decb17B66529", 7 | "abiFile": "GovernorBravo.json", 8 | "events": [ 9 | "ProposalCanceled", 10 | "ProposalCreated", 11 | "ProposalExecuted", 12 | "ProposalQueued", 13 | "ProposalThresholdSet", 14 | "VoteCast" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /governance/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-comp-governance-events", 3 | "version": "0.0.5", 4 | "description": "This Bot monitors events emitted from the Compound GovernorBravo contract.", 5 | "scripts": { 6 | "start": "npm run start:dev", 7 | "start:prod": "forta-agent run --prod", 8 | "tx": "forta-agent run --tx", 9 | "block": "forta-agent run --block", 10 | "range": "forta-agent run --range", 11 | "file": "forta-agent run --file", 12 | "publish": "forta-agent publish", 13 | "push": "forta-agent push", 14 | "disable": "forta-agent disable", 15 | "enable": "forta-agent enable", 16 | "keyfile": "forta-agent keyfile", 17 | "test": "jest" 18 | }, 19 | "dependencies": { 20 | "axios": "0.27.2", 21 | "forta-agent": "0.0.39" 22 | }, 23 | "devDependencies": { 24 | "eslint": "8.16.0", 25 | "eslint-config-airbnb-base": "15.0.0", 26 | "eslint-plugin-import": "2.26.0", 27 | "jest": "^29.5.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /large-borrows-governance/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /large-borrows-governance/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /large-borrows-governance/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /large-borrows-governance/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./abi ./abi 17 | COPY ./src ./src 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /large-borrows-governance/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Large Borrows Governance Forta Bot 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /large-borrows-governance/README.md: -------------------------------------------------------------------------------- 1 | # Compound Large Borrows Governance Bot 2 | 3 | ## Description 4 | 5 | This bot monitors all borrow events of COMP to see if the borrower address has accrued enough COMP 6 | to pass significant governance thresholds. This can be an early indication of governance attacks. 7 | 8 | ## Alerts 9 | 10 | 11 | - AE-COMP-GOVERNANCE-THRESHOLD 12 | - Type is always set to `Suspicious` 13 | - Severity is set to `Medium` for the proposal threshold alert and `High` for the voting quorum 14 | threshold alert 15 | - Metadata field contains: 16 | - Borrower address 17 | - Governance threshold level that has been surpassed, which can be either `proposal` or `votingQuorum` 18 | - The minimum amount of COMP needed to pass the respective governance threshold 19 | - The amount of COMP owned by the borrower address 20 | 21 | ## Testing 22 | 23 | Run unit tests: 24 | ```console 25 | npm test 26 | ``` -------------------------------------------------------------------------------- /large-borrows-governance/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "COMPAddress": "0xc00e94Cb662C3520282E6f5717214004A7f26888", 6 | "cCOMPAddress": "0x70e36f6BF80a52b3B46b3aF8e106CC0ed743E8e4", 7 | "governorAddress": "0xc0Da02939E1441F497fd74F78cE7Decb17B66529", 8 | "borrowLevels": { 9 | "proposal": { 10 | "type": "Suspicious", 11 | "severity": "Medium" 12 | }, 13 | "votingQuorum": { 14 | "type": "Suspicious", 15 | "severity": "High" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /large-borrows-governance/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-large-borrows-governance", 3 | "version": "0.0.3", 4 | "chainIds": [ 5 | 1 6 | ], 7 | "description": "This Bot monitors all borrow events of COMP to see if an address has borrowed has enough COMP to influence governance.", 8 | "scripts": { 9 | "start": "npm run start:dev", 10 | "start:prod": "forta-agent run --prod", 11 | "tx": "forta-agent run --tx", 12 | "block": "forta-agent run --block", 13 | "range": "forta-agent run --range", 14 | "file": "forta-agent run --file", 15 | "publish": "forta-agent publish", 16 | "push": "forta-agent push", 17 | "disable": "forta-agent disable", 18 | "enable": "forta-agent enable", 19 | "keyfile": "forta-agent keyfile", 20 | "test": "jest" 21 | }, 22 | "dependencies": { 23 | "bignumber.js": "9.0.2", 24 | "forta-agent": "0.0.39" 25 | }, 26 | "devDependencies": { 27 | "eslint": "8.16.0", 28 | "eslint-config-airbnb-base": "15.0.0", 29 | "eslint-plugin-import": "2.26.0", 30 | "jest": "28.1.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /liquidation-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /liquidation-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | 'no-param-reassign': 'off', 22 | }, 23 | }, 24 | ], 25 | }; 26 | -------------------------------------------------------------------------------- /liquidation-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | .env 5 | -------------------------------------------------------------------------------- /liquidation-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | LABEL "network.forta.settings.agent-logs.enable"="true" 12 | WORKDIR /app 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY ./bot-config.json ./bot-config.json 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /liquidation-monitor/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "liquidationMonitor": { 6 | "comptrollerAddress": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 7 | "comptrollerABI": "Comptroller.json", 8 | "oneInchAddress": "0x07D91f5fb9Bf7798734C3f606dB065549F6893bb", 9 | "oneInchABI": "OneInch.json", 10 | "triggerLevels": { 11 | "maximumHealth": 100, 12 | "minimumBorrowInETH": 0.1, 13 | "minimumLiquidationInUSD": 400, 14 | "lowHealthThreshold": 1.03 15 | }, 16 | "alert": { 17 | "type": "Info", 18 | "severity": "Info" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /liquidation-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-compound-finance-liquidation-monitor", 3 | "version": "0.0.2", 4 | "description": "Forta Bot that monitors Compound Finance for positions that can be liquidated", 5 | "chainIds": [ 6 | 1 7 | ], 8 | "scripts": { 9 | "start": "npm run start:dev", 10 | "start:prod": "forta-agent run --prod", 11 | "tx": "forta-agent run --tx", 12 | "block": "forta-agent run --block", 13 | "range": "forta-agent run --range", 14 | "file": "forta-agent run --file", 15 | "publish": "forta-agent publish", 16 | "push": "forta-agent push", 17 | "disable": "forta-agent disable", 18 | "enable": "forta-agent enable", 19 | "keyfile": "forta-agent keyfile", 20 | "test": "jest" 21 | }, 22 | "dependencies": { 23 | "axios": "0.27.2", 24 | "bignumber.js": "9.0.2", 25 | "forta-agent": "0.1.3" 26 | }, 27 | "devDependencies": { 28 | "eslint": "8.16.0", 29 | "eslint-config-airbnb-base": "15.0.0", 30 | "eslint-plugin-import": "2.26.0", 31 | "jest": "28.1.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /liquidation-monitor/src/utils.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | function getAbi(abiName) { 4 | // eslint-disable-next-line global-require,import/no-dynamic-require 5 | const { abi } = require(`../abi/${abiName}`); 6 | return abi; 7 | } 8 | 9 | // Helper for Compound API 10 | function buildJsonRequest(maxHealth, minBorrow, pageNumber, pageSize) { 11 | const jsonRequest = { 12 | addresses: [], // returns all accounts if empty or not included 13 | block_number: 0, // returns latest if given 0 14 | max_health: { value: maxHealth }, 15 | min_borrow_value_in_eth: { value: minBorrow }, 16 | page_number: pageNumber, 17 | page_size: pageSize, 18 | }; 19 | return jsonRequest; 20 | } 21 | 22 | async function callCompoundAPI(jsonRequest) { 23 | try { 24 | const apiURL = 'https://api.compound.finance/api/v2/account'; 25 | const resp = await axios.post(apiURL, jsonRequest); 26 | return resp.data; 27 | } catch (err) { 28 | // Handle Error Here 29 | return null; 30 | } 31 | } 32 | 33 | module.exports = { 34 | getAbi, 35 | callCompoundAPI, 36 | buildJsonRequest, 37 | }; 38 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Protocol Monitoring 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/README.md: -------------------------------------------------------------------------------- 1 | # Compound Low Liquidity Market Attack Monitor 2 | 3 | ## Description 4 | 5 | This bot monitors Compound Finance cToken contracts that have low liquidity for potential 6 | market attacks where a malicious actor mints cTokens and then transfers additional tokens in 7 | order to unbalance the contract such that subsequent mints will not yield cTokens. 8 | 9 | ## Alerts 10 | 11 | 12 | - AE-COMP-MARKET-ATTACK-EVENT 13 | - Type is always set to `Suspicious` 14 | - Severity is always set to `Info` 15 | - Metadata field contains: 16 | - COMP Token symbol 17 | - COMP Token Address 18 | - Minted Amount 19 | - Minted COMP Tokens 20 | - Malicious Address 21 | - Malicious Transfer Amount -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "contracts": { 6 | "Comptroller": { 7 | "address": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 8 | "abiFile": "Comptroller.json" 9 | }, 10 | "CompToken": { 11 | "abiFile": "cErc20.json" 12 | } 13 | }, 14 | "excludeAddresses": ["0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5"] 15 | } 16 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-comp-market-attack-events", 3 | "version": "0.0.5", 4 | "description": "This Bot monitors Compound Finance cToken contracts for market attack events.", 5 | "scripts": { 6 | "start": "npm run start:dev", 7 | "start:prod": "forta-agent run --prod", 8 | "tx": "forta-agent run --tx", 9 | "block": "forta-agent run --block", 10 | "range": "forta-agent run --range", 11 | "file": "forta-agent run --file", 12 | "publish": "forta-agent publish", 13 | "push": "forta-agent push", 14 | "disable": "forta-agent disable", 15 | "enable": "forta-agent enable", 16 | "keyfile": "forta-agent keyfile", 17 | "test": "jest" 18 | }, 19 | "dependencies": { 20 | "bignumber.js": "9.0.2", 21 | "forta-agent": "0.1.6" 22 | }, 23 | "devDependencies": { 24 | "eslint": "8.16.0", 25 | "eslint-config-airbnb-base": "15.0.0", 26 | "eslint-plugin-import": "2.26.0", 27 | "jest": "28.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /low-liquidity-market-attack-monitor/src/utils.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('forta-agent'); 2 | 3 | function getAbi(abiName) { 4 | // eslint-disable-next-line global-require,import/no-dynamic-require 5 | const { abi } = require(`../abi/${abiName}`); 6 | return abi; 7 | } 8 | 9 | // helper function that identifies key strings in the args array obtained from log parsing 10 | // these key-value pairs will be added to the metadata as event args 11 | // all values are converted to strings so that BigNumbers are readable 12 | function extractEventArgs(args) { 13 | const eventArgs = {}; 14 | Object.keys(args).forEach((key) => { 15 | if (Number.isNaN(Number(key))) { 16 | eventArgs[key] = args[key].toString(); 17 | } 18 | }); 19 | return eventArgs; 20 | } 21 | 22 | function isAddress(valueString) { 23 | return ethers.utils.isHexString(valueString, 20); 24 | } 25 | 26 | module.exports = { 27 | getAbi, 28 | extractEventArgs, 29 | isAddress, 30 | }; 31 | -------------------------------------------------------------------------------- /multisig-transactions-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json -------------------------------------------------------------------------------- /multisig-transactions-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-plusplus': 'off', 21 | 'no-continue': 'off', 22 | 'no-console': 'off', 23 | }, 24 | }, 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /multisig-transactions-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /multisig-transactions-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | WORKDIR /app 12 | LABEL "network.forta.settings.agent-logs.enable"="true" 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./src ./src 17 | COPY ./abi ./abi 18 | COPY bot-config.json ./ 19 | COPY package*.json ./ 20 | RUN npm ci --production 21 | CMD [ "npm", "run", "start:prod" ] 22 | -------------------------------------------------------------------------------- /multisig-transactions-monitor/bot-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "developerAbbreviation": "AE", 3 | "protocolName": "Compound", 4 | "protocolAbbreviation": "COMP", 5 | "contracts": { 6 | "multisig": { 7 | "address": "0xbbf3f1421D886E9b2c5D716B5192aC998af2012c", 8 | "abiFile": "GnosisSafe.json", 9 | "events": [ 10 | "AddedOwner", 11 | "ApproveHash", 12 | "ChangedMasterCopy", 13 | "ChangedThreshold", 14 | "DisabledModule", 15 | "EnabledModule", 16 | "ExecutionFailure", 17 | "ExecutionFromModuleFailure", 18 | "ExecutionFromModuleSuccess", 19 | "ExecutionSuccess", 20 | "RemovedOwner", 21 | "SignMsg" 22 | ] 23 | }, 24 | "governance": { 25 | "address": "0xc0Da02939E1441F497fd74F78cE7Decb17B66529", 26 | "abiFile": "GovernorBravo.json", 27 | "events": [ 28 | "ProposalCreated", 29 | "ProposalExecuted", 30 | "ProposalCanceled", 31 | "VoteCast", 32 | "ProposalThresholdSet", 33 | "NewAdmin" 34 | ] 35 | }, 36 | "comptroller": { 37 | "address": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 38 | "abiFile": "Comptroller.json", 39 | "protocolVersion": "2", 40 | "events": [ 41 | "NewPauseGuardian", 42 | "ActionPaused", 43 | "NewBorrowCap", 44 | "NewBorrowCapGuardian" 45 | ] 46 | }, 47 | "comet_usdc": { 48 | "address": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", 49 | "abiFile": "Comet.json", 50 | "protocolVersion": "3", 51 | "events": ["PauseAction"] 52 | } 53 | }, 54 | "v2Addresses": { 55 | "comptroller": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", 56 | "comp": "0xc00e94Cb662C3520282E6f5717214004A7f26888", 57 | "timelock": "0x6d903f6003cca6255d85cca4d3b5e5146dc33925" 58 | }, 59 | "v3Addresses": { 60 | "comptrollerV2": "0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b", 61 | "comet": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", 62 | "configurator": "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3", 63 | "rewards": "0x1B0e765F6224C21223AeA2af16c1C46E38885a40", 64 | "bulker": "0x74a81F84268744a40FEBc48f8b812a1f188D80C3" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /multisig-transactions-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-compound-finance-multisig-transaction-bot", 3 | "version": "0.0.6", 4 | "description": "Forta Bot monitoring transactions for the Compound Finance Community Multisig Contract", 5 | "chainIds": [ 6 | 1 7 | ], 8 | "scripts": { 9 | "start": "npm run start:dev", 10 | "start:prod": "forta-agent run --prod", 11 | "tx": "forta-agent run --tx", 12 | "block": "forta-agent run --block", 13 | "range": "forta-agent run --range", 14 | "file": "forta-agent run --file", 15 | "publish": "forta-agent publish", 16 | "push": "forta-agent push", 17 | "disable": "forta-agent disable", 18 | "enable": "forta-agent enable", 19 | "keyfile": "forta-agent keyfile", 20 | "test": "jest" 21 | }, 22 | "dependencies": { 23 | "forta-agent": "0.1.1" 24 | }, 25 | "devDependencies": { 26 | "eslint": "8.16.0", 27 | "eslint-config-airbnb-base": "15.0.0", 28 | "eslint-plugin-import": "2.26.0", 29 | "jest": "28.1.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /oracle-price-monitor/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | forta.config.json 4 | -------------------------------------------------------------------------------- /oracle-price-monitor/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'airbnb-base', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 12, 13 | }, 14 | rules: { 15 | }, 16 | overrides: [ 17 | { 18 | files: '*', 19 | rules: { 20 | 'no-console': 'off', 21 | }, 22 | }, 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /oracle-price-monitor/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | forta.config.json 4 | node_modules 5 | dist 6 | -------------------------------------------------------------------------------- /oracle-price-monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage: obfuscate Javascript (optional) 2 | # FROM node:14.15.5-alpine as builder 3 | # WORKDIR /app 4 | # COPY . . 5 | # RUN npm install -g javascript-obfuscator 6 | # RUN javascript-obfuscator ./src --output ./dist --split-strings true --split-strings-chunk-length 3 7 | 8 | # Final stage: install production dependencies 9 | FROM node:12-alpine 10 | ENV NODE_ENV=production 11 | LABEL "network.forta.settings.agent-logs.enable"="true" 12 | WORKDIR /app 13 | # if using obfuscated code from build stage: 14 | # COPY --from=builder /app/dist ./src 15 | # else if using unobfuscated code: 16 | COPY ./abi ./abi 17 | COPY ./src ./src 18 | COPY package*.json ./ 19 | RUN npm ci --production 20 | CMD [ "npm", "run", "start:prod" ] 21 | -------------------------------------------------------------------------------- /oracle-price-monitor/LICENSE: -------------------------------------------------------------------------------- 1 | Compound Oracle Price Monitor Forta Bot 2 | 3 | Copyright (C) 2022 Arbitrary Execution 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /oracle-price-monitor/README.md: -------------------------------------------------------------------------------- 1 | # Compound Oracle Price Monitor Bot 2 | 3 | ## Description 4 | 5 | This bot monitors the UniswapAnchoredProxy contract for PriceGuarded events which indicate that 6 | a ValidatorProxy reported a cToken price that is outside of the Uniswap V3 TWAP percent threshold. 7 | 8 | ## Alerts 9 | 10 | 11 | - AE-COMP-CTOKEN-PRICE-REJECTED 12 | - Type is always set to `Degraded` 13 | - Severity is always set to `High` 14 | - Metadata field contains: 15 | - Address of the affected cToken 16 | - Address of the underlying token 17 | - Address of the respective ValidatorProxy contract 18 | - Anchor Price (current price) 19 | - Reporter Price (failed price) 20 | 21 | ## Testing 22 | 23 | Running against a real transaction: 24 | ```console 25 | npx forta-agent run --tx 0xe9456ccee1b1764dfe80291f3b894a29f0789f20f995de7d88ff186e8cafe55c 26 | ``` 27 | 28 | Run unit tests: 29 | ```console 30 | npm test 31 | ``` 32 | -------------------------------------------------------------------------------- /oracle-price-monitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forta-ae-oracle-price-monitor", 3 | "version": "0.0.5", 4 | "chainIds": [ 5 | 1 6 | ], 7 | "description": "This Bot monitors the UniswapAnchoredView contract to see if any price updates have been rejected.", 8 | "scripts": { 9 | "start": "npm run start:dev", 10 | "start:prod": "forta-agent run --prod", 11 | "tx": "forta-agent run --tx", 12 | "block": "forta-agent run --block", 13 | "range": "forta-agent run --range", 14 | "file": "forta-agent run --file", 15 | "publish": "forta-agent publish", 16 | "push": "forta-agent push", 17 | "disable": "forta-agent disable", 18 | "enable": "forta-agent enable", 19 | "keyfile": "forta-agent keyfile", 20 | "test": "jest" 21 | }, 22 | "dependencies": { 23 | "forta-agent": "0.0.38" 24 | }, 25 | "devDependencies": { 26 | "eslint": "8.16.0", 27 | "eslint-config-airbnb-base": "15.0.0", 28 | "eslint-plugin-import": "2.26.0", 29 | "jest": "28.1.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "compound-monitoring", 3 | "version": "1.0.0", 4 | 5 | "devDependencies": { 6 | "prettier": "^2.8.8", 7 | "prettier-plugin-solidity": "^1.1.3" 8 | } 9 | } 10 | --------------------------------------------------------------------------------