├── .dockerignore ├── CODEOWNERS ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── bug_report.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── release.yaml │ ├── lint.yaml │ └── test.yaml └── dependabot.yml ├── internal ├── engine │ ├── protocol │ │ ├── near │ │ │ ├── data_source_test.go │ │ │ ├── state.go │ │ │ ├── filter.go │ │ │ └── option.go │ │ ├── atproto │ │ │ ├── filter.go │ │ │ ├── state.go │ │ │ ├── option.go │ │ │ └── task.go │ │ ├── activitypub │ │ │ └── state.go │ │ ├── arweave │ │ │ ├── state.go │ │ │ ├── filter.go │ │ │ └── data_source_test.go │ │ ├── ethereum │ │ │ ├── state.go │ │ │ └── filter.go │ │ ├── farcaster │ │ │ ├── state.go │ │ │ ├── option.go │ │ │ └── task.go │ │ └── factory.go │ ├── worker │ │ ├── decentralized │ │ │ ├── core │ │ │ │ ├── near │ │ │ │ │ └── config.go │ │ │ │ ├── arweave │ │ │ │ │ └── config.go │ │ │ │ ├── ethereum │ │ │ │ │ └── config.go │ │ │ │ └── worker.go │ │ │ └── contract │ │ │ │ ├── linear │ │ │ │ ├── config.go │ │ │ │ └── schema.go │ │ │ │ ├── nearsocial │ │ │ │ ├── config.go │ │ │ │ └── schema.go │ │ │ │ ├── mirror │ │ │ │ └── model │ │ │ │ │ └── dataset_mirror_post.go │ │ │ │ ├── lens │ │ │ │ └── utils.go │ │ │ │ ├── curve │ │ │ │ └── pool │ │ │ │ │ └── schema.go │ │ │ │ └── crossbell │ │ │ │ └── schema.go │ │ ├── rss │ │ │ └── factory.go │ │ ├── federated │ │ │ └── factory.go │ │ └── ai │ │ │ └── core │ │ │ └── agentdata │ │ │ └── worker.go │ ├── data_source.go │ ├── checkpoint.go │ ├── worker.go │ └── task.go ├── stream │ ├── driver.go │ ├── client.go │ └── provider │ │ └── provider.go ├── database │ ├── driver.go │ ├── model │ │ ├── dataset_ens_namehash.go │ │ ├── dataset_farcaster_profile.go │ │ ├── dataset_bluesky_profile.go │ │ ├── dataset_mastodon_handle.go │ │ └── activity.go │ └── dialer │ │ ├── postgres │ │ ├── migration │ │ │ ├── 20240425043201_add_calldata.sql │ │ │ ├── 20231228162957_add_checkpoints_index_count_column.sql │ │ │ ├── 20241218042140_add_activities_indexes.sql │ │ │ ├── 20240115040941_add_ens_namehash.sql │ │ │ ├── 20240922233919_add_mastodon_handles.sql │ │ │ └── 20241210031220_add_bluesky_profiles.sql │ │ └── table │ │ │ ├── dataset_ens_namehash.go │ │ │ ├── dataset_mirror_post.go │ │ │ ├── dataset_mastodon_update_handle.go │ │ │ ├── dataset_farcaster_profile.go │ │ │ ├── dataset_bluesky_profile.go │ │ │ └── checkpoint.go │ │ └── dialer.go ├── node │ ├── component │ │ ├── component.go │ │ ├── rss │ │ │ ├── option.go │ │ │ └── handler.go │ │ ├── middleware │ │ │ └── auth.go │ │ ├── federated │ │ │ └── transformer_activity.go │ │ └── ai │ │ │ └── option.go │ ├── middlewarex │ │ └── middlewarex_test.go │ └── broadcaster │ │ └── server.go ├── constant │ └── version.go ├── telemetry │ ├── meter │ │ └── meter.go │ └── tracer │ │ └── tracer.go └── utils │ └── utils.go ├── docs ├── schemas │ ├── Cursor.yaml │ ├── To.yaml │ ├── NodeInfoData.yaml │ ├── Worker.yaml │ ├── Authentication.yaml │ ├── Platform.yaml │ ├── RSSAccount.yaml │ ├── Success.yaml │ ├── Types.yaml │ ├── DecentralizedAccount.yaml │ ├── Networks.yaml │ ├── Timestamp.yaml │ ├── FederatedAccount.yaml │ ├── ActionPage.yaml │ ├── Tags.yaml │ ├── ProtocolDirection.yaml │ ├── ProtocolTag.yaml │ ├── MetaCursor.yaml │ ├── RSSWorker.yaml │ ├── MetaTotalPages.yaml │ ├── ProtocolNetwork.yaml │ ├── RSSPlatform.yaml │ ├── Error.yaml │ ├── FederatedWorker.yaml │ ├── Limit.yaml │ ├── ActionLimit.yaml │ ├── NetworkConfigDetail.yaml │ ├── Version.yaml │ ├── FederatedPlatform.yaml │ ├── ProtocolType.yaml │ ├── EndpointConfig.yaml │ ├── MinimumResource.yaml │ ├── WorkerStatus.yaml │ ├── tmpl │ │ ├── RSS.yaml.tmpl │ │ ├── Federated.yaml.tmpl │ │ └── Decentralized.yaml.tmpl │ ├── WorkerProgress.yaml │ ├── ProtocolMetadata.yaml │ ├── ConfigDetail.yaml │ ├── Calldata.yaml │ ├── Fee.yaml │ ├── WorkerConfig.yaml │ ├── Reward.yaml │ ├── WorkerInfo.yaml │ ├── NetworkConfig.yaml │ ├── Parameters.yaml │ ├── Records.yaml │ ├── DecentralizedAction.yaml │ ├── RSSAction.yaml │ ├── FederatedAction.yaml │ ├── FederatedMetadata.yaml │ ├── DecentralizedWorker.yaml │ ├── DecentralizedPlatform.yaml │ ├── RSSMetadata.yaml │ ├── RSSActivity.yaml │ ├── FederatedActivity.yaml │ └── ComponentInfo.yaml ├── responses │ ├── NotFound.yaml │ ├── NodeInfoResponse.yaml │ ├── NetworkConfigResponse.yaml │ ├── BadRequest.yaml │ ├── InternalError.yaml │ ├── AIResponse.yaml │ ├── WorkerInfoResponse.yaml │ ├── FederatedActivityResponse.yaml │ ├── DecentralizedActivityResponse.yaml │ ├── FederatedActivitiesResponse.yaml │ └── DecentralizedActivitiesResponse.yaml ├── parameters │ ├── path_rss.yaml │ ├── path_ai.yaml │ ├── path_platform_federated.yaml │ ├── path_network.yaml │ ├── path_platform_decentralized.yaml │ ├── query_tag.yaml │ ├── query_cursor.yaml │ ├── query_type.yaml │ ├── query_network.yaml │ ├── query_direction.yaml │ ├── path_activity_id.yaml │ ├── query_success.yaml │ ├── query_until_timestamp.yaml │ ├── path_account_decentralized.yaml │ ├── query_since_timestamp.yaml │ ├── query_action_page.yaml │ ├── query_limit.yaml │ ├── query_platform_federated.yaml │ ├── path_account_federated.yaml │ ├── query_action_limit.yaml │ └── query_platform_decentralized.yaml ├── cfg.yaml ├── path │ ├── info.yaml │ ├── workers_status.yaml │ ├── networks │ │ └── config.yaml │ ├── ai.yaml │ ├── version.yaml │ ├── rss.yaml │ ├── home.yaml │ ├── federated │ │ ├── tx.yaml │ │ ├── accounts.yaml │ │ ├── network.yaml │ │ ├── platform.yaml │ │ └── account.yaml │ ├── decentralized │ │ ├── tx.yaml │ │ ├── accounts.yaml │ │ ├── metadata.yaml │ │ ├── network.yaml │ │ ├── platform.yaml │ │ └── account.yaml │ └── activity_count.yaml ├── tool.go └── requestBody │ ├── BatchGetFederatedAccountsActivities.yaml │ ├── BatchGetDecentralizedAccountsActivities.yaml │ └── BatchGetDecentralizedMetadataActivities.yaml ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── config ├── flag │ └── config.go ├── parameter │ ├── README.md │ └── data.go └── validator.go ├── provider ├── arweave │ ├── contract │ │ ├── mirror │ │ │ └── contract.go │ │ ├── paragraph │ │ │ └── contract.go │ │ └── momoka │ │ │ └── contract.go │ ├── type_network.go │ ├── bundle │ │ ├── irys │ │ │ ├── genqlient.yaml │ │ │ ├── graphql.config.yaml │ │ │ ├── constant.go │ │ │ ├── operation_test.go │ │ │ └── operation │ │ │ │ └── transactions.graphql │ │ ├── transaction.go │ │ └── signature.go │ ├── type_block.go │ ├── utils.go │ ├── type_transaction.go │ └── gateway.go ├── near │ ├── utils.go │ └── client_test.go ├── ethereum │ ├── contract │ │ ├── erc165 │ │ │ ├── contract.go │ │ │ └── abi │ │ │ │ └── ERC165.abi │ │ ├── iqwiki │ │ │ ├── graphql.config.yaml │ │ │ ├── genqlient.yaml │ │ │ ├── client_test.go │ │ │ ├── contract.go │ │ │ ├── client.go │ │ │ └── operation │ │ │ │ └── activities.graphql │ │ ├── ens │ │ │ ├── action.go │ │ │ ├── erc1577 │ │ │ │ └── contenthash.go │ │ │ └── contract_test.go │ │ ├── matters │ │ │ └── contract.go │ │ ├── zerion │ │ │ └── contract.go │ │ ├── erc20 │ │ │ └── contract.go │ │ ├── cow │ │ │ └── contract.go │ │ ├── erc721 │ │ │ └── contract.go │ │ ├── erc1155 │ │ │ └── contract.go │ │ ├── highlight │ │ │ └── contract.go │ │ ├── savm │ │ │ └── contract.go │ │ ├── aavegotchi │ │ │ └── contract.go │ │ ├── kiwistand │ │ │ └── contract.go │ │ ├── selector_test.go │ │ ├── weth │ │ │ └── contract.go │ │ ├── arbitrum │ │ │ └── abi │ │ │ │ └── L1ERC20Gateway.abi │ │ ├── polymarket │ │ │ └── contract.go │ │ ├── rainbow │ │ │ └── contract.go │ │ ├── benddao │ │ │ └── contract.go │ │ ├── paraswap │ │ │ └── contract.go │ │ ├── selector.go │ │ ├── base │ │ │ └── contract.go │ │ └── nouns │ │ │ └── contract.go │ ├── option.go │ └── etherface │ │ └── client_test.go ├── atproto │ └── model.go ├── ipfs │ ├── gateway.go │ ├── gateway_test.go │ └── url.go └── redis │ └── client.go ├── cmd └── tools.go ├── deploy ├── README.md └── default │ └── config.default.yaml ├── .run ├── build.run.xml ├── image.run.xml └── run.run.xml ├── schema └── worker │ ├── status.go │ ├── rss │ ├── platform.go │ └── worker.go │ ├── federated │ ├── platform.go │ └── worker.go │ └── worker.go ├── .pre-commit-config.yaml ├── .gitignore ├── Dockerfile ├── .golangci.yaml ├── LICENSE ├── README.md └── common ├── http └── response │ └── error.go └── sync └── quickgroup_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @polebug @pseudoyu 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /internal/engine/protocol/near/data_source_test.go: -------------------------------------------------------------------------------- 1 | package near_test 2 | -------------------------------------------------------------------------------- /docs/schemas/Cursor.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | description: Specify the cursor used for pagination -------------------------------------------------------------------------------- /docs/schemas/To.yaml: -------------------------------------------------------------------------------- 1 | description: The address to which the action is directed. 2 | type: string 3 | -------------------------------------------------------------------------------- /docs/schemas/NodeInfoData.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | data: 3 | $ref: "./NodeInfo.yaml" 4 | type: object 5 | -------------------------------------------------------------------------------- /docs/schemas/Worker.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: "./DecentralizedWorker.yaml" 3 | - $ref: "./FederatedWorker.yaml" 4 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:39 2 | 3 | RUN dnf update -y && \ 4 | dnf install procps git make golang -y 5 | -------------------------------------------------------------------------------- /docs/schemas/Authentication.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | access_key: 3 | $ref: "./ConfigDetail.yaml" 4 | type: object 5 | -------------------------------------------------------------------------------- /docs/schemas/Platform.yaml: -------------------------------------------------------------------------------- 1 | allOf: 2 | - $ref: "./DecentralizedPlatform.yaml" 3 | - $ref: "./FederatedPlatform.yaml" 4 | -------------------------------------------------------------------------------- /docs/schemas/RSSAccount.yaml: -------------------------------------------------------------------------------- 1 | description: The owner of the activity. 2 | type: string 3 | example: 4 | - "www.abc.net.au" -------------------------------------------------------------------------------- /docs/schemas/Success.yaml: -------------------------------------------------------------------------------- 1 | type: boolean 2 | description: Retrieve activities based on success status 3 | x-go-name: Status -------------------------------------------------------------------------------- /docs/schemas/Types.yaml: -------------------------------------------------------------------------------- 1 | items: 2 | $ref: "./ProtocolType.yaml" 3 | type: array 4 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /docs/schemas/DecentralizedAccount.yaml: -------------------------------------------------------------------------------- 1 | description: The owner of the activity. 2 | type: string 3 | pattern: 0x[0-9a-fA-F]{40} -------------------------------------------------------------------------------- /docs/schemas/Networks.yaml: -------------------------------------------------------------------------------- 1 | items: 2 | $ref: "./ProtocolNetwork.yaml" 3 | type: array 4 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /docs/schemas/Timestamp.yaml: -------------------------------------------------------------------------------- 1 | description: The timestamp of when the activity occurred. 2 | type: integer 3 | x-go-type: uint64 -------------------------------------------------------------------------------- /internal/engine/protocol/atproto/filter.go: -------------------------------------------------------------------------------- 1 | package atproto 2 | 3 | type Filter struct { 4 | Type []string `json:"type"` 5 | } 6 | -------------------------------------------------------------------------------- /docs/schemas/FederatedAccount.yaml: -------------------------------------------------------------------------------- 1 | description: The owner of the activity. 2 | type: string 3 | example: "@seachdamh@101010.pl" 4 | 5 | -------------------------------------------------------------------------------- /config/flag/config.go: -------------------------------------------------------------------------------- 1 | package flag 2 | 3 | var ( 4 | KeyConfig = "config" 5 | KeyModule = "module" 6 | KeyWorkerID = "worker.id" 7 | ) 8 | -------------------------------------------------------------------------------- /docs/schemas/ActionPage.yaml: -------------------------------------------------------------------------------- 1 | default: 1 2 | minimum: 1 3 | type: integer 4 | x-oapi-codegen-extra-tags: 5 | validate: "min=1" 6 | default: "1" -------------------------------------------------------------------------------- /provider/arweave/contract/mirror/contract.go: -------------------------------------------------------------------------------- 1 | package mirror 2 | 3 | var ( 4 | AddressMirror = "Ky1c1Kkt-jZ9sY1hvLF5nCf6WWdBhIU5Un_BMYh-t3c" 5 | ) 6 | -------------------------------------------------------------------------------- /provider/arweave/contract/paragraph/contract.go: -------------------------------------------------------------------------------- 1 | package paragraph 2 | 3 | var ( 4 | AddressParagraph = "w5AtiFsNvORfcRtikbdrp2tzqixb05vdPw-ZhgVkD70" 5 | ) 6 | -------------------------------------------------------------------------------- /cmd/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package main 5 | 6 | import ( 7 | _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" 8 | ) 9 | -------------------------------------------------------------------------------- /internal/stream/driver.go: -------------------------------------------------------------------------------- 1 | package stream 2 | 3 | type Driver string 4 | 5 | const ( 6 | DriverKafka Driver = "kafka" 7 | DriverPulsar Driver = "pulsar" 8 | ) 9 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/core/near/config.go: -------------------------------------------------------------------------------- 1 | package near 2 | 3 | type Config struct { 4 | // TODO Implement support for customizable configurations. 5 | } 6 | -------------------------------------------------------------------------------- /config/parameter/README.md: -------------------------------------------------------------------------------- 1 | ## Parameter 2 | 3 | This directory contains the parameters affecting the behavior of the Node. 4 | 5 | The parameters must NOT be changed manually. -------------------------------------------------------------------------------- /docs/responses/NotFound.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | $ref: "../schemas/Error.yaml" 5 | description: The specified resource was not found. 6 | -------------------------------------------------------------------------------- /docs/responses/NodeInfoResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | $ref: "../schemas/NodeInfoData.yaml" 5 | description: The request was successful. 6 | -------------------------------------------------------------------------------- /docs/schemas/Tags.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities for the specified tag(s) 2 | items: 3 | $ref: "./ProtocolTag.yaml" 4 | type: array 5 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /internal/database/driver.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | type Driver string 4 | 5 | const ( 6 | DriverPostgreSQL Driver = "postgres" 7 | DriverMySQL Driver = "mysql" 8 | ) 9 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/linear/config.go: -------------------------------------------------------------------------------- 1 | package linear 2 | 3 | type Config struct { 4 | // TODO Implement support for customizable configurations. 5 | } 6 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/core/arweave/config.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | type Config struct { 4 | // TODO Implement support for customizable configurations. 5 | } 6 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/core/ethereum/config.go: -------------------------------------------------------------------------------- 1 | package ethereum 2 | 3 | type Config struct { 4 | // TODO Implement support for customizable configurations. 5 | } 6 | -------------------------------------------------------------------------------- /docs/parameters/path_rss.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve details for the specified RSS path 2 | example: abc 3 | in: path 4 | name: path 5 | required: true 6 | schema: 7 | type: string 8 | -------------------------------------------------------------------------------- /docs/schemas/ProtocolDirection.yaml: -------------------------------------------------------------------------------- 1 | allOf: 2 | - $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/enum/Direction.yaml" 3 | # - x-go-type: string -------------------------------------------------------------------------------- /docs/responses/NetworkConfigResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | $ref: "../schemas/NetworkConfigData.yaml" 5 | description: The request was successful. 6 | -------------------------------------------------------------------------------- /docs/schemas/ProtocolTag.yaml: -------------------------------------------------------------------------------- 1 | allOf: 2 | - $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/enum/Tag.yaml" 3 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/nearsocial/config.go: -------------------------------------------------------------------------------- 1 | package nearsocial 2 | 3 | type Config struct { 4 | // TODO Implement support for customizable configurations. 5 | } 6 | -------------------------------------------------------------------------------- /docs/responses/BadRequest.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | $ref: '../schemas/Error.yaml' 5 | description: The request is malformed or contains invalid parameters. 6 | -------------------------------------------------------------------------------- /provider/arweave/type_network.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | // Network represents the Network information of the Arweave network. 4 | type Network struct { 5 | Blocks int64 `json:"blocks"` 6 | } 7 | -------------------------------------------------------------------------------- /docs/parameters/path_ai.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve details for the specified AgentData path 2 | example: api/v1/ai_intel 3 | in: path 4 | name: path 5 | required: true 6 | schema: 7 | type: string 8 | -------------------------------------------------------------------------------- /docs/responses/InternalError.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | $ref: "../schemas/Error.yaml" 5 | description: An internal server error occurred while processing the request. 6 | -------------------------------------------------------------------------------- /docs/schemas/MetaCursor.yaml: -------------------------------------------------------------------------------- 1 | description: Metadata for paginated responses. 2 | properties: 3 | cursor: 4 | description: The cursor for the next set of results. 5 | type: string 6 | type: object 7 | -------------------------------------------------------------------------------- /internal/engine/protocol/near/state.go: -------------------------------------------------------------------------------- 1 | package near 2 | 3 | type State struct { 4 | BlockHeight uint64 `json:"block_height,omitempty"` 5 | BlockTimestamp uint64 `json:"block_timestamp,omitempty"` 6 | } 7 | -------------------------------------------------------------------------------- /provider/arweave/bundle/irys/genqlient.yaml: -------------------------------------------------------------------------------- 1 | schema: schema.graphql 2 | operations: 3 | - ./operation/transactions.graphql 4 | generated: operation.go 5 | bindings: 6 | BigInt: 7 | type: "*math/big.Int" 8 | -------------------------------------------------------------------------------- /internal/engine/protocol/activitypub/state.go: -------------------------------------------------------------------------------- 1 | package activitypub 2 | 3 | // State represents the state of the ActivityPub data protocol. 4 | type State struct { 5 | LastOffset int64 `json:"last_offset"` 6 | } 7 | -------------------------------------------------------------------------------- /docs/parameters/path_platform_federated.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified platform. 2 | in: path 3 | name: platform 4 | required: true 5 | schema: 6 | $ref: "../schemas/FederatedPlatform.yaml" 7 | -------------------------------------------------------------------------------- /docs/schemas/RSSWorker.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | enum: 3 | - core 4 | x-go-type: rss.Worker 5 | x-go-type-skip-optional-pointer: true 6 | x-go-type-import: 7 | path: github.com/rss3-network/node/v2/schema/worker/rss 8 | -------------------------------------------------------------------------------- /docs/parameters/path_network.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified network. 2 | example: ethereum 3 | in: path 4 | name: network 5 | required: true 6 | schema: 7 | $ref: "../schemas/ProtocolNetwork.yaml" 8 | -------------------------------------------------------------------------------- /docs/schemas/MetaTotalPages.yaml: -------------------------------------------------------------------------------- 1 | description: Metadata indicating the total number of pages. 2 | properties: 3 | totalPages: 4 | description: The total number of pages available. 5 | type: integer 6 | type: object 7 | -------------------------------------------------------------------------------- /docs/schemas/ProtocolNetwork.yaml: -------------------------------------------------------------------------------- 1 | allOf: 2 | - $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/enum/Network.yaml" 3 | # - x-go-type: string 4 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /docs/parameters/path_platform_decentralized.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified platform. 2 | in: path 3 | name: platform 4 | required: true 5 | schema: 6 | $ref: "../schemas/DecentralizedPlatform.yaml" 7 | -------------------------------------------------------------------------------- /docs/parameters/query_tag.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities for the specified tag(s). 2 | in: query 3 | name: tag 4 | required: false 5 | schema: 6 | $ref: "../schemas/Tags.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: tag -------------------------------------------------------------------------------- /docs/parameters/query_cursor.yaml: -------------------------------------------------------------------------------- 1 | description: Specify the cursor used for pagination. 2 | in: query 3 | name: cursor 4 | required: false 5 | schema: 6 | $ref: "../schemas/Cursor.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: cursor -------------------------------------------------------------------------------- /docs/parameters/query_type.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities for the specified type(s). 2 | in: query 3 | name: type 4 | required: false 5 | schema: 6 | $ref: "../schemas/Types.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: "-" -------------------------------------------------------------------------------- /docs/schemas/RSSPlatform.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | enum: 3 | - Unknown 4 | - RSSHub 5 | x-go-type: rss.Platform 6 | x-go-type-skip-optional-pointer: true 7 | x-go-type-import: 8 | path: github.com/rss3-network/node/v2/schema/worker/rss 9 | -------------------------------------------------------------------------------- /docs/responses/AIResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | type: object 5 | description: Response with AI-generated content of any structure 6 | description: JSON response containing AI-generated content 7 | -------------------------------------------------------------------------------- /docs/parameters/query_network.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified network(s). 2 | in: query 3 | name: network 4 | required: false 5 | schema: 6 | $ref: "../schemas/Networks.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: network -------------------------------------------------------------------------------- /docs/responses/WorkerInfoResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | type: object 5 | properties: 6 | data: 7 | $ref: "../schemas/ComponentInfo.yaml" 8 | description: The request was successful. 9 | -------------------------------------------------------------------------------- /docs/schemas/Error.yaml: -------------------------------------------------------------------------------- 1 | description: An error response. 2 | properties: 3 | code: 4 | description: The error code. 5 | type: integer 6 | message: 7 | description: The error message. 8 | type: string 9 | type: object 10 | -------------------------------------------------------------------------------- /docs/parameters/query_direction.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities based on direction. 2 | in: query 3 | name: direction 4 | required: false 5 | schema: 6 | $ref: "../schemas/ProtocolDirection.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: direction -------------------------------------------------------------------------------- /docs/schemas/FederatedWorker.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | enum: 3 | - mastodon 4 | - bluesky 5 | x-go-type: federated.Worker 6 | x-go-type-skip-optional-pointer: true 7 | x-go-type-import: 8 | path: github.com/rss3-network/node/v2/schema/worker/federated 9 | -------------------------------------------------------------------------------- /provider/near/utils.go: -------------------------------------------------------------------------------- 1 | package near 2 | 3 | import ( 4 | "encoding/base64" 5 | ) 6 | 7 | // DecodeBase64 decodes a base64 string. 8 | func DecodeBase64(data string) ([]byte, error) { 9 | return base64.StdEncoding.DecodeString(data) 10 | } 11 | -------------------------------------------------------------------------------- /docs/parameters/path_activity_id.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve details for the specified activity ID 2 | example: '0x840e42d573ebe1ff27a9e4914573b4e0518fcd685c7f9331d319abe854f780e3' 3 | in: path 4 | name: id 5 | required: true 6 | schema: 7 | type: string 8 | -------------------------------------------------------------------------------- /docs/schemas/Limit.yaml: -------------------------------------------------------------------------------- 1 | type: integer 2 | description: Specify the number of activities to retrieve 3 | example: 20 4 | default: 100 5 | minimum: 1 6 | maximum: 100 7 | x-oapi-codegen-extra-tags: 8 | validate: "min=1,max=100" 9 | default: "100" 10 | -------------------------------------------------------------------------------- /docs/parameters/query_success.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities based on success status. 2 | in: query 3 | name: success 4 | required: false 5 | schema: 6 | $ref: "../schemas/Success.yaml" 7 | x-go-name: Status 8 | x-oapi-codegen-extra-tags: 9 | query: success -------------------------------------------------------------------------------- /docs/parameters/query_until_timestamp.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities up to this timestamp. 2 | in: query 3 | name: until_timestamp 4 | required: false 5 | schema: 6 | $ref: "../schemas/Timestamp.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: until_timestamp -------------------------------------------------------------------------------- /docs/schemas/ActionLimit.yaml: -------------------------------------------------------------------------------- 1 | type: integer 2 | description: Specify the number of actions within the activity to retrieve 3 | example: 10 4 | default: 10 5 | maximum: 20 6 | minimum: 1 7 | x-oapi-codegen-extra-tags: 8 | validate: "min=1,max=20" 9 | default: "10" -------------------------------------------------------------------------------- /docs/schemas/NetworkConfigDetail.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | endpoint_configs: 3 | $ref: "./EndpointConfig.yaml" 4 | id: 5 | type: string 6 | worker_configs: 7 | items: 8 | $ref: "./WorkerConfig.yaml" 9 | type: array 10 | type: object 11 | -------------------------------------------------------------------------------- /docs/schemas/Version.yaml: -------------------------------------------------------------------------------- 1 | description: The git version info of node. 2 | properties: 3 | commit: 4 | description: The git commit of node. 5 | type: string 6 | tag: 7 | description: The git tag of node. 8 | type: string 9 | type: object 10 | -------------------------------------------------------------------------------- /internal/engine/protocol/arweave/state.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | type State struct { 4 | BlockHeight uint64 `json:"block_height,omitempty"` 5 | Cursor string `json:"cursor,omitempty"` 6 | BlockTimestamp uint64 `json:"block_timestamp,omitempty"` 7 | } 8 | -------------------------------------------------------------------------------- /docs/parameters/path_account_decentralized.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified account. 2 | in: path 3 | name: account 4 | required: true 5 | schema: 6 | $ref: "../schemas/DecentralizedAccount.yaml" 7 | example: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" -------------------------------------------------------------------------------- /docs/parameters/query_since_timestamp.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities starting from this timestamp. 2 | in: query 3 | name: since_timestamp 4 | required: false 5 | schema: 6 | $ref: "../schemas/Timestamp.yaml" 7 | x-oapi-codegen-extra-tags: 8 | query: since_timestamp -------------------------------------------------------------------------------- /provider/ethereum/contract/erc165/contract.go: -------------------------------------------------------------------------------- 1 | package erc165 2 | 3 | // https://eips.ethereum.org/EIPS/eip-165 4 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/ERC165.abi --pkg erc165 --type ERC165 --out contract_erc165.go 5 | -------------------------------------------------------------------------------- /internal/database/model/dataset_ens_namehash.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/ethereum/go-ethereum/common" 4 | 5 | type ENSNamehash struct { 6 | Hash common.Hash `json:"hash"` // Hexadecimal hash bytes 7 | Name string `json:"name"` // ENS name, *.eth 8 | } 9 | -------------------------------------------------------------------------------- /internal/engine/protocol/ethereum/state.go: -------------------------------------------------------------------------------- 1 | package ethereum 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | ) 6 | 7 | type State struct { 8 | BlockHash common.Hash `json:"block_hash"` 9 | BlockNumber uint64 `json:"block_number"` 10 | } 11 | -------------------------------------------------------------------------------- /provider/arweave/bundle/irys/graphql.config.yaml: -------------------------------------------------------------------------------- 1 | schema: schema.graphql 2 | documents: "*.graphql" 3 | extensions: 4 | endpoints: 5 | mainnet: 6 | url: https://arweave.mainnet.irys.xyz/graphql 7 | devnet: 8 | url: https://arweave.devnet.irys.xyz/graphql 9 | -------------------------------------------------------------------------------- /docs/schemas/FederatedPlatform.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | enum: 3 | - Unknown 4 | - Mastodon 5 | - Bluesky 6 | x-go-type: federated.Platform 7 | x-go-type-skip-optional-pointer: true 8 | x-go-type-import: 9 | path: github.com/rss3-network/node/v2/schema/worker/federated 10 | -------------------------------------------------------------------------------- /internal/engine/protocol/near/filter.go: -------------------------------------------------------------------------------- 1 | package near 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/internal/engine" 5 | ) 6 | 7 | var _ engine.DataSourceFilter = (*Filter)(nil) 8 | 9 | type Filter struct { 10 | ReceiverIDs []string `yaml:"receiver_ids"` 11 | } 12 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/mirror/model/dataset_mirror_post.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // DatasetMirrorPost represents a mirror post for revise logic check. 4 | type DatasetMirrorPost struct { 5 | TransactionID string 6 | OriginContentDigest string 7 | } 8 | -------------------------------------------------------------------------------- /internal/stream/client.go: -------------------------------------------------------------------------------- 1 | package stream 2 | 3 | import ( 4 | "context" 5 | 6 | activityx "github.com/rss3-network/protocol-go/schema/activity" 7 | ) 8 | 9 | type Client interface { 10 | PushActivities(ctx context.Context, activities []*activityx.Activity) error 11 | } 12 | -------------------------------------------------------------------------------- /provider/ethereum/contract/iqwiki/graphql.config.yaml: -------------------------------------------------------------------------------- 1 | schema: schema.graphql 2 | documents: "**/*.graphql" 3 | extensions: 4 | endpoints: 5 | default: 6 | url: https://graph.everipedia.org/graphql 7 | headers: 8 | user-agent: JS GraphQL 9 | introspect: false -------------------------------------------------------------------------------- /docs/schemas/ProtocolType.yaml: -------------------------------------------------------------------------------- 1 | allOf: 2 | - $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/Type.yaml" 3 | - x-go-type: schema.Type 4 | x-go-type-import: 5 | path: github.com/rss3-network/protocol-go/schema 6 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /internal/engine/protocol/atproto/state.go: -------------------------------------------------------------------------------- 1 | package atproto 2 | 3 | type State struct { 4 | SubscribeCursor int64 `json:"subscribe_cursor,omitempty"` 5 | SubscribeTimestamp int64 `json:"subscribe_timestamp,omitempty"` 6 | ListReposCursor string `json:"list_repos_cursor,omitempty"` 7 | } 8 | -------------------------------------------------------------------------------- /docs/schemas/EndpointConfig.yaml: -------------------------------------------------------------------------------- 1 | description: The endpoint options and config details of the worker. 2 | properties: 3 | http2_disabled: 4 | $ref: "./ConfigDetail.yaml" 5 | http_headers: 6 | $ref: "./ConfigDetail.yaml" 7 | url: 8 | $ref: "./ConfigDetail.yaml" 9 | type: object 10 | -------------------------------------------------------------------------------- /docs/schemas/MinimumResource.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | cpu_core: 3 | format: float 4 | type: number 5 | disk_space_in_gb: 6 | type: integer 7 | key: 8 | type: string 9 | memory_in_gb: 10 | format: float 11 | type: number 12 | title: 13 | type: string 14 | type: object 15 | -------------------------------------------------------------------------------- /docs/parameters/query_action_page.yaml: -------------------------------------------------------------------------------- 1 | description: Specify the pagination for actions 2 | example: 1 3 | in: query 4 | name: action_page 5 | required: false 6 | schema: 7 | $ref: "../schemas/ActionPage.yaml" 8 | x-oapi-codegen-extra-tags: 9 | validate: "min=1" 10 | default: "1" 11 | query: action_page -------------------------------------------------------------------------------- /docs/parameters/query_limit.yaml: -------------------------------------------------------------------------------- 1 | description: Specify the number of activities to retrieve. 2 | example: '20' 3 | in: query 4 | name: limit 5 | required: false 6 | schema: 7 | $ref: "../schemas/Limit.yaml" 8 | x-oapi-codegen-extra-tags: 9 | validate: "min=1,max=100" 10 | default: "100" 11 | query: limit -------------------------------------------------------------------------------- /docs/schemas/WorkerStatus.yaml: -------------------------------------------------------------------------------- 1 | description: The worker status. 2 | type: string 3 | enum: 4 | - Unknown 5 | - Indexing 6 | - Ready 7 | - Unhealthy 8 | x-go-type: worker.Status 9 | x-go-type-skip-optional-pointer: true 10 | x-go-type-import: 11 | path: github.com/rss3-network/node/v2/schema/worker 12 | -------------------------------------------------------------------------------- /docs/schemas/tmpl/RSS.yaml.tmpl: -------------------------------------------------------------------------------- 1 | type: string 2 | {{- with .Values }} 3 | enum: 4 | {{- range . }} 5 | - {{ .name }} 6 | {{- end }} 7 | {{- end }} 8 | x-go-type: rss.{{ .Name }} 9 | x-go-type-skip-optional-pointer: true 10 | x-go-type-import: 11 | path: github.com/rss3-network/node/v2/schema/worker/rss 12 | -------------------------------------------------------------------------------- /deploy/README.md: -------------------------------------------------------------------------------- 1 | ## config.yaml Setup 2 | 3 | Before running the Node, you need to set up the `config.yaml` file. 4 | 5 | 1. Copy `config.example.yaml` to `config.yaml`: 6 | ```bash 7 | cp config.example.yaml config.yaml 8 | ``` 9 | 1. Edit `config.yaml` and fill in all the environment variables. 10 | -------------------------------------------------------------------------------- /docs/schemas/tmpl/Federated.yaml.tmpl: -------------------------------------------------------------------------------- 1 | type: string 2 | {{- with .Values }} 3 | enum: 4 | {{- range . }} 5 | - {{ .name }} 6 | {{- end }} 7 | {{- end }} 8 | x-go-type: federated.{{ .Name }} 9 | x-go-type-skip-optional-pointer: true 10 | x-go-type-import: 11 | path: github.com/rss3-network/node/v2/schema/worker/federated 12 | -------------------------------------------------------------------------------- /docs/responses/FederatedActivityResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | properties: 5 | data: 6 | $ref: '../schemas/FederatedActivity.yaml' 7 | meta: 8 | $ref: '../schemas/MetaTotalPages.yaml' 9 | type: object 10 | description: The request was successful. 11 | -------------------------------------------------------------------------------- /docs/schemas/WorkerProgress.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | properties: 3 | index_count: 4 | description: The index count of worker. 5 | type: integer 6 | indexed_state: 7 | description: The indexed state of worker. 8 | type: integer 9 | remote_state: 10 | description: The remote state of worker. 11 | type: integer -------------------------------------------------------------------------------- /docs/responses/DecentralizedActivityResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | properties: 5 | data: 6 | $ref: '../schemas/DecentralizedActivity.yaml' 7 | meta: 8 | $ref: '../schemas/MetaTotalPages.yaml' 9 | type: object 10 | description: The request was successful. 11 | -------------------------------------------------------------------------------- /docs/schemas/tmpl/Decentralized.yaml.tmpl: -------------------------------------------------------------------------------- 1 | type: string 2 | {{- with .Values }} 3 | enum: 4 | {{- range . }} 5 | - {{ .name }} 6 | {{- end }} 7 | {{- end }} 8 | x-go-type: decentralized.{{ .Name }} 9 | x-go-type-skip-optional-pointer: true 10 | x-go-type-import: 11 | path: github.com/rss3-network/node/v2/schema/worker/decentralized 12 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/lens/utils.go: -------------------------------------------------------------------------------- 1 | package lens 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func EncodeID(id *big.Int) string { 11 | value := strconv.FormatInt(id.Int64(), 16) 12 | 13 | return fmt.Sprintf("0x%s%s", strings.Repeat("0", len(value)%2), value) 14 | } 15 | -------------------------------------------------------------------------------- /provider/arweave/type_block.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | // Block represents a block on the Arweave network. 4 | type Block struct { 5 | Nonce string `json:"nonce"` 6 | Timestamp int64 `json:"timestamp"` 7 | Height int64 `json:"height"` 8 | Hash string `json:"hash"` 9 | Txs []string `json:"txs"` 10 | } 11 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/migration/20240425043201_add_calldata.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | ALTER TABLE "activities" 4 | ADD "calldata" json; 5 | -- +goose StatementEnd 6 | 7 | -- +goose Down 8 | -- +goose StatementBegin 9 | ALTER TABLE "activities" 10 | DROP COLUMN "calldata"; 11 | -- +goose StatementEnd 12 | -------------------------------------------------------------------------------- /docs/parameters/query_platform_federated.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified platform(s). 2 | in: query 3 | name: platform 4 | required: false 5 | schema: 6 | items: 7 | $ref: "../schemas/FederatedPlatform.yaml" 8 | type: array 9 | x-go-type-skip-optional-pointer: true 10 | x-oapi-codegen-extra-tags: 11 | query: platform -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node", 3 | "dockerComposeFile": "docker-compose.yaml", 4 | "service": "devcontainer", 5 | "runServices": [ 6 | "postgres" 7 | ], 8 | "workspaceFolder": "/workspace/${localWorkspaceFolderBasename}", 9 | "forwardPorts": [ 10 | "postgres:8080", 11 | "postgres:5432" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /docs/parameters/path_account_federated.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified account. 2 | in: path 3 | name: account 4 | required: true 5 | schema: 6 | $ref: "../schemas/FederatedAccount.yaml" 7 | examples: 8 | seachdamh: 9 | value: "@seachdamh@101010.pl" 10 | 11 | LukaszHorodecki: 12 | value: "@LukaszHorodecki@pol.social" -------------------------------------------------------------------------------- /docs/parameters/query_action_limit.yaml: -------------------------------------------------------------------------------- 1 | description: Specify the number of actions within the activity to retrieve. 2 | example: '10' 3 | in: query 4 | name: action_limit 5 | required: false 6 | schema: 7 | $ref: "../schemas/ActionLimit.yaml" 8 | x-oapi-codegen-extra-tags: 9 | validate: "min=1,max=20" 10 | default: "10" 11 | query: action_limit 12 | -------------------------------------------------------------------------------- /docs/schemas/ProtocolMetadata.yaml: -------------------------------------------------------------------------------- 1 | description: Additional metadata related to the action. 2 | type: object 3 | allOf: 4 | - $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/Metadata.yaml" 5 | - x-go-type: metadata.Metadata 6 | x-go-type-import: 7 | path: github.com/rss3-network/protocol-go/schema/metadata 8 | -------------------------------------------------------------------------------- /docs/cfg.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json 2 | package: docs 3 | output: ./generated.go 4 | generate: 5 | models: true 6 | echo-server: true 7 | embedded-spec: true 8 | output-options: 9 | user-templates: 10 | echo/echo-wrappers.tmpl: echo/echo-wrappers.tmpl -------------------------------------------------------------------------------- /docs/parameters/query_platform_decentralized.yaml: -------------------------------------------------------------------------------- 1 | description: Retrieve activities from the specified platform(s). 2 | in: query 3 | name: platform 4 | required: false 5 | schema: 6 | items: 7 | $ref: "../schemas/DecentralizedPlatform.yaml" 8 | type: array 9 | x-go-type-skip-optional-pointer: true 10 | x-oapi-codegen-extra-tags: 11 | query: platform -------------------------------------------------------------------------------- /docs/schemas/ConfigDetail.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | description: 3 | type: string 4 | is_required: 5 | type: boolean 6 | key: 7 | type: string 8 | title: 9 | type: string 10 | type: 11 | type: string 12 | value: 13 | type: string 14 | required: 15 | - is_required 16 | - type 17 | - value 18 | - description 19 | type: object 20 | -------------------------------------------------------------------------------- /provider/ethereum/contract/iqwiki/genqlient.yaml: -------------------------------------------------------------------------------- 1 | # Default genqlient config; for full documentation see: 2 | # https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml 3 | schema: schema.graphql 4 | operations: 5 | - ./operation/activities.graphql 6 | bindings: 7 | Any: 8 | type: any 9 | DateTime: 10 | type: time.Time 11 | generated: operation.go -------------------------------------------------------------------------------- /.run/build.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.run/image.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/schemas/Calldata.yaml: -------------------------------------------------------------------------------- 1 | description: Represents the call data associated with an activity. 2 | properties: 3 | function_hash: 4 | description: The hash of the function called. 5 | type: string 6 | parsed_function: 7 | description: The parsed function name. 8 | type: string 9 | raw: 10 | description: The raw calldata. 11 | type: string 12 | type: object 13 | -------------------------------------------------------------------------------- /docs/schemas/Fee.yaml: -------------------------------------------------------------------------------- 1 | description: Represents fee information for an activity. 2 | properties: 3 | address: 4 | description: The address to which the fee is paid. 5 | type: string 6 | amount: 7 | description: The amount of the fee. 8 | type: string 9 | decimal: 10 | description: The decimal precision of the fee amount. 11 | type: integer 12 | type: object 13 | -------------------------------------------------------------------------------- /docs/path/info.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetNodeInfo 3 | summary: Get Node Status 4 | description: Retrieve node status details. 5 | security: [] 6 | tags: 7 | - Info 8 | responses: 9 | "200": 10 | $ref: "../responses/NodeInfoResponse.yaml" 11 | "400": 12 | $ref: "../responses/BadRequest.yaml" 13 | "500": 14 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /internal/database/dialer/postgres/migration/20231228162957_add_checkpoints_index_count_column.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | ALTER TABLE "checkpoints" 4 | ADD "index_count" bigint NOT NULL DEFAULT 0; 5 | -- +goose StatementEnd 6 | 7 | -- +goose Down 8 | -- +goose StatementBegin 9 | ALTER TABLE "checkpoints" 10 | DROP COLUMN "index_count"; 11 | -- +goose StatementEnd 12 | -------------------------------------------------------------------------------- /internal/engine/protocol/ethereum/filter.go: -------------------------------------------------------------------------------- 1 | package ethereum 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/internal/engine" 6 | ) 7 | 8 | var _ engine.DataSourceFilter = (*Filter)(nil) 9 | 10 | type Filter struct { 11 | LogAddresses []common.Address `yaml:"log_addresses"` 12 | LogTopics []common.Hash `yaml:"log_topics"` 13 | } 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | ## Checklist 4 | 5 | - [ ] The commit message follows [Angular Contributing guidelines](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit); 6 | - [ ] Tests for the changes have been added (for bug fixes / features); 7 | 8 | ## Does this PR introduce a breaking change? 9 | 10 | - [ ] Yes 11 | - [ ] No 12 | 13 | ## Other information 14 | -------------------------------------------------------------------------------- /internal/engine/worker/rss/factory.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/config" 5 | "github.com/rss3-network/node/v2/internal/engine" 6 | ) 7 | 8 | func New(_ *config.Module) (engine.Worker, error) { 9 | // Not implemented 10 | // If the rsshub worker exists, it will be started by default, and there will not be a separate worker instance 11 | return nil, nil 12 | } 13 | -------------------------------------------------------------------------------- /internal/database/model/dataset_farcaster_profile.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Profile struct { 4 | Fid int64 `json:"fid"` // Farcaster ID 5 | Username string `json:"username"` // Farcaster username 6 | CustodyAddress string `json:"custody_address"` // Farcaster custody address 7 | EthAddresses []string `json:"eth_addresses"` // Farcaster account bound evm addresses 8 | } 9 | -------------------------------------------------------------------------------- /docs/path/workers_status.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetWorkersStatus 3 | summary: Get Node Worker Status 4 | description: Retrieve node worker status details. 5 | security: [] 6 | tags: 7 | - Info 8 | responses: 9 | "200": 10 | $ref: "../responses/WorkerInfoResponse.yaml" 11 | "400": 12 | $ref: "../responses/BadRequest.yaml" 13 | "500": 14 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /internal/database/dialer/dialer.go: -------------------------------------------------------------------------------- 1 | package dialer 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rss3-network/node/v2/config" 7 | "github.com/rss3-network/node/v2/internal/database" 8 | "github.com/rss3-network/node/v2/internal/database/dialer/postgres" 9 | ) 10 | 11 | func Dial(ctx context.Context, config *config.Database) (database.Client, error) { 12 | return postgres.Dial(ctx, config.URI, true) 13 | } 14 | -------------------------------------------------------------------------------- /schema/worker/status.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | //go:generate go run --mod=mod github.com/dmarkham/enumer@v1.5.9 --values --type=Status --linecomment --output status_string.go --json --yaml --sql 4 | type Status uint64 5 | 6 | const ( 7 | StatusUnknown Status = iota // Unknown 8 | StatusIndexing // Indexing 9 | StatusReady // Ready 10 | StatusUnhealthy // Unhealthy 11 | ) 12 | -------------------------------------------------------------------------------- /docs/schemas/WorkerConfig.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | endpoint: 3 | $ref: "./ConfigDetail.yaml" 4 | id: 5 | $ref: "./ConfigDetail.yaml" 6 | ipfs_gateways: 7 | $ref: "./ConfigDetail.yaml" 8 | minimum_resource: 9 | $ref: "./MinimumResource.yaml" 10 | network: 11 | $ref: "./ConfigDetail.yaml" 12 | parameters: 13 | $ref: "./Parameters.yaml" 14 | worker: 15 | $ref: "./ConfigDetail.yaml" 16 | type: object 17 | -------------------------------------------------------------------------------- /internal/database/model/dataset_bluesky_profile.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type BlueskyProfile struct { 6 | DID string `json:"did"` 7 | Handle string `json:"handle"` 8 | CreatedAt time.Time `json:"created_at"` 9 | UpdatedAt time.Time `json:"updated_at"` 10 | } 11 | 12 | type QueryBlueskyProfiles struct { 13 | Since *uint64 14 | Limit *int 15 | Cursor *string 16 | Handles []string 17 | } 18 | -------------------------------------------------------------------------------- /docs/path/networks/config.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetNetworksConfig 3 | summary: Get worker config options 4 | description: Retrieve worker config options and descriptions. 5 | security: [] 6 | tags: 7 | - Info 8 | responses: 9 | "200": 10 | $ref: "../../responses/NetworkConfigResponse.yaml" 11 | "400": 12 | $ref: "../../responses/BadRequest.yaml" 13 | "500": 14 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/schemas/Reward.yaml: -------------------------------------------------------------------------------- 1 | description: The reward of node. 2 | properties: 3 | epoch: 4 | description: The epoch of reward. 5 | type: integer 6 | operator_rewards: 7 | description: The operator rewards of reward. 8 | type: string 9 | request_counts: 10 | description: The request counts of reward. 11 | type: string 12 | staking_rewards: 13 | description: The staking rewards of reward. 14 | type: string 15 | type: object 16 | -------------------------------------------------------------------------------- /provider/ethereum/contract/erc165/abi/ERC165.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [ 5 | { 6 | "name": "interfaceID", 7 | "type": "bytes4" 8 | } 9 | ], 10 | "name": "supportsInterface", 11 | "outputs": [ 12 | { 13 | "name": "", 14 | "type": "bool" 15 | } 16 | ], 17 | "payable": false, 18 | "stateMutability": "view", 19 | "type": "function" 20 | } 21 | ] 22 | -------------------------------------------------------------------------------- /internal/stream/provider/provider.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rss3-network/node/v2/config" 7 | "github.com/rss3-network/node/v2/internal/stream" 8 | "github.com/rss3-network/node/v2/internal/stream/provider/kafka" 9 | ) 10 | 11 | const kafkaTopic = "rss3.node.activities" 12 | 13 | func New(ctx context.Context, config *config.Stream) (stream.Client, error) { 14 | return kafka.New(ctx, config.URI, kafkaTopic) 15 | } 16 | -------------------------------------------------------------------------------- /provider/atproto/model.go: -------------------------------------------------------------------------------- 1 | package atproto 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/bluesky-social/indigo/api/bsky" 7 | "github.com/bluesky-social/indigo/atproto/syntax" 8 | ) 9 | 10 | type Message struct { 11 | URI string 12 | Did syntax.DID 13 | Handle string 14 | Collection string 15 | Rkey string 16 | CreatedAt time.Time 17 | 18 | Feed *bsky.FeedPost 19 | Profile *bsky.ActorProfile 20 | RefMessage *Message 21 | } 22 | -------------------------------------------------------------------------------- /internal/engine/data_source.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/rss3-network/protocol-go/schema/network" 8 | ) 9 | 10 | // DataSource is the interface that wraps the basic methods of a data protocol. 11 | type DataSource interface { 12 | Network() network.Network 13 | State() json.RawMessage 14 | Start(ctx context.Context, tasksChan chan<- *Tasks, errorChan chan<- error) 15 | } 16 | 17 | type DataSourceFilter interface{} 18 | -------------------------------------------------------------------------------- /internal/database/model/dataset_mastodon_handle.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type MastodonHandle struct { 6 | Handle string `json:"handle"` 7 | CreatedAt time.Time `json:"created_at"` 8 | UpdatedAt time.Time `json:"updated_at"` 9 | } 10 | 11 | type PaginatedMastodonHandles struct { 12 | Handles []string 13 | TotalCount int64 14 | NextCursor string 15 | } 16 | 17 | type QueryMastodonHandles struct { 18 | Since *uint64 19 | Limit *int 20 | Cursor *string 21 | } 22 | -------------------------------------------------------------------------------- /internal/engine/checkpoint.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | 7 | "github.com/rss3-network/protocol-go/schema/network" 8 | ) 9 | 10 | type Checkpoint struct { 11 | ID string `json:"id"` 12 | Network network.Network `json:"network"` 13 | Worker string `json:"worker"` 14 | State json.RawMessage `json:"state"` 15 | IndexCount int64 `json:"index_count"` 16 | UpdatedAt time.Time `json:"updated_at"` 17 | } 18 | -------------------------------------------------------------------------------- /provider/ethereum/contract/ens/action.go: -------------------------------------------------------------------------------- 1 | package ens 2 | 3 | import "fmt" 4 | 5 | var _ fmt.Stringer = (*UpdateAction)(nil) 6 | 7 | type UpdateAction string 8 | 9 | func (n UpdateAction) String() string { 10 | return string(n) 11 | } 12 | 13 | const ( 14 | FusesSet UpdateAction = "Fuses" 15 | AddressChanged UpdateAction = "Address" 16 | ContentHashChanged UpdateAction = "ContentHash" 17 | NameChanged UpdateAction = "Name" 18 | PubkeyChanged UpdateAction = "Pubkey" 19 | ) 20 | -------------------------------------------------------------------------------- /docs/schemas/WorkerInfo.yaml: -------------------------------------------------------------------------------- 1 | description: The status of the worker. 2 | type: object 3 | allOf: 4 | - properties: 5 | worker_id: 6 | description: The worker ID. 7 | type: string 8 | worker: 9 | $ref: "./Worker.yaml" 10 | network: 11 | $ref: "./ProtocolNetwork.yaml" 12 | tags: 13 | $ref: "./Tags.yaml" 14 | platform: 15 | $ref: "./Platform.yaml" 16 | status: 17 | $ref: "./WorkerStatus.yaml" 18 | - $ref: "./WorkerProgress.yaml" -------------------------------------------------------------------------------- /.run/run.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/responses/FederatedActivitiesResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | description: The response structure for a list of activities. 5 | properties: 6 | data: 7 | description: The list of activities. 8 | items: 9 | $ref: "../schemas/FederatedActivity.yaml" 10 | type: array 11 | meta: 12 | $ref: "../schemas/MetaCursor.yaml" 13 | type: object 14 | required: 15 | - data 16 | description: The request was successful. 17 | -------------------------------------------------------------------------------- /docs/path/ai.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetAgentData 3 | summary: Get Agent Data by Path 4 | description: Retrieve details from the specified path. 5 | tags: 6 | - AI 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../parameters/path_ai.yaml" 11 | responses: 12 | "200": 13 | $ref: "../responses/AIResponse.yaml" 14 | "400": 15 | $ref: "../responses/BadRequest.yaml" 16 | "404": 17 | $ref: "../responses/NotFound.yaml" 18 | "500": 19 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/path/version.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | summary: Get Node Version 3 | description: Retrieve node status details. 4 | tags: 5 | - Info 6 | responses: 7 | "200": 8 | content: 9 | application/json: 10 | schema: 11 | type: object 12 | properties: 13 | data: 14 | $ref: "../schemas/Version.yaml" 15 | 16 | description: Node status details. 17 | "400": 18 | $ref: "../responses/BadRequest.yaml" 19 | "500": 20 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/responses/DecentralizedActivitiesResponse.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | application/json: 3 | schema: 4 | description: The response structure for a list of activities. 5 | properties: 6 | data: 7 | description: The list of activities. 8 | items: 9 | $ref: "../schemas/DecentralizedActivity.yaml" 10 | type: array 11 | meta: 12 | $ref: "../schemas/MetaCursor.yaml" 13 | type: object 14 | required: 15 | - data 16 | description: The request was successful. 17 | -------------------------------------------------------------------------------- /docs/schemas/NetworkConfig.yaml: -------------------------------------------------------------------------------- 1 | description: The worker config details by source. 2 | properties: 3 | decentralized: 4 | items: 5 | $ref: "./NetworkConfigDetail.yaml" 6 | type: array 7 | federated: 8 | items: 9 | $ref: "./NetworkConfigDetail.yaml" 10 | type: array 11 | rss: 12 | properties: 13 | endpoint_configs: 14 | $ref: "./EndpointConfig.yaml" 15 | id: 16 | type: string 17 | worker_configs: 18 | $ref: "./WorkerConfig.yaml" 19 | type: object 20 | type: object 21 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/migration/20241218042140_add_activities_indexes.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | CREATE INDEX IF NOT EXISTS activities_id_platform_index ON public.activities (platform); 4 | CREATE INDEX IF NOT EXISTS activities_id_tag_and_type_index ON public.activities (tag, type); 5 | -- +goose StatementEnd 6 | 7 | -- +goose Down 8 | -- +goose StatementBegin 9 | DROP INDEX IF EXISTS public.activities_id_platform_index; 10 | DROP INDEX IF EXISTS public.activities_id_tag_and_type_index; 11 | -- +goose StatementEnd 12 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.5.0 4 | hooks: 5 | - id: end-of-file-fixer 6 | - id: trailing-whitespace 7 | - repo: https://github.com/golangci/golangci-lint 8 | rev: v1.55.2 9 | hooks: 10 | - id: golangci-lint 11 | - repo: https://github.com/commitizen-tools/commitizen 12 | rev: v2.42.1 13 | hooks: 14 | - id: commitizen 15 | - repo: https://github.com/gitleaks/gitleaks 16 | rev: v8.16.1 17 | hooks: 18 | - id: gitleaks 19 | -------------------------------------------------------------------------------- /docs/path/rss.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetRSS 3 | summary: Get RSS Activity by Path 4 | description: Retrieve details from the specified RSS path. 5 | tags: 6 | - RSS 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../parameters/path_rss.yaml" 11 | responses: 12 | "200": 13 | $ref: "../responses/RSSActivitiesResponse.yaml" 14 | "400": 15 | $ref: "../responses/BadRequest.yaml" 16 | "404": 17 | $ref: "../responses/NotFound.yaml" 18 | "500": 19 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Visual Studio Code 2 | .vscode/* 3 | 4 | 5 | ### JetBrains 6 | .idea/* 7 | 8 | !.idea/icon.svg 9 | 10 | ### Linux 11 | 12 | ### Go template 13 | *.exe 14 | *.exe~ 15 | *.dll 16 | *.so 17 | *.dylib 18 | 19 | # Test binary, built with `go test -c` 20 | *.test 21 | 22 | # Output of the go coverage tool, specifically when used with LiteIDE 23 | *.out 24 | 25 | # Go workspace file 26 | go.work 27 | 28 | ### macOS 29 | .DS_Store 30 | 31 | ### Project 32 | /build/* 33 | 34 | ### Configuration 35 | deploy/config.yaml 36 | 37 | first_start_time.txt 38 | -------------------------------------------------------------------------------- /internal/engine/protocol/farcaster/state.go: -------------------------------------------------------------------------------- 1 | package farcaster 2 | 3 | type State struct { 4 | EventID uint64 `json:"event_id"` // Event ID that has been processed 5 | CastsFid uint64 `json:"casts_fid"` // Casts ID that has been processed in backfill casts 6 | CastsBackfill bool `json:"casts_backfill"` // Casts backfill flag 7 | ReactionsFid uint64 `json:"reactions_fid"` // Reactions ID that has been processed in backfill reactions 8 | ReactionsBackfill bool `json:"reactions_backfill"` // Reactions backfill flag 9 | } 10 | -------------------------------------------------------------------------------- /provider/arweave/contract/momoka/contract.go: -------------------------------------------------------------------------------- 1 | package momoka 2 | 3 | var AddressesLens = []string{ 4 | "llq4QhHA7fQWBKd6V8vzAhK-qy_JulpzlYUEgxAgJ4E", 5 | "6Li0nuSO_w6DLZN4OC7XclIL6uLaeSSkjVX_B2Qn6r8", 6 | } 7 | 8 | var AddressesBundlr = []string{ 9 | "OXcT1sVRSA5eGwt2k6Yuz8-3e3g9WJi5uSE99CWqsBs", 10 | "ZE0N-8P9gXkhtK-07PQu9d8me5tGDxa_i4Mee5RzVYg", 11 | } 12 | 13 | // AddressesSubmitter is a list of addresses that Lens uses to submit transactions to Irys. 14 | var AddressesSubmitter = []string{ 15 | "0xBe29464B9784a0d8956f29630d8bc4D7B5737435", // Lens's default submitter. 16 | } 17 | -------------------------------------------------------------------------------- /docs/path/home.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetNodeOperatorInfo 3 | summary: Get Node Operator Info 4 | description: Retrieve node status details. 5 | security: [] 6 | tags: 7 | - Info 8 | responses: 9 | "200": 10 | content: 11 | # return raw string 12 | text/plain: 13 | schema: 14 | type: string 15 | pattern: "This is an RSS3 Node operated by 0x[0-9a-fA-F]{40}." 16 | description: Node status details. 17 | "400": 18 | $ref: "../responses/BadRequest.yaml" 19 | "500": 20 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/schemas/Parameters.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | api_key: 3 | $ref: "./ConfigDetail.yaml" 4 | authentication: 5 | $ref: "./Authentication.yaml" 6 | block_batch_size: 7 | $ref: "./ConfigDetail.yaml" 8 | block_receipts_batch_size: 9 | $ref: "./ConfigDetail.yaml" 10 | block_start: 11 | $ref: "./ConfigDetail.yaml" 12 | block_target: 13 | $ref: "./ConfigDetail.yaml" 14 | concurrent_block_requests: 15 | $ref: "./ConfigDetail.yaml" 16 | relay_url_list: 17 | $ref: "./ConfigDetail.yaml" 18 | receipts_batch_size: 19 | $ref: "./ConfigDetail.yaml" 20 | type: object 21 | -------------------------------------------------------------------------------- /provider/arweave/bundle/irys/constant.go: -------------------------------------------------------------------------------- 1 | package irys 2 | 3 | //go:generate go run --mod=mod github.com/Khan/genqlient@v0.7.0 4 | 5 | const ( 6 | GatewayMainnet = "https://gateway.irys.xyz" 7 | 8 | EndpointMainnet = "https://arweave.mainnet.irys.xyz/graphql" 9 | EndpointDevnet = "https://arweave.devnet.irys.xyz/graphql" 10 | 11 | // DefaultLimit is the limit on the number of items when obtaining transactions, with a maximum value of 1000. 12 | DefaultLimit = 1000 13 | ) 14 | 15 | // DefaultGateways is the list of default gateways. 16 | var DefaultGateways = []string{ 17 | GatewayMainnet, 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | tags: 9 | - 'v*' 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Set node 20 | uses: actions/setup-node@v4 21 | with: 22 | registry-url: https://registry.npmjs.org/ 23 | node-version: lts/* 24 | 25 | - run: npx changelogithub 26 | env: 27 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | -------------------------------------------------------------------------------- /docs/schemas/Records.yaml: -------------------------------------------------------------------------------- 1 | description: The records of node activities. 2 | properties: 3 | last_heartbeat: 4 | description: The last heartbeat of node. 5 | type: integer 6 | recent_requests: 7 | description: The recent requests of node. 8 | items: 9 | description: The request to the node api. 10 | type: string 11 | type: array 12 | recent_rewards: 13 | description: The recent rewards of node. 14 | items: 15 | $ref: "./Reward.yaml" 16 | type: array 17 | slashed_tokens: 18 | description: The slashed tokens of node. 19 | type: string 20 | type: object 21 | -------------------------------------------------------------------------------- /internal/node/component/component.go: -------------------------------------------------------------------------------- 1 | package component 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/go-playground/validator/v10" 7 | "github.com/labstack/echo/v4" 8 | ) 9 | 10 | type Component interface { 11 | Name() string 12 | InitMeter() error 13 | CollectMetric(ctx context.Context, path, value string) 14 | CollectTrace(ctx context.Context, path, value string) 15 | } 16 | 17 | var _ echo.Validator = (*Validator)(nil) 18 | 19 | type Validator struct { 20 | Validator *validator.Validate 21 | } 22 | 23 | func (v *Validator) Validate(i interface{}) error { 24 | return v.Validator.Struct(i) 25 | } 26 | -------------------------------------------------------------------------------- /docs/schemas/DecentralizedAction.yaml: -------------------------------------------------------------------------------- 1 | description: Represents an individual action within an activity. 2 | properties: 3 | from: 4 | $ref: './DecentralizedAccount.yaml' 5 | metadata: 6 | $ref: "./ProtocolMetadata.yaml" 7 | platform: 8 | $ref: "./DecentralizedPlatform.yaml" 9 | related_urls: 10 | description: A list of URLs related to the action. 11 | items: 12 | type: string 13 | format: uri 14 | type: array 15 | tag: 16 | $ref: "./ProtocolTag.yaml" 17 | to: 18 | $ref: "./DecentralizedAccount.yaml" 19 | type: 20 | $ref: "./ProtocolType.yaml" 21 | type: object 22 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/migration/20240115040941_add_ens_namehash.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | CREATE TABLE IF NOT EXISTS "dataset_ens_namehashes" 4 | ( 5 | "hash" bytea NOT NULL, 6 | "name" text NOT NULL, 7 | 8 | CONSTRAINT "pk_dataset_ens_namehashs" PRIMARY KEY ("hash") 9 | ); 10 | 11 | CREATE INDEX IF NOT EXISTS idx_ensnamehash_name ON dataset_ens_namehashes (name); 12 | -- +goose StatementEnd 13 | 14 | -- +goose Down 15 | -- +goose StatementBegin 16 | DROP INDEX IF EXISTS idx_ensnamehash_name; 17 | DROP TABLE IF EXISTS "dataset_ens_namehashes"; 18 | -- +goose StatementEnd 19 | -------------------------------------------------------------------------------- /internal/engine/protocol/arweave/filter.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/internal/engine" 5 | ) 6 | 7 | var _ engine.DataSourceFilter = (*Filter)(nil) 8 | 9 | type Filter struct { 10 | OwnerAddresses []string `yaml:"owner_addresses"` 11 | 12 | // BundlrOnly is a tag, indicating that only transactions of Bundlr nodes are pulled. 13 | BundlrOnly bool `yaml:"bundlr_only"` 14 | 15 | // BundlrAddresses is a list of addresses that are considered Bundlr nodes. 16 | // If BundlrOnly is true, the field needs to be ignored. 17 | BundlrAddresses []string `yaml:"bundlr_addresses"` 18 | } 19 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/migration/20240922233919_add_mastodon_handles.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | CREATE TABLE IF NOT EXISTS dataset_mastodon_update_handles ( 4 | "handle" text PRIMARY KEY, 5 | "created_at" timestamptz NOT NULL DEFAULT now(), 6 | "updated_at" timestamptz NOT NULL DEFAULT now() 7 | ); 8 | 9 | CREATE INDEX idx_mastodon_update_handles_time_at ON dataset_mastodon_update_handles(updated_at DESC,created_at DESC); 10 | -- +goose StatementEnd 11 | 12 | -- +goose Down 13 | -- +goose StatementBegin 14 | DROP TABLE IF EXISTS dataset_mastodon_update_handles; 15 | -- +goose StatementEnd 16 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - prod 7 | paths-ignore: 8 | - "deploy/**" 9 | pull_request: 10 | paths-ignore: 11 | - "deploy/**" 12 | 13 | jobs: 14 | lint: 15 | name: Lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Setup Go 19 | uses: actions/setup-go@v5 20 | with: 21 | go-version: "1.22.7" 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | - name: GolangCI Lint 25 | uses: golangci/golangci-lint-action@v6 26 | with: 27 | version: v1.55.2 28 | -------------------------------------------------------------------------------- /provider/ethereum/contract/iqwiki/client_test.go: -------------------------------------------------------------------------------- 1 | package iqwiki_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/rss3-network/node/v2/provider/ethereum/contract/iqwiki" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_Client(t *testing.T) { 12 | t.Parallel() 13 | 14 | client, err := iqwiki.NewClient(iqwiki.Endpoint) 15 | 16 | require.NoError(t, err, "build IQ.Wiki client") 17 | 18 | wikiResponse, err := iqwiki.ActivityByWikiIdAndBlock(context.Background(), client, 46938791, "buffer") 19 | 20 | require.NoError(t, err) 21 | 22 | t.Log(wikiResponse.ActivityByWikiIdAndBlock.Ipfs) 23 | } 24 | -------------------------------------------------------------------------------- /provider/ethereum/contract/matters/contract.go: -------------------------------------------------------------------------------- 1 | package matters 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // Wiki 9 | // https://polygonscan.com/address/0x5edebbdae7B5C79a69AaCF7873796bb1Ec664DB8 10 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi abi/curation.abi --pkg matters --type Matters --out contract_curation.go 11 | 12 | var ( 13 | AddressCuration = common.HexToAddress("0x5edebbdae7B5C79a69AaCF7873796bb1Ec664DB8") 14 | 15 | EventCuration = contract.EventHash("Curation(address,address,address,string,uint256)") 16 | ) 17 | -------------------------------------------------------------------------------- /internal/node/component/rss/option.go: -------------------------------------------------------------------------------- 1 | package rss 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/config" 5 | ) 6 | 7 | type Option struct { 8 | Authentication OptionAuthentication `json:"authentication" mapstructure:"authentication"` 9 | } 10 | 11 | type OptionAuthentication struct { 12 | AccessKey string `json:"access_key" mapstructure:"access_key"` 13 | } 14 | 15 | func NewOption(options *config.Parameters) (*Option, error) { 16 | var instance Option 17 | 18 | if options == nil { 19 | return &instance, nil 20 | } 21 | 22 | if err := options.Decode(&instance); err != nil { 23 | return nil, err 24 | } 25 | 26 | return &instance, nil 27 | } 28 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | target-branch: main 8 | open-pull-requests-limit: 0 9 | ignore: 10 | - dependency-name: "github.com/ethereum/go-ethereum" 11 | - dependency-name: "github.com/rss3-network/protocol-go" 12 | - package-ecosystem: github-actions 13 | directory: / 14 | schedule: 15 | interval: weekly 16 | target-branch: main 17 | open-pull-requests-limit: 0 18 | - package-ecosystem: docker 19 | directory: / 20 | schedule: 21 | interval: weekly 22 | target-branch: main 23 | open-pull-requests-limit: 0 24 | -------------------------------------------------------------------------------- /docs/schemas/RSSAction.yaml: -------------------------------------------------------------------------------- 1 | description: Represents an individual action within an activity. 2 | properties: 3 | tag: 4 | allOf: 5 | - $ref: "./ProtocolTag.yaml" 6 | - example: rss 7 | type: 8 | $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/type/RSSType.yaml" 9 | platform: 10 | $ref: "./RSSPlatform.yaml" 11 | from: 12 | $ref: "./RSSAccount.yaml" 13 | to: 14 | $ref: "./RSSAccount.yaml" 15 | metadata: 16 | $ref: "./RSSMetadata.yaml" 17 | related_urls: 18 | description: A list of URLs related to the action. 19 | items: 20 | type: string 21 | format: uri 22 | type: array 23 | type: object 24 | -------------------------------------------------------------------------------- /provider/ethereum/contract/iqwiki/contract.go: -------------------------------------------------------------------------------- 1 | package iqwiki 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // Wiki 9 | // https://polygonscan.com/address/0xb8aa8cabfba7ee3ccb218a9969aef86dff3b9d2d 10 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/Wiki.abi --pkg iqwiki --type IqWiki --out contract_wiki.go 11 | 12 | var ( 13 | AddressWiki = common.HexToAddress("0xb8aA8CabfBa7eE3ccb218a9969AEF86DFf3b9d2D") 14 | AddressSig = common.HexToAddress("0x191a41c307373211d08613b68df4031977589069") 15 | 16 | EventPosted = contract.EventHash("Posted(address,string)") 17 | ) 18 | -------------------------------------------------------------------------------- /docs/path/federated/tx.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetFederatedTxID 3 | summary: Get Activity by ID 4 | description: Retrieve details for the specified activity ID. 5 | tags: 6 | - Federated 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_activity_id.yaml" 11 | - $ref: "../../parameters/query_action_limit.yaml" 12 | - $ref: "../../parameters/query_action_page.yaml" 13 | responses: 14 | "200": 15 | $ref: "../../responses/FederatedActivityResponse.yaml" 16 | "400": 17 | $ref: "../../responses/BadRequest.yaml" 18 | "404": 19 | $ref: "../../responses/NotFound.yaml" 20 | "500": 21 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /internal/constant/version.go: -------------------------------------------------------------------------------- 1 | package constant 2 | 3 | // FIXME: should this be mvoed to config/parameter.go? 4 | 5 | import "fmt" 6 | 7 | const Name = "node" 8 | 9 | // The Go compiler will set these variables via ldflags. 10 | var ( 11 | Version string 12 | Commit string 13 | ) 14 | 15 | func BuildVersion() string { 16 | if Version == "" { 17 | Version = "0.0.0" 18 | } 19 | 20 | if Commit == "" { 21 | Commit = "000000" 22 | } 23 | 24 | return fmt.Sprintf("%s (%s)", Version, Commit) 25 | } 26 | 27 | func BuildVersionDetail() (string, string) { 28 | if Version == "" { 29 | Version = "0.0.0" 30 | } 31 | 32 | if Commit == "" { 33 | Commit = "000000" 34 | } 35 | 36 | return Version, Commit 37 | } 38 | -------------------------------------------------------------------------------- /provider/ethereum/contract/iqwiki/client.go: -------------------------------------------------------------------------------- 1 | package iqwiki 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/Khan/genqlient/graphql" 7 | ) 8 | 9 | //go:generate go run --mod=mod github.com/Khan/genqlient 10 | 11 | const Endpoint = "https://graph.everipedia.org/graphql" 12 | 13 | var _ graphql.Doer = (*client)(nil) 14 | 15 | type client struct { 16 | httpClient *http.Client 17 | } 18 | 19 | func (c *client) Do(request *http.Request) (*http.Response, error) { 20 | return c.httpClient.Do(request) 21 | } 22 | 23 | func NewClient(endpoint string) (graphql.Client, error) { 24 | instance := client{ 25 | httpClient: http.DefaultClient, 26 | } 27 | 28 | return graphql.NewClient(endpoint, &instance), nil 29 | } 30 | -------------------------------------------------------------------------------- /docs/path/decentralized/tx.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetDecentralizedTxID 3 | summary: Get Activity by ID 4 | description: Retrieve details for the specified activity ID. 5 | tags: [Decentralized] 6 | security: 7 | - bearerAuth: [] 8 | parameters: 9 | - $ref: "../../parameters/path_activity_id.yaml" 10 | - $ref: "../../parameters/query_action_limit.yaml" 11 | - $ref: "../../parameters/query_action_page.yaml" 12 | responses: 13 | '200': 14 | $ref: "../../responses/DecentralizedActivityResponse.yaml" 15 | '400': 16 | $ref: "../../responses/BadRequest.yaml" 17 | '404': 18 | $ref: "../../responses/NotFound.yaml" 19 | '500': 20 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/schemas/FederatedAction.yaml: -------------------------------------------------------------------------------- 1 | description: Represents an individual action within an activity. 2 | properties: 3 | tag: 4 | allOf: 5 | - $ref: "./ProtocolTag.yaml" 6 | - example: social 7 | type: 8 | $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/type/Social.yaml" 9 | platform: 10 | $ref: "./FederatedPlatform.yaml" 11 | from: 12 | $ref: "./FederatedAccount.yaml" 13 | to: 14 | $ref: "./FederatedAccount.yaml" 15 | metadata: 16 | $ref: "./FederatedMetadata.yaml" 17 | related_urls: 18 | description: A list of URLs related to the action. 19 | items: 20 | type: string 21 | format: uri 22 | type: array 23 | type: object 24 | -------------------------------------------------------------------------------- /provider/ethereum/contract/zerion/contract.go: -------------------------------------------------------------------------------- 1 | package zerion 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./Router.abi --pkg zerion --type Router --out router.go 9 | var ( 10 | AddressRouter = common.HexToAddress("0xd7F1Dd5D49206349CaE8b585fcB0Ce3D96f1696F") 11 | AddressNativeToken = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") 12 | 13 | EventHashExecuted = contract.EventHash("Executed(address,uint256,uint256,address,uint256,uint256,uint256,uint256,(uint8,(uint256,address),(uint256,address),address,address,bytes),address)") 14 | ) 15 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/migration/20241210031220_add_bluesky_profiles.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | CREATE TABLE IF NOT EXISTS dataset_bluesky_profiles 4 | ( 5 | "did" text PRIMARY KEY, 6 | "handle" text, 7 | "created_at" timestamptz NOT NULL DEFAULT now(), 8 | "updated_at" timestamptz NOT NULL DEFAULT now() 9 | ); 10 | 11 | CREATE INDEX idx_dataset_bluesky_profiles_cursor ON dataset_bluesky_profiles (updated_at DESC, created_at DESC); 12 | 13 | CREATE INDEX idx_dataset_bluesky_profiles_handle ON dataset_bluesky_profiles (handle); 14 | -- +goose StatementEnd 15 | 16 | -- +goose Down 17 | -- +goose StatementBegin 18 | DROP TABLE IF EXISTS dataset_bluesky_profiles; 19 | -- +goose StatementEnd 20 | -------------------------------------------------------------------------------- /docs/schemas/FederatedMetadata.yaml: -------------------------------------------------------------------------------- 1 | description: Additional metadata related to the action. 2 | type: object 3 | allOf: 4 | - $ref: "./ProtocolMetadata.yaml" 5 | example: 6 | handle: "@seachdamh@101010.pl" 7 | body: "Some text" 8 | publication_id: 113550154261051135 9 | tags: ["@LukaszHorodecki@pol.social"] 10 | author_url: https://101010.pl/users/seachdamh 11 | timestamp: 1732637851 12 | target: 13 | handle: "@LukaszHorodecki@pol.social" 14 | body: Some text 15 | publication_id: 113549630375809974 16 | tags: 17 | - "#pc" 18 | - "#obudowa" 19 | author_url: https://pol.social/users/LukaszHorodecki 20 | timestamp: 1732629858 21 | target_url: https://pol.social/users/LukaszHorodecki/statuses/113549630375809974 -------------------------------------------------------------------------------- /provider/ethereum/contract/erc20/contract.go: -------------------------------------------------------------------------------- 1 | package erc20 2 | 3 | import "github.com/rss3-network/node/v2/provider/ethereum/contract" 4 | 5 | // https://eips.ethereum.org/EIPS/eip-20 6 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/ERC20.abi --pkg erc20 --type ERC20 --out contract_erc20.go 7 | 8 | var ( 9 | MethodIDTransfer = contract.MethodID("transfer(address,uint256)") 10 | MethodIDTransferFrom = contract.MethodID("transferFrom(address,address,uint256)") 11 | MethodIDApprove = contract.MethodID("approve(address,uint256)") 12 | 13 | EventHashTransfer = contract.EventHash("Transfer(address,address,uint256)") 14 | EventHashApproval = contract.EventHash("Approval(address,address,uint256)") 15 | ) 16 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/table/dataset_ens_namehash.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/internal/database/model" 6 | ) 7 | 8 | type DatasetENSNamehash struct { 9 | Hash common.Hash `gorm:"column:hash;primary_key"` 10 | Name string `gorm:"column:name;index:idx_ensnamehash_name"` 11 | } 12 | 13 | func (d *DatasetENSNamehash) Import(ensNamehash *model.ENSNamehash) (err error) { 14 | d.Hash = ensNamehash.Hash 15 | d.Name = ensNamehash.Name 16 | 17 | return nil 18 | } 19 | 20 | func (d *DatasetENSNamehash) Export() (*model.ENSNamehash, error) { 21 | profile := model.ENSNamehash{ 22 | Hash: d.Hash, 23 | Name: d.Name, 24 | } 25 | 26 | return &profile, nil 27 | } 28 | -------------------------------------------------------------------------------- /provider/arweave/bundle/irys/operation_test.go: -------------------------------------------------------------------------------- 1 | package irys_test 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "testing" 7 | 8 | "github.com/Khan/genqlient/graphql" 9 | "github.com/rss3-network/node/v2/provider/arweave/bundle/irys" 10 | "github.com/rss3-network/node/v2/provider/arweave/contract/momoka" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestQueryTransactions(t *testing.T) { 15 | t.Parallel() 16 | 17 | graphqlClient := graphql.NewClient(irys.EndpointMainnet, http.DefaultClient) 18 | 19 | transactions, err := irys.Transactions(context.Background(), graphqlClient, momoka.AddressesSubmitter, "", irys.DefaultLimit) 20 | require.NoError(t, err) 21 | 22 | require.Len(t, transactions.Transactions.Edges, irys.DefaultLimit) 23 | } 24 | -------------------------------------------------------------------------------- /provider/ethereum/contract/cow/contract.go: -------------------------------------------------------------------------------- 1 | package cow 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // GPv2Settlement 9 | // https://etherscan.io/address/0x9008D19f58AAbD9eD0D60971565AA8510560ab41 10 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/GPv2Settlement.abi --pkg cow --type Settlement --out contract_settlement.go 11 | 12 | var ( 13 | AddressSettlement = common.HexToAddress("0x9008D19f58AAbD9eD0D60971565AA8510560ab41") 14 | AddressETH = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") 15 | 16 | EventHashSettlementTrade = contract.EventHash("Trade(address,address,address,uint256,uint256,uint256,bytes)") 17 | ) 18 | -------------------------------------------------------------------------------- /provider/arweave/utils.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/base64" 6 | ) 7 | 8 | // PublicKeyToAddress returns the arweave address of the owner. 9 | func PublicKeyToAddress(publicKey string) (string, error) { 10 | by, err := Base64Decode(publicKey) 11 | if err != nil { 12 | return "", err 13 | } 14 | 15 | addr := sha256.Sum256(by) 16 | 17 | return Base64Encode(addr[:]), nil 18 | } 19 | 20 | // Base64Encode returns the base64 encoding of data. 21 | func Base64Encode(data []byte) string { 22 | return base64.RawURLEncoding.EncodeToString(data) 23 | } 24 | 25 | // Base64Decode returns the bytes represented by the base64 string. 26 | func Base64Decode(data string) ([]byte, error) { 27 | return base64.RawURLEncoding.DecodeString(data) 28 | } 29 | -------------------------------------------------------------------------------- /provider/ethereum/contract/iqwiki/operation/activities.graphql: -------------------------------------------------------------------------------- 1 | query ActivityByWikiIdAndBlock($block:Int!,$wikiId:String) { 2 | activityByWikiIdAndBlock(block: $block, wikiId: $wikiId) { 3 | id 4 | wikiId 5 | block 6 | type 7 | datetime 8 | ipfs 9 | user { 10 | id 11 | profile { 12 | username 13 | bio 14 | } 15 | } 16 | content { 17 | id 18 | title 19 | content 20 | summary 21 | categories { 22 | title 23 | } 24 | images { 25 | id 26 | } 27 | tags { 28 | id 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docs/schemas/DecentralizedWorker.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | enum: 3 | - aave 4 | - aavegotchi 5 | - arbitrum 6 | - base 7 | - benddao 8 | - core 9 | - cow 10 | - crossbell 11 | - curve 12 | - ens 13 | - highlight 14 | - iqwiki 15 | - kiwistand 16 | - lens 17 | - lido 18 | - linea 19 | - linear 20 | - looksrare 21 | - matters 22 | - mirror 23 | - momoka 24 | - nearsocial 25 | - nouns 26 | - 1inch 27 | - opensea 28 | - optimism 29 | - paragraph 30 | - paraswap 31 | - polymarket 32 | - rainbow 33 | - rss3 34 | - savm 35 | - stargate 36 | - uniswap 37 | - vsl 38 | - zerion 39 | x-go-type: decentralized.Worker 40 | x-go-type-skip-optional-pointer: true 41 | x-go-type-import: 42 | path: github.com/rss3-network/node/v2/schema/worker/decentralized 43 | -------------------------------------------------------------------------------- /docs/path/federated/accounts.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | operationId: PostFederatedAccounts 3 | summary: Batch Get Accounts Activities 4 | description: Retrieve a batch of activities associated with multiple specified accounts in the federated system. You can use various query parameters to filter and paginate the results, including limits on the number of activities and actions, timestamps, success status, direction, and more. 5 | tags: 6 | - Federated 7 | security: 8 | - bearerAuth: [] 9 | requestBody: 10 | $ref: "../../requestBody/BatchGetFederatedAccountsActivities.yaml" 11 | responses: 12 | "200": 13 | $ref: "../../responses/FederatedActivitiesResponse.yaml" 14 | "400": 15 | $ref: "../../responses/BadRequest.yaml" 16 | "500": 17 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/schemas/DecentralizedPlatform.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | enum: 3 | - Unknown 4 | - 1inch 5 | - AAVE 6 | - Aavegotchi 7 | - Arbitrum 8 | - Base 9 | - BendDAO 10 | - Cow 11 | - Crossbell 12 | - Curve 13 | - ENS 14 | - Farcaster 15 | - Highlight 16 | - IQWiki 17 | - KiwiStand 18 | - Lens 19 | - Lido 20 | - Linea 21 | - LiNEAR 22 | - LooksRare 23 | - Matters 24 | - Mirror 25 | - NearSocial 26 | - Nouns 27 | - OpenSea 28 | - Optimism 29 | - Paragraph 30 | - Paraswap 31 | - Polymarket 32 | - RSS3 33 | - Rainbow 34 | - SAVM 35 | - Stargate 36 | - Uniswap 37 | - VSL 38 | - Zerion 39 | x-go-type: decentralized.Platform 40 | x-go-type-skip-optional-pointer: true 41 | x-go-type-import: 42 | path: github.com/rss3-network/node/v2/schema/worker/decentralized 43 | -------------------------------------------------------------------------------- /docs/path/decentralized/accounts.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | operationId: PostDecentralizedAccounts 3 | summary: Batch Get Accounts Activities 4 | description: Retrieve a batch of activities associated with multiple specified accounts in the decentralized system. You can use various query parameters to filter and paginate the results, including limits on the number of activities and actions, timestamps, success status, direction, and more. 5 | tags: 6 | - Decentralized 7 | security: 8 | - bearerAuth: [] 9 | requestBody: 10 | $ref: "../../requestBody/BatchGetDecentralizedAccountsActivities.yaml" 11 | responses: 12 | '200': 13 | $ref: "../../responses/DecentralizedActivitiesResponse.yaml" 14 | '400': 15 | $ref: "../../responses/BadRequest.yaml" 16 | '500': 17 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/tool.go: -------------------------------------------------------------------------------- 1 | package docs 2 | 3 | //go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml api.yaml 4 | 5 | import ( 6 | "fmt" 7 | "reflect" 8 | 9 | "github.com/labstack/echo/v4" 10 | ) 11 | 12 | func BindPath(ctx echo.Context, paramName string, dest any) error { 13 | // Everything comes in by pointer, dereference it 14 | v := reflect.Indirect(reflect.ValueOf(dest)) 15 | 16 | // This is the basic type of the destination object. 17 | t := v.Type() 18 | 19 | if t.Kind() == reflect.String { 20 | return echo.PathParamsBinder(ctx).String(paramName, dest.(*string)).BindError() 21 | } else if bu, ok := dest.(echo.BindUnmarshaler); ok { 22 | return echo.PathParamsBinder(ctx).BindUnmarshaler(paramName, bu).BindError() 23 | } 24 | 25 | return fmt.Errorf("unsupported type %T", t.Kind()) 26 | } 27 | -------------------------------------------------------------------------------- /docs/path/decentralized/metadata.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | operationId: PostDecentralizedMetadata 3 | summary: Batch Get Activities By Metadata 4 | description: Retrieve a batch of activities associated with multiple specified metadata in the decentralized system. You can use various query parameters to filter and paginate the results, including limits on the number of activities and actions, timestamps, success status, direction, and more. 5 | tags: 6 | - Decentralized 7 | security: 8 | - bearerAuth: [ ] 9 | requestBody: 10 | $ref: "../../requestBody/BatchGetDecentralizedMetadataActivities.yaml" 11 | responses: 12 | '200': 13 | $ref: "../../responses/DecentralizedActivitiesResponse.yaml" 14 | '400': 15 | $ref: "../../responses/BadRequest.yaml" 16 | '500': 17 | $ref: "../../responses/InternalError.yaml" 18 | -------------------------------------------------------------------------------- /provider/arweave/type_transaction.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // Transaction represents a transaction on the Arweave network. 8 | type Transaction struct { 9 | Format int `json:"format"` 10 | ID string `json:"id"` 11 | Owner string `json:"owner"` 12 | Tags []Tag `json:"tags"` 13 | Target string `json:"target"` 14 | Quantity string `json:"quantity"` 15 | Data string `json:"data"` 16 | DataReader io.Reader `json:"-"` 17 | DataSize string `json:"data_size"` 18 | DataRoot string `json:"data_root"` 19 | Reward string `json:"reward"` 20 | Signature string `json:"signature"` 21 | } 22 | 23 | // Tag represents a tag on the Arweave network. 24 | type Tag struct { 25 | Name string `json:"name" avro:"name"` 26 | Value string `json:"value" avro:"value"` 27 | } 28 | -------------------------------------------------------------------------------- /docs/path/activity_count.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetActivityCount 3 | summary: Get Node Activity Count 4 | description: Retrieve node worker status details. 5 | security: [] 6 | tags: 7 | - Info 8 | responses: 9 | "200": 10 | description: Activity count retrieved successfully. 11 | content: 12 | application/json: 13 | schema: 14 | type: object 15 | properties: 16 | count: 17 | type: integer 18 | description: The number of activities. 19 | example: 1242092608 20 | last_updated: 21 | type: string 22 | format: date-time 23 | description: The last time the activity count was updated. 24 | "400": 25 | $ref: "../responses/BadRequest.yaml" 26 | "500": 27 | $ref: "../responses/InternalError.yaml" -------------------------------------------------------------------------------- /provider/arweave/bundle/irys/operation/transactions.graphql: -------------------------------------------------------------------------------- 1 | query Transactions($owners: [String!], $after: String, $first: Int) { 2 | transactions(owners: $owners, after: $after, first: $first, order: ASC) { 3 | edges { 4 | cursor 5 | node { 6 | id 7 | token 8 | address 9 | tags { 10 | name 11 | value 12 | } 13 | signature 14 | timestamp 15 | receipt { 16 | version 17 | signature 18 | timestamp 19 | deadlineHeight 20 | } 21 | size 22 | fee 23 | } 24 | } 25 | pageInfo { 26 | endCursor 27 | hasNextPage 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /provider/arweave/bundle/transaction.go: -------------------------------------------------------------------------------- 1 | package bundle 2 | 3 | import "io" 4 | 5 | type Transaction struct { 6 | Header Header 7 | DataItems []DataItem 8 | } 9 | 10 | type Header struct { 11 | Numbers uint32 12 | DataItemInfos []DataItemInfo 13 | } 14 | 15 | type DataItemInfo struct { 16 | Size uint32 17 | ID string 18 | } 19 | 20 | var _ io.Reader = (*DataItem)(nil) 21 | 22 | type DataItem struct { 23 | SignatureType uint16 24 | Signature string 25 | Owner string 26 | Target string 27 | Anchor string 28 | TagsNumber uint16 29 | TagsBytes uint16 30 | Tags []Tag 31 | Data []byte 32 | 33 | dataReader io.Reader 34 | } 35 | 36 | func (d *DataItem) Read(buffer []byte) (int, error) { 37 | return d.dataReader.Read(buffer) 38 | } 39 | 40 | type Tag struct { 41 | Name []byte `avro:"name"` 42 | Value []byte `avro:"value"` 43 | } 44 | -------------------------------------------------------------------------------- /internal/node/middlewarex/middlewarex_test.go: -------------------------------------------------------------------------------- 1 | package middlewarex_test 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | 8 | "github.com/labstack/echo/v4" 9 | "github.com/rss3-network/node/v2/internal/node/middlewarex" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestPathParameterDecodeMiddleware_DecodesValidPathParameters(t *testing.T) { 14 | t.Parallel() 15 | 16 | e := echo.New() 17 | req := httptest.NewRequest(http.MethodGet, "/test/36kr%2Fnewsflashes+", nil) 18 | rec := httptest.NewRecorder() 19 | c := e.NewContext(req, rec) 20 | c.SetPath("/test/:path") 21 | c.SetParamNames("path") 22 | c.SetParamValues("36kr%2Fnewsflashes+") 23 | 24 | handler := middlewarex.DecodePathParamsMiddleware(func(c echo.Context) error { 25 | assert.Equal(t, "36kr/newsflashes+", c.Param("path")) 26 | return nil 27 | }) 28 | 29 | err := handler(c) 30 | assert.NoError(t, err) 31 | } 32 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/table/dataset_mirror_post.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/internal/engine/worker/decentralized/contract/mirror/model" 5 | ) 6 | 7 | // DatasetMirrorPost represents a mirror post for revise logic check. 8 | type DatasetMirrorPost struct { 9 | ID string `gorm:"column:id;primary_key"` 10 | OriginContentDigest string `gorm:"column:origin_content_digest;index:idx_origin_content_digest"` 11 | } 12 | 13 | func (p *DatasetMirrorPost) Import(post *model.DatasetMirrorPost) (err error) { 14 | p.ID = post.TransactionID 15 | p.OriginContentDigest = post.OriginContentDigest 16 | 17 | return nil 18 | } 19 | 20 | func (p *DatasetMirrorPost) Export() (*model.DatasetMirrorPost, error) { 21 | post := model.DatasetMirrorPost{ 22 | TransactionID: p.ID, 23 | OriginContentDigest: p.OriginContentDigest, 24 | } 25 | 26 | return &post, nil 27 | } 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/rss3-network/go-image/go-builder:main-230cb74 AS base 2 | 3 | WORKDIR /root/node 4 | 5 | RUN --mount=type=cache,target=/go/pkg/mod/ \ 6 | --mount=type=bind,source=go.sum,target=go.sum \ 7 | --mount=type=bind,source=go.mod,target=go.mod \ 8 | go mod download -x 9 | 10 | RUN wget -O etherface.tar.gz https://storage.googleapis.com/rss3-etherface/etherface.tar.gz && \ 11 | tar -xzf etherface.tar.gz && \ 12 | rm etherface.tar.gz 13 | 14 | COPY . . 15 | 16 | FROM base AS builder 17 | 18 | ENV CGO_ENABLED=0 19 | RUN --mount=type=cache,target=/go/pkg/mod/ \ 20 | make build 21 | 22 | FROM ghcr.io/rss3-network/go-image/go-builder:main-230cb74 AS runner 23 | 24 | WORKDIR /root/node 25 | 26 | COPY --from=builder /root/node/etherface /root/node/etherface 27 | 28 | COPY --from=builder /root/node/build/node . 29 | COPY deploy/default/config.default.yaml /etc/rss3/node/config.yaml 30 | 31 | ENTRYPOINT ["./node"] 32 | -------------------------------------------------------------------------------- /internal/engine/worker/federated/factory.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/redis/rueidis" 7 | "github.com/rss3-network/node/v2/config" 8 | "github.com/rss3-network/node/v2/internal/database" 9 | "github.com/rss3-network/node/v2/internal/engine" 10 | "github.com/rss3-network/node/v2/internal/engine/worker/federated/bluesky" 11 | "github.com/rss3-network/node/v2/internal/engine/worker/federated/mastodon" 12 | "github.com/rss3-network/node/v2/schema/worker/federated" 13 | ) 14 | 15 | func New(config *config.Module, databaseClient database.Client, redisClient rueidis.Client) (engine.Worker, error) { 16 | switch config.Worker.(federated.Worker) { 17 | case federated.Mastodon: 18 | return mastodon.NewWorker(databaseClient, redisClient) 19 | case federated.Bluesky: 20 | return bluesky.NewWorker(databaseClient) 21 | default: 22 | return nil, fmt.Errorf("[federated/factory.go] unsupported worker %s", config.Worker) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/validator.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/samber/lo" 7 | ) 8 | 9 | // HasOneWorker Check if there is at least one worker deployed 10 | func HasOneWorker(config *File) error { 11 | if (CalculateWorkerCount(config)) == 0 { 12 | return fmt.Errorf("at least one worker must be deployed") 13 | } 14 | 15 | return nil 16 | } 17 | 18 | // IsRSSOrAIComponentOnly Check if the configuration contains an RSS or AI component only 19 | func IsRSSOrAIComponentOnly(config *File) bool { 20 | return len(config.Component.Decentralized) == 0 && len(config.Component.Federated) == 0 && 21 | (config.Component.RSS != nil || config.Component.AI != nil) 22 | } 23 | 24 | // CalculateWorkerCount returns the number of workers deployed 25 | func CalculateWorkerCount(config *File) int { 26 | return len(config.Component.Decentralized) + lo.Ternary(config.Component.RSS != nil, 1, 0) + len(config.Component.Federated) + lo.Ternary(config.Component.AI != nil, 1, 0) 27 | } 28 | -------------------------------------------------------------------------------- /schema/worker/rss/platform.go: -------------------------------------------------------------------------------- 1 | package rss 2 | 3 | import "github.com/labstack/echo/v4" 4 | 5 | //go:generate go run --mod=mod github.com/dmarkham/enumer@v1.5.9 --values --type=Platform --linecomment --output platform_string.go --json --yaml --sql 6 | //go:generate go run --mod=mod github.com/rss3-network/enum-schema@v0.1.6 --type=Platform --linecomment --output ../../../docs/schemas/RSSPlatform.yaml -t ../../../docs/schemas/tmpl/RSS.yaml.tmpl 7 | type Platform uint64 8 | 9 | const ( 10 | PlatformUnknown Platform = iota // Unknown 11 | PlatformRSSHub // RSSHub 12 | ) 13 | 14 | var _ echo.BindUnmarshaler = (*Platform)(nil) 15 | 16 | func (p *Platform) UnmarshalParam(param string) error { 17 | platform, err := PlatformString(param) 18 | if err != nil { 19 | return err 20 | } 21 | 22 | *p = platform 23 | 24 | return nil 25 | } 26 | 27 | // ToPlatformMap is a map of worker to platform 28 | var ToPlatformMap = map[Worker]Platform{ 29 | Core: PlatformRSSHub, 30 | } 31 | -------------------------------------------------------------------------------- /docs/schemas/RSSMetadata.yaml: -------------------------------------------------------------------------------- 1 | description: Additional metadata related to the action. 2 | type: object 3 | allOf: 4 | - $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/metadata/RSS.yaml" 5 | example: 6 | authors: 7 | - name: Emma Wynne 8 | description: '

In short:

Nicheliving customer Cindy Richardson 9 | says she is overwhelmed with costs, including rent, mortgage and rates 10 | due to the long delays completing her house.

She has applied to 11 | access her superannuation on hardship grounds but was rejected.

What''s 12 | next?

WA Commerce Minister Sue Ellery is in talks with the company 13 | about resolving the long completion delays many customers are facing.

14 | 15 | ' 16 | pub_date: '2024-07-02T04:13:38.000Z' 17 | title: Cindy was supposed to be living in a new home by now. Instead she's 18 | facing bankruptcy -------------------------------------------------------------------------------- /provider/ethereum/contract/ens/erc1577/contenthash.go: -------------------------------------------------------------------------------- 1 | package erc1577 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ipfs/go-cid" 7 | "github.com/multiformats/go-multicodec" 8 | "github.com/multiformats/go-varint" 9 | ) 10 | 11 | func Parse(contentHash []byte) (path string, err error) { 12 | contentCode, cursor, err := varint.FromUvarint(contentHash) 13 | if err != nil { 14 | return "", fmt.Errorf("invaild content hash: %w", err) 15 | } 16 | 17 | var protocol string 18 | 19 | switch contentCode := multicodec.Code(contentCode); contentCode { 20 | case multicodec.Ipfs: 21 | protocol = "ipfs" 22 | case multicodec.Ipns: 23 | protocol = "ipns" 24 | default: 25 | return "", fmt.Errorf("unsupported content code: %d", contentCode) 26 | } 27 | 28 | _, contentCID, err := cid.CidFromBytes(contentHash[cursor:]) 29 | if err != nil { 30 | return "", fmt.Errorf("invalid content hash: %w", err) 31 | } 32 | 33 | return fmt.Sprintf("/%s/%s", protocol, contentCID.String()), nil 34 | } 35 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 10m 3 | 4 | linters: 5 | enable: 6 | - asasalint 7 | - asciicheck 8 | - bodyclose 9 | - durationcheck 10 | - errcheck 11 | - errorlint 12 | - gci 13 | - gocognit 14 | - gocritic 15 | - gocyclo 16 | - gosec 17 | - govet 18 | - ineffassign 19 | - makezero 20 | - nakedret 21 | - noctx 22 | - paralleltest 23 | - prealloc 24 | - predeclared 25 | - reassign 26 | - revive 27 | - staticcheck 28 | - stylecheck 29 | - unconvert 30 | - unparam 31 | - unused 32 | - whitespace 33 | - wsl 34 | 35 | issues: 36 | max-issues-per-linter: 0 # Unlimited 37 | max-same-issues: 0 # Unlimited 38 | 39 | linters-settings: 40 | govet: 41 | enable-all: true 42 | disable: 43 | - shadow 44 | - fieldalignment 45 | gocognit: 46 | min-complexity: 30 47 | gocyclo: 48 | min-complexity: 30 49 | gocritic: 50 | disabled-tags: ["opinionated", "experimental"] -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/linear/schema.go: -------------------------------------------------------------------------------- 1 | package linear 2 | 3 | type FunctionCallArgs struct { 4 | ReceiverID string `json:"receiver_id"` 5 | Amount string `json:"amount"` 6 | Msg string `json:"msg"` 7 | } 8 | 9 | type Msg struct { 10 | Force int64 `json:"force"` 11 | Actions []Action `json:"actions"` 12 | } 13 | 14 | type Action struct { 15 | PoolID int64 `json:"pool_id"` 16 | TokenIn string `json:"token_in"` 17 | TokenOut string `json:"token_out"` 18 | AmountIn string `json:"amount_in,omitempty"` 19 | MinAmountOut string `json:"min_amount_out"` 20 | } 21 | 22 | type Event struct { 23 | Standard string `json:"standard"` 24 | Version string `json:"version"` 25 | Event string `json:"event"` 26 | Data []Data `json:"data"` 27 | TokenAddress string `json:"token_address"` 28 | } 29 | 30 | type Data struct { 31 | OldOwnerID string `json:"old_owner_id"` 32 | NewOwnerID string `json:"new_owner_id"` 33 | Amount string `json:"amount"` 34 | } 35 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/table/dataset_mastodon_update_handle.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/rss3-network/node/v2/internal/database/model" 7 | ) 8 | 9 | type DatasetMastodonUpdateHandle struct { 10 | Handle string `gorm:"column:handle;primaryKey"` 11 | CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` 12 | UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` 13 | } 14 | 15 | func (d *DatasetMastodonUpdateHandle) Import(handle *model.MastodonHandle) error { 16 | d.Handle = handle.Handle 17 | d.UpdatedAt = handle.UpdatedAt 18 | d.CreatedAt = handle.CreatedAt 19 | 20 | return nil 21 | } 22 | 23 | func (d *DatasetMastodonUpdateHandle) Export() (*model.MastodonHandle, error) { 24 | handle := model.MastodonHandle{ 25 | Handle: d.Handle, 26 | UpdatedAt: d.UpdatedAt, 27 | CreatedAt: d.CreatedAt, 28 | } 29 | 30 | return &handle, nil 31 | } 32 | 33 | func (DatasetMastodonUpdateHandle) TableName() string { 34 | return "dataset_mastodon_update_handles" 35 | } 36 | -------------------------------------------------------------------------------- /provider/ethereum/contract/erc721/contract.go: -------------------------------------------------------------------------------- 1 | package erc721 2 | 3 | import "github.com/rss3-network/node/v2/provider/ethereum/contract" 4 | 5 | // https://eips.ethereum.org/EIPS/eip-721 6 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/ERC721.abi --pkg erc721 --type ERC721 --out contract_erc721.go 7 | 8 | var ( 9 | MethodIDSafeTransferFrom = contract.MethodID("safeTransferFrom(address,address,uint256)") 10 | MethodIDSafeTransferFromAndCallReceiver = contract.MethodID("safeTransferFrom(address,address,uint256,bytes)") 11 | MethodIDApprove = contract.MethodID("approve(address,uint256)") 12 | MethodIDSetApprovalForAll = contract.MethodID("setApprovalForAll(address,bool)") 13 | 14 | EventHashTransfer = contract.EventHash("Transfer(address,address,uint256)") 15 | EventHashApproval = contract.EventHash("Approval(address,address,uint256)") 16 | EventHashApprovalForAll = contract.EventHash("ApprovalForAll(address,address,bool)") 17 | ) 18 | -------------------------------------------------------------------------------- /internal/engine/protocol/farcaster/option.go: -------------------------------------------------------------------------------- 1 | package farcaster 2 | 3 | import ( 4 | "math/big" 5 | 6 | "github.com/rss3-network/node/v2/config" 7 | "github.com/rss3-network/node/v2/config/parameter" 8 | "github.com/rss3-network/protocol-go/schema/network" 9 | ) 10 | 11 | type Option struct { 12 | APIKey *string `json:"api_key" mapstructure:"api_key"` 13 | // TimestampStart is the Farcaster seconds timestamp that the worker should start from. 14 | TimestampStart *big.Int `json:"timestamp_start" mapstructure:"timestamp_start"` 15 | } 16 | 17 | func NewOption(n network.Network, parameters *config.Parameters) (*Option, error) { 18 | var option Option 19 | 20 | if parameters == nil { 21 | return &Option{ 22 | TimestampStart: parameter.CurrentNetworkStartBlock[n].Block, 23 | }, nil 24 | } 25 | 26 | if err := parameters.Decode(&option); err != nil { 27 | return nil, err 28 | } 29 | 30 | if option.TimestampStart == nil { 31 | option.TimestampStart = parameter.CurrentNetworkStartBlock[n].Block 32 | } 33 | 34 | return &option, nil 35 | } 36 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/table/dataset_farcaster_profile.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "github.com/lib/pq" 5 | "github.com/rss3-network/node/v2/internal/database/model" 6 | ) 7 | 8 | type DatasetFarcasterProfile struct { 9 | Fid int64 `gorm:"column:fid"` 10 | Username string `gorm:"column:username"` 11 | CustodyAddress string `gorm:"column:custody_address"` 12 | EthAddresses pq.StringArray `gorm:"column:eth_addresses;type:text[]"` 13 | } 14 | 15 | func (d *DatasetFarcasterProfile) Import(profile *model.Profile) (err error) { 16 | d.Fid = profile.Fid 17 | d.Username = profile.Username 18 | d.CustodyAddress = profile.CustodyAddress 19 | d.EthAddresses = profile.EthAddresses 20 | 21 | return nil 22 | } 23 | 24 | func (d *DatasetFarcasterProfile) Export() (*model.Profile, error) { 25 | profile := model.Profile{ 26 | Fid: d.Fid, 27 | Username: d.Username, 28 | CustodyAddress: d.CustodyAddress, 29 | EthAddresses: d.EthAddresses, 30 | } 31 | 32 | return &profile, nil 33 | } 34 | -------------------------------------------------------------------------------- /provider/ethereum/contract/erc1155/contract.go: -------------------------------------------------------------------------------- 1 | package erc1155 2 | 3 | import "github.com/rss3-network/node/v2/provider/ethereum/contract" 4 | 5 | // https://eips.ethereum.org/EIPS/eip-1155 6 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/ERC1155.abi --pkg erc1155 --type ERC1155 --out contract_erc1155.go 7 | 8 | var ( 9 | MethodIDSafeTransferFrom = contract.MethodID("safeTransferFrom(address,address,uint256,uint256,bytes)") 10 | MethodIDSafeBatchTransferFrom = contract.MethodID("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)") 11 | MethodIDSetApprovalForAll = contract.MethodID("setApprovalForAll(address,bool)") 12 | 13 | EventHashTransferSingle = contract.EventHash("TransferSingle(address,address,address,uint256,uint256)") 14 | EventHashTransferBatch = contract.EventHash("TransferBatch(address,address,address,uint256[],uint256[])") 15 | EventHashApprovalForAll = contract.EventHash("ApprovalForAll(address,address,bool)") 16 | EventHashURI = contract.EventHash("URI(string,uint256)") 17 | ) 18 | -------------------------------------------------------------------------------- /internal/node/component/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | 7 | "github.com/labstack/echo/v4" 8 | ) 9 | 10 | // BearerAuth middleware for bearer token authentication 11 | func BearerAuth(accessToken string) echo.MiddlewareFunc { 12 | return func(next echo.HandlerFunc) echo.HandlerFunc { 13 | return func(c echo.Context) error { 14 | authHeader := c.Request().Header.Get("Authorization") 15 | if authHeader == "" { 16 | return echo.NewHTTPError(http.StatusUnauthorized, "Missing Authorization header") 17 | } 18 | 19 | // Check if the header starts with "Bearer " 20 | if !strings.HasPrefix(authHeader, "Bearer ") { 21 | return echo.NewHTTPError(http.StatusUnauthorized, "Invalid Authorization header format") 22 | } 23 | 24 | // Extract the token 25 | token := strings.TrimPrefix(authHeader, "Bearer ") 26 | 27 | // Verify the token 28 | if token != accessToken { 29 | return echo.NewHTTPError(http.StatusUnauthorized, "Invalid access token") 30 | } 31 | 32 | return next(c) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-present, The RSS3 Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /schema/worker/federated/platform.go: -------------------------------------------------------------------------------- 1 | package federated 2 | 3 | import "github.com/labstack/echo/v4" 4 | 5 | //go:generate go run --mod=mod github.com/dmarkham/enumer@v1.5.9 --values --type=Platform --linecomment --output platform_string.go --json --yaml --sql 6 | //go:generate go run --mod=mod github.com/rss3-network/enum-schema@v0.1.6 --type=Platform --linecomment --output ../../../docs/schemas/FederatedPlatform.yaml -t ../../../docs/schemas/tmpl/Federated.yaml.tmpl 7 | type Platform uint64 8 | 9 | const ( 10 | PlatformUnknown Platform = iota // Unknown 11 | PlatformMastodon // Mastodon 12 | PlatformBluesky // Bluesky 13 | ) 14 | 15 | var _ echo.BindUnmarshaler = (*Platform)(nil) 16 | 17 | func (p *Platform) UnmarshalParam(param string) error { 18 | platform, err := PlatformString(param) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | *p = platform 24 | 25 | return nil 26 | } 27 | 28 | // ToPlatformMap is a map of worker to platform 29 | var ToPlatformMap = map[Worker]Platform{ 30 | Mastodon: PlatformMastodon, 31 | Bluesky: PlatformBluesky, 32 | } 33 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/table/dataset_bluesky_profile.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/rss3-network/node/v2/internal/database/model" 7 | ) 8 | 9 | type DatasetBlueskyProfile struct { 10 | DID string `gorm:"column:did;primaryKey"` 11 | Handle string `gorm:"column:handle"` 12 | CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` 13 | UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` 14 | } 15 | 16 | func (DatasetBlueskyProfile) TableName() string { 17 | return "dataset_bluesky_profiles" 18 | } 19 | 20 | func (d *DatasetBlueskyProfile) Import(profile *model.BlueskyProfile) error { 21 | d.DID = profile.DID 22 | d.Handle = profile.Handle 23 | d.CreatedAt = profile.CreatedAt 24 | d.UpdatedAt = profile.UpdatedAt 25 | 26 | return nil 27 | } 28 | 29 | func (d *DatasetBlueskyProfile) Export() (*model.BlueskyProfile, error) { 30 | profile := model.BlueskyProfile{ 31 | DID: d.DID, 32 | Handle: d.Handle, 33 | CreatedAt: d.CreatedAt, 34 | UpdatedAt: d.UpdatedAt, 35 | } 36 | 37 | return &profile, nil 38 | } 39 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/curve/pool/schema.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/protocol-go/schema/network" 6 | ) 7 | 8 | type ContractType string 9 | 10 | // Contract types. 11 | const ( 12 | ContractTypePool ContractType = "pool" 13 | ContractTypeToken ContractType = "token" 14 | ContractTypeGauge ContractType = "gauge" 15 | ) 16 | 17 | // Response is a curve pool. 18 | type Response[T any] struct { 19 | Success bool `json:"success"` 20 | Data T `json:"data"` 21 | Timestamp int64 `json:"generatedTimeMs"` 22 | } 23 | 24 | type GetPoolData struct { 25 | PoolData []Pool `json:"poolData"` 26 | } 27 | 28 | // Pool is a curve pool. 29 | type Pool struct { 30 | Network network.Network `json:"-"` 31 | Name string `json:"name"` 32 | Address common.Address `json:"address"` 33 | LiquidityProviderTokenAddress common.Address `json:"lpTokenAddress"` 34 | GaugeAddress common.Address `json:"gaugeAddress"` 35 | } 36 | -------------------------------------------------------------------------------- /provider/arweave/bundle/signature.go: -------------------------------------------------------------------------------- 1 | package bundle 2 | 3 | const ( 4 | SignatureTypeArweave = 1 5 | SignatureED25519 = 2 6 | SignatureEthereum = 3 7 | SignatureSolana = 4 8 | SignatureInjectedAptos = 5 9 | SignatureMultiAptos = 6 10 | SignatureTypeTypedEthereum = 7 11 | ) 12 | 13 | type SignatureType struct { 14 | SignatureLength uint16 15 | PublicKeyLength uint16 16 | } 17 | 18 | var signatureTypeMap = map[uint16]SignatureType{ 19 | SignatureTypeArweave: { 20 | SignatureLength: 512, 21 | PublicKeyLength: 512, 22 | }, 23 | SignatureED25519: { 24 | SignatureLength: 64, 25 | PublicKeyLength: 32, 26 | }, 27 | SignatureEthereum: { 28 | SignatureLength: 64 + 1, 29 | PublicKeyLength: 65, 30 | }, 31 | SignatureSolana: { 32 | SignatureLength: 64, 33 | PublicKeyLength: 32, 34 | }, 35 | SignatureInjectedAptos: { 36 | SignatureLength: 64, 37 | PublicKeyLength: 32, 38 | }, 39 | SignatureMultiAptos: { 40 | SignatureLength: 64*32 + 4, 41 | PublicKeyLength: 32*32 + 1, 42 | }, 43 | SignatureTypeTypedEthereum: { 44 | SignatureLength: 64 + 1, 45 | PublicKeyLength: 42, 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: Submit discovered bugs 3 | labels: ['bug'] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Please ensure you provide all the information required by this template, otherwise the issue will be closed immediately. 10 | 11 | - type: textarea 12 | id: what-expected 13 | attributes: 14 | label: What is expected? 15 | validations: 16 | required: true 17 | 18 | - type: textarea 19 | id: actual-happened 20 | attributes: 21 | label: What is actually happening? 22 | validations: 23 | required: true 24 | 25 | - type: textarea 26 | id: logs 27 | attributes: 28 | label: Additional info 29 | description: logs, errors, etc. 30 | render: shell 31 | validations: 32 | required: true 33 | 34 | - type: checkboxes 35 | id: terms 36 | attributes: 37 | label: This is not a duplicated issue 38 | options: 39 | - label: I have searched [existing issues](https://github.com/rss3-network/node/issues) to ensure this bug has not already been reported 40 | required: true 41 | -------------------------------------------------------------------------------- /internal/engine/worker.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rss3-network/protocol-go/schema" 7 | activityx "github.com/rss3-network/protocol-go/schema/activity" 8 | "github.com/rss3-network/protocol-go/schema/network" 9 | "github.com/rss3-network/protocol-go/schema/tag" 10 | ) 11 | 12 | type Worker interface { 13 | // Name is the name of the worker. 14 | Name() string 15 | // Platform returns the display name of the worker as the `platform` in the final Activity response. 16 | Platform() string 17 | // Network returns all networks where the worker runs on and displayed as the `network` in the final Activity response. 18 | Network() []network.Network 19 | // Tags the possible `tag` of the worker, displayed in the final Activity response. 20 | Tags() []tag.Tag 21 | // Types the possible `type` of the worker, displayed in the final Activity response. 22 | Types() []schema.Type 23 | // Filter the DataSourceFilter of the worker(network, state, start logics, etc.). 24 | Filter() DataSourceFilter 25 | // Transform the core logic of the worker and returns the Activity. 26 | Transform(ctx context.Context, task Task) (*activityx.Activity, error) 27 | } 28 | -------------------------------------------------------------------------------- /provider/ethereum/contract/highlight/contract.go: -------------------------------------------------------------------------------- 1 | package highlight 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // exchange https://etherscan.io/address/0x1bf979282181f2b7a640d17ab5d2e25125f2de5e 9 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/MintManager.abi --pkg highlight --type mint_manager --out mint_manager.go 10 | 11 | var ( 12 | AddressMintManagerMainnet = common.HexToAddress("0x1bf979282181f2b7a640d17ab5d2e25125f2de5e") 13 | AddressMintManagerPolygon = common.HexToAddress("0xfbb65C52f439B762F712026CF6DD7D8E82F81eb9") 14 | AddressMintManagerArbitrum = common.HexToAddress("0x41cbab1028984A34C1338F437C726de791695AE8") 15 | AddressMintManagerBase = common.HexToAddress("0x8087039152c472Fa74F47398628fF002994056EA") 16 | AddressMintManagerOptimism = common.HexToAddress("0xFafd47bb399d570b5AC95694c5D2a1fb5EA030bB") 17 | 18 | EventHashNativeGasTokenPayment = contract.EventHash("NativeGasTokenPayment(address,bytes32,uint256,uint32)") 19 | EventHashNumTokenMint = contract.EventHash("NumTokenMint(bytes32,address,bool,uint256)") 20 | ) 21 | -------------------------------------------------------------------------------- /provider/ethereum/contract/savm/contract.go: -------------------------------------------------------------------------------- 1 | package savm 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // SAVMBridge 9 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/SAVMBridge.abi --pkg savm --type SAVMBridge --out contract_savm_bridge.go 10 | // BTCBridge 11 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/BTCBridge.abi --pkg savm --type BTCBridge --out contract_btc_bridge.go 12 | 13 | var ( 14 | AddressSAVMBridge = common.HexToAddress("0x1109F6221F684BCb9B2529b8803a7b8c3411d45f") 15 | AddressBTCBridge = common.HexToAddress("0xF70Af817B07118CBF7ACCC38767899598e045408") 16 | AddressSAVMToken = common.HexToAddress("0x0E02765992f946397E6d2e65642eABb9cc674928") 17 | AddressWBTCToken = common.HexToAddress("0x5db252ead05C54B08A83414adCAbF46Eaa9E0337") 18 | 19 | EventHashBTCBridgeDeposit = contract.EventHash("Deposit(bytes32,uint256,address)") 20 | EventHashBTCBridgeWithdraw = contract.EventHash("Withdraw(bytes32,uint256,address)") 21 | EventHashSAVMTransfer = contract.EventHash("Transfer(address,address,uint256)") 22 | ) 23 | -------------------------------------------------------------------------------- /config/parameter/data.go: -------------------------------------------------------------------------------- 1 | package parameter 2 | 3 | import ( 4 | "math/big" 5 | 6 | "github.com/rss3-network/protocol-go/schema/network" 7 | ) 8 | 9 | // NumberOfMonthsToCover the number of months that a Node should cover data for 10 | const NumberOfMonthsToCover = 4 11 | 12 | type StartBlock struct { 13 | Block *big.Int `json:"block"` 14 | Timestamp int64 `json:"timestamp"` 15 | } 16 | 17 | type NetworkTolerance map[network.Network]uint64 18 | type NetworkStartBlock map[network.Network]*StartBlock 19 | 20 | type NetworkCoreWorkerDiskSpacePerMonth map[network.Network]uint 21 | 22 | // CurrentNetworkTolerance should be updated each epoch from vsl 23 | var CurrentNetworkTolerance = NetworkTolerance{} 24 | 25 | // CurrentNetworkStartBlock should be updated each epoch from vsl 26 | var CurrentNetworkStartBlock = NetworkStartBlock{} 27 | 28 | // CurrentNetworkCoreWorkerDiskSpacePerMonth the disk space required for the network's core worker to store a month worth of data 29 | // The data is calculated based on the average disk space usage during 2024 Q1. 30 | // Actually usage may vary depending on the network's activity. 31 | var CurrentNetworkCoreWorkerDiskSpacePerMonth = NetworkCoreWorkerDiskSpacePerMonth{} 32 | -------------------------------------------------------------------------------- /schema/worker/rss/worker.go: -------------------------------------------------------------------------------- 1 | package rss 2 | 3 | import ( 4 | "github.com/labstack/echo/v4" 5 | "github.com/rss3-network/protocol-go/schema/tag" 6 | ) 7 | 8 | //go:generate go run --mod=mod github.com/dmarkham/enumer@v1.5.9 --values --type=Worker --linecomment --output worker_string.go --json --yaml --sql 9 | //go:generate go run --mod=mod github.com/rss3-network/enum-schema@v0.1.6 --type=Worker --linecomment --output ../../../docs/schemas/RSSWorker.yaml -t ../../../docs/schemas/tmpl/RSS.yaml.tmpl 10 | type Worker int 11 | 12 | const ( 13 | Core Worker = iota + 1 // core 14 | ) 15 | 16 | func (w Worker) Component() string { 17 | return "rss" 18 | } 19 | 20 | func (w Worker) Name() string { 21 | return w.String() 22 | } 23 | 24 | var _ echo.BindUnmarshaler = (*Worker)(nil) 25 | 26 | func (w *Worker) UnmarshalParam(param string) error { 27 | worker, err := WorkerString(param) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | *w = worker 33 | 34 | return nil 35 | } 36 | 37 | func GetValueByWorkerStr(workerStr string) Worker { 38 | return _WorkerNameToValueMap[workerStr] 39 | } 40 | 41 | // ToTagsMap is a map of worker to tags 42 | var ToTagsMap = map[Worker][]tag.Tag{ 43 | Core: {tag.RSS}, 44 | } 45 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/core/worker.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/redis/rueidis" 7 | "github.com/rss3-network/node/v2/config" 8 | "github.com/rss3-network/node/v2/internal/engine" 9 | "github.com/rss3-network/node/v2/internal/engine/worker/decentralized/core/arweave" 10 | "github.com/rss3-network/node/v2/internal/engine/worker/decentralized/core/ethereum" 11 | "github.com/rss3-network/node/v2/internal/engine/worker/decentralized/core/farcaster" 12 | "github.com/rss3-network/node/v2/internal/engine/worker/decentralized/core/near" 13 | "github.com/rss3-network/protocol-go/schema/network" 14 | ) 15 | 16 | // NewWorker creates a new core worker. 17 | func NewWorker(config *config.Module, redisClient rueidis.Client) (engine.Worker, error) { 18 | switch config.Network.Protocol() { 19 | case network.EthereumProtocol: 20 | return ethereum.NewWorker(config, redisClient) 21 | case network.ArweaveProtocol: 22 | return arweave.NewWorker(config) 23 | case network.FarcasterProtocol: 24 | return farcaster.NewWorker() 25 | case network.NearProtocol: 26 | return near.NewWorker(config) 27 | default: 28 | return nil, fmt.Errorf("unsupported worker %s", config.Network) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /schema/worker/worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/mitchellh/mapstructure" 7 | "github.com/rss3-network/node/v2/schema/worker/decentralized" 8 | "github.com/rss3-network/node/v2/schema/worker/federated" 9 | "github.com/rss3-network/node/v2/schema/worker/rss" 10 | ) 11 | 12 | type Worker interface { 13 | Component() string 14 | Name() string 15 | } 16 | 17 | func HookFunc() mapstructure.DecodeHookFuncType { 18 | return func( 19 | f reflect.Type, 20 | t reflect.Type, 21 | data interface{}, 22 | ) (interface{}, error) { 23 | // Only process if the target type is Worker and the protocol type is string 24 | if f.Kind() == reflect.String && t.Kind() == reflect.TypeOf((*Worker)(nil)).Elem().Kind() { 25 | workerStr := data.(string) 26 | 27 | // TODO: Implement the logic to determine the worker type 28 | if value := decentralized.GetValueByWorkerStr(workerStr); value != 0 { 29 | return value, nil 30 | } else if value := federated.GetValueByWorkerStr(workerStr); value != 0 { 31 | return value, nil 32 | } else if value := rss.GetValueByWorkerStr(workerStr); value != 0 { 33 | return value, nil 34 | } 35 | } 36 | // For all other types, return data 37 | return data, nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /internal/node/broadcaster/server.go: -------------------------------------------------------------------------------- 1 | package broadcaster 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/robfig/cron/v3" 12 | "github.com/rss3-network/node/v2/config" 13 | ) 14 | 15 | type Broadcaster struct { 16 | config *config.File 17 | cron *cron.Cron 18 | httpClient *http.Client 19 | } 20 | 21 | func (b *Broadcaster) Run(ctx context.Context) error { 22 | // run register cron job 23 | if err := b.Register(ctx); err != nil { 24 | return fmt.Errorf("register: %w", err) 25 | } 26 | 27 | _, err := b.cron.AddFunc("@every 1m", func() { 28 | if err := b.Heartbeat(ctx); err != nil { 29 | return 30 | } 31 | }) 32 | if err != nil { 33 | return fmt.Errorf("add heartbeat cron job: %w", err) 34 | } 35 | 36 | b.cron.Start() 37 | 38 | stopchan := make(chan os.Signal, 1) 39 | 40 | signal.Notify(stopchan, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM) 41 | <-stopchan 42 | 43 | return nil 44 | } 45 | 46 | func NewBroadcaster(_ context.Context, config *config.File) (*Broadcaster, error) { 47 | instance := &Broadcaster{ 48 | config: config, 49 | cron: cron.New(), 50 | httpClient: http.DefaultClient, 51 | } 52 | 53 | return instance, nil 54 | } 55 | -------------------------------------------------------------------------------- /internal/node/component/federated/transformer_activity.go: -------------------------------------------------------------------------------- 1 | package federated 2 | 3 | import ( 4 | "context" 5 | 6 | activityx "github.com/rss3-network/protocol-go/schema/activity" 7 | "github.com/rss3-network/protocol-go/schema/tag" 8 | lop "github.com/samber/lo/parallel" 9 | "go.uber.org/zap" 10 | ) 11 | 12 | // TransformActivity should add related URLs to the activity based on action tag, network and platform 13 | func (c *Component) TransformActivity(ctx context.Context, activity *activityx.Activity) (*activityx.Activity, error) { 14 | if activity == nil { 15 | return nil, nil 16 | } 17 | 18 | // iterate over actions and transform them based on tag, network and platform 19 | lop.ForEach(activity.Actions, func(actionPtr *activityx.Action, index int) { 20 | action := *actionPtr 21 | 22 | var err error 23 | 24 | switch action.Tag { 25 | case tag.Social: 26 | *activity.Actions[index], err = c.TransformSocialType(ctx, activity.Network, activity.Platform, *actionPtr) 27 | default: 28 | activity.Actions[index] = actionPtr 29 | } 30 | 31 | if err != nil { 32 | zap.L().Error("failed to transform federated activity action", 33 | zap.Error(err), 34 | zap.String("id", activity.ID)) 35 | } 36 | }) 37 | 38 | return activity, nil 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | RSS3 logo 6 | 7 |

8 |

9 | follow RSS3 on X 10 | Join RSS3 Discord 11 | 12 |

13 | 14 | 15 | # RSS3 Node 16 | 17 | The RSS3 Node, an RSS3 Data Sublayer (DSL) component, is responsible for indexing, transforming, storing, and ultimately serving the Open Information to the end users. 18 | 19 | ## Deployment 20 | 21 | See for a detailed deployment guide. 22 | 23 | ## Contribution 24 | 25 | See for a detailed contribution guide. 26 | 27 | ## License 28 | 29 | [MIT](LICENSE). 30 | -------------------------------------------------------------------------------- /docs/path/federated/network.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetFederatedNetwork 3 | summary: Get Network Activities 4 | description: Retrieve a list of activities from the specified federated network. This endpoint allows you to filter activities by various parameters such as limit, timestamp, success status, and more. 5 | tags: 6 | - Federated 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_network.yaml" 11 | - $ref: "../../parameters/query_limit.yaml" 12 | - $ref: "../../parameters/query_action_limit.yaml" 13 | - $ref: "../../parameters/query_cursor.yaml" 14 | - $ref: "../../parameters/query_since_timestamp.yaml" 15 | - $ref: "../../parameters/query_until_timestamp.yaml" 16 | - $ref: "../../parameters/query_success.yaml" 17 | - $ref: "../../parameters/query_direction.yaml" 18 | - $ref: "../../parameters/query_tag.yaml" 19 | - $ref: "../../parameters/query_type.yaml" 20 | - $ref: "../../parameters/query_platform_federated.yaml" 21 | responses: 22 | "200": 23 | $ref: "../../responses/FederatedActivitiesResponse.yaml" 24 | "400": 25 | $ref: "../../responses/BadRequest.yaml" 26 | "404": 27 | $ref: "../../responses/NotFound.yaml" 28 | "500": 29 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /internal/node/component/ai/option.go: -------------------------------------------------------------------------------- 1 | package ai 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/config" 5 | ) 6 | 7 | type Option struct { 8 | AgentdataDBURL string `json:"agentdata_db_url" mapstructure:"agentdata_db_url"` 9 | OpenAIAPIKey string `json:"openai_api_key" mapstructure:"openai_api_key"` 10 | OllamaHost string `json:"ollama_host" mapstructure:"ollama_host"` 11 | Twitter OptionTwitter `json:"twitter" mapstructure:"twitter"` 12 | KaitoAPIToken string `json:"kaito_api_token" mapstructure:"kaito_api_token"` 13 | } 14 | 15 | type OptionTwitter struct { 16 | BearerToken string `json:"bearer_token" mapstructure:"bearer_token"` 17 | APIKey string `json:"api_key" mapstructure:"api_key"` 18 | APISecret string `json:"api_secret" mapstructure:"api_secret"` 19 | AccessToken string `json:"access_token" mapstructure:"access_token"` 20 | AccessTokenSecret string `json:"access_token_secret" mapstructure:"access_token_secret"` 21 | } 22 | 23 | func NewOption(options *config.Parameters) (*Option, error) { 24 | var instance Option 25 | 26 | if options == nil { 27 | return &instance, nil 28 | } 29 | 30 | if err := options.Decode(&instance); err != nil { 31 | return nil, err 32 | } 33 | 34 | return &instance, nil 35 | } 36 | -------------------------------------------------------------------------------- /provider/ethereum/contract/aavegotchi/contract.go: -------------------------------------------------------------------------------- 1 | package aavegotchi 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/ERC1155MarketplaceFacet.abi --pkg aavegotchi --type ERC1155Marketplace --out ./contract_erc1155_marketplace_facet.go 9 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/ERC721MarketplaceFacet.abi --pkg aavegotchi --type ERC721Marketplace --out ./contract_erc721_marketplace_facet.go 10 | 11 | var ( 12 | AddressAavegotchi = common.HexToAddress("0x86935F11C86623deC8a25696E1C19a8659CbF95d") 13 | 14 | EventHashERC721ListingAdd = contract.EventHash("ERC721ListingAdd(uint256,address,address,uint256,uint256,uint256)") 15 | EventHashERC721ExecutedListing = contract.EventHash("ERC721ExecutedListing(uint256,address,address,address,uint256,uint256,uint256,uint256)") 16 | EventHashERC1155ExecutedListing = contract.EventHash("ERC1155ExecutedListing(uint256,address,address,address,uint256,uint256,uint256,uint256,uint256)") 17 | EventHashERC1155ListingAdd = contract.EventHash("ERC1155ListingAdd(uint256,address,address,uint256,uint256,uint256,uint256,uint256)") 18 | ) 19 | -------------------------------------------------------------------------------- /docs/path/federated/platform.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetFederatedPlatform 3 | summary: Get Platform Activities 4 | description: Retrieve a list of activities from the specified federated platform. This endpoint allows you to filter activities by various parameters such as limit, timestamp, success status, and more. 5 | tags: 6 | - Federated 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_platform_federated.yaml" 11 | - $ref: "../../parameters/query_limit.yaml" 12 | - $ref: "../../parameters/query_action_limit.yaml" 13 | - $ref: "../../parameters/query_cursor.yaml" 14 | - $ref: "../../parameters/query_since_timestamp.yaml" 15 | - $ref: "../../parameters/query_until_timestamp.yaml" 16 | - $ref: "../../parameters/query_success.yaml" 17 | - $ref: "../../parameters/query_direction.yaml" 18 | - $ref: "../../parameters/query_tag.yaml" 19 | - $ref: "../../parameters/query_type.yaml" 20 | - $ref: "../../parameters/query_network.yaml" 21 | responses: 22 | "200": 23 | $ref: "../../responses/FederatedActivitiesResponse.yaml" 24 | "400": 25 | $ref: "../../responses/BadRequest.yaml" 26 | "404": 27 | $ref: "../../responses/NotFound.yaml" 28 | "500": 29 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /internal/node/component/rss/handler.go: -------------------------------------------------------------------------------- 1 | package rss 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | "github.com/rss3-network/node/v2/common/http/response" 8 | activityx "github.com/rss3-network/protocol-go/schema/activity" 9 | "go.uber.org/zap" 10 | ) 11 | 12 | type Response struct { 13 | Data []*activityx.Activity `json:"data"` 14 | } 15 | 16 | func (h *Component) Handler(ctx echo.Context) error { 17 | path := ctx.Param("*") 18 | zap.L().Debug("handling RSS request", 19 | zap.String("path", path), 20 | zap.String("request_uri", ctx.Request().RequestURI)) 21 | 22 | go h.CollectTrace(ctx.Request().Context(), ctx.Request().RequestURI, path) 23 | 24 | go h.CollectMetric(ctx.Request().Context(), ctx.Request().RequestURI, path) 25 | 26 | addRecentRequest(ctx.Request().RequestURI) 27 | 28 | data, err := h.getActivities(ctx.Request().Context(), path, ctx.Request().URL) 29 | if err != nil { 30 | zap.L().Error("failed to get activities from RSS feed", 31 | zap.String("path", path), 32 | zap.Error(err)) 33 | 34 | return response.InternalError(ctx) 35 | } 36 | 37 | zap.L().Info("successfully retrieved RSS activities", 38 | zap.String("path", path), 39 | zap.Int("activity_count", len(data))) 40 | 41 | return ctx.JSON(http.StatusOK, Response{ 42 | Data: data, 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /internal/database/dialer/postgres/table/checkpoint.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | 7 | "github.com/rss3-network/node/v2/internal/engine" 8 | "github.com/rss3-network/protocol-go/schema/network" 9 | ) 10 | 11 | type Checkpoint struct { 12 | ID string `gorm:"column:id"` 13 | Network network.Network `gorm:"column:network"` 14 | Worker string `gorm:"column:worker"` 15 | State json.RawMessage `gorm:"column:state;type:jsonb"` 16 | IndexCount int64 `gorm:"column:index_count"` 17 | CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` 18 | UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` 19 | } 20 | 21 | func (c *Checkpoint) Import(checkpoint *engine.Checkpoint) (err error) { 22 | c.ID = checkpoint.ID 23 | c.Network = checkpoint.Network 24 | c.Worker = checkpoint.Worker 25 | c.State = checkpoint.State 26 | c.IndexCount = checkpoint.IndexCount 27 | c.UpdatedAt = checkpoint.UpdatedAt 28 | 29 | return nil 30 | } 31 | 32 | func (c *Checkpoint) Export() (*engine.Checkpoint, error) { 33 | return &engine.Checkpoint{ 34 | ID: c.ID, 35 | Network: c.Network, 36 | Worker: c.Worker, 37 | State: c.State, 38 | IndexCount: c.IndexCount, 39 | UpdatedAt: c.UpdatedAt, 40 | }, nil 41 | } 42 | -------------------------------------------------------------------------------- /schema/worker/federated/worker.go: -------------------------------------------------------------------------------- 1 | package federated 2 | 3 | import ( 4 | "github.com/labstack/echo/v4" 5 | "github.com/rss3-network/protocol-go/schema/tag" 6 | ) 7 | 8 | //go:generate go run --mod=mod github.com/dmarkham/enumer@v1.5.9 --values --type=Worker --linecomment --output worker_string.go --json --yaml --sql 9 | //go:generate go run --mod=mod github.com/rss3-network/enum-schema@v0.1.6 --type=Worker --linecomment --output ../../../docs/schemas/FederatedWorker.yaml -t ../../../docs/schemas/tmpl/Federated.yaml.tmpl 10 | type Worker int 11 | 12 | const ( 13 | Mastodon Worker = iota + 1 // mastodon 14 | Bluesky // bluesky 15 | ) 16 | 17 | func (w Worker) Component() string { 18 | return "federated" 19 | } 20 | 21 | func (w Worker) Name() string { 22 | return w.String() 23 | } 24 | 25 | var _ echo.BindUnmarshaler = (*Worker)(nil) 26 | 27 | func (w *Worker) UnmarshalParam(param string) error { 28 | worker, err := WorkerString(param) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | *w = worker 34 | 35 | return nil 36 | } 37 | 38 | func GetValueByWorkerStr(workerStr string) Worker { 39 | return _WorkerNameToValueMap[workerStr] 40 | } 41 | 42 | // ToTagsMap is a map of worker to tags 43 | var ToTagsMap = map[Worker][]tag.Tag{ 44 | Mastodon: {tag.Social}, 45 | Bluesky: {tag.Social}, 46 | } 47 | -------------------------------------------------------------------------------- /docs/path/decentralized/network.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetDecentralizedNetwork 3 | summary: Get Network Activities 4 | description: Retrieve a list of activities from the specified decentralized network. This endpoint allows you to filter activities by various parameters such as limit, timestamp, success status, and more. 5 | tags: 6 | - Decentralized 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_network.yaml" 11 | - $ref: "../../parameters/query_limit.yaml" 12 | - $ref: "../../parameters/query_action_limit.yaml" 13 | - $ref: "../../parameters/query_cursor.yaml" 14 | - $ref: "../../parameters/query_since_timestamp.yaml" 15 | - $ref: "../../parameters/query_until_timestamp.yaml" 16 | - $ref: "../../parameters/query_success.yaml" 17 | - $ref: "../../parameters/query_direction.yaml" 18 | - $ref: "../../parameters/query_tag.yaml" 19 | - $ref: "../../parameters/query_type.yaml" 20 | - $ref: "../../parameters/query_platform_decentralized.yaml" 21 | responses: 22 | "200": 23 | $ref: "../../responses/DecentralizedActivitiesResponse.yaml" 24 | "400": 25 | $ref: "../../responses/BadRequest.yaml" 26 | "404": 27 | $ref: "../../responses/NotFound.yaml" 28 | "500": 29 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/path/decentralized/platform.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetDecentralizedPlatform 3 | summary: Get Platform Activities 4 | description: Retrieve a list of activities from the specified decentralized platform. This endpoint allows you to filter activities by various parameters such as limit, timestamp, success status, and more. 5 | tags: 6 | - Decentralized 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_platform_decentralized.yaml" 11 | - $ref: "../../parameters/query_limit.yaml" 12 | - $ref: "../../parameters/query_action_limit.yaml" 13 | - $ref: "../../parameters/query_cursor.yaml" 14 | - $ref: "../../parameters/query_since_timestamp.yaml" 15 | - $ref: "../../parameters/query_until_timestamp.yaml" 16 | - $ref: "../../parameters/query_success.yaml" 17 | - $ref: "../../parameters/query_direction.yaml" 18 | - $ref: "../../parameters/query_tag.yaml" 19 | - $ref: "../../parameters/query_type.yaml" 20 | - $ref: "../../parameters/query_network.yaml" 21 | responses: 22 | "200": 23 | $ref: "../../responses/DecentralizedActivitiesResponse.yaml" 24 | "400": 25 | $ref: "../../responses/BadRequest.yaml" 26 | "404": 27 | $ref: "../../responses/NotFound.yaml" 28 | "500": 29 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /internal/engine/protocol/atproto/option.go: -------------------------------------------------------------------------------- 1 | package atproto 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/rss3-network/node/v2/config" 8 | "github.com/rss3-network/node/v2/config/parameter" 9 | "github.com/rss3-network/protocol-go/schema/network" 10 | "github.com/samber/lo" 11 | "go.uber.org/zap" 12 | ) 13 | 14 | type Option struct { 15 | Username string `json:"username" mapstructure:"username"` 16 | Password string `json:"password" mapstructure:"password"` 17 | 18 | TimestampStart time.Time `json:"timestamp_start" mapstructure:"timestamp_start"` 19 | } 20 | 21 | func NewOption(parameters *config.Parameters) (*Option, error) { 22 | var option Option 23 | 24 | if parameters == nil { 25 | return &Option{}, nil 26 | } 27 | 28 | if err := parameters.Decode(&option); err != nil { 29 | zap.L().Error("decode parameters failed", zap.Error(err)) 30 | 31 | return nil, fmt.Errorf("decode parameters failed: %w", err) 32 | } 33 | 34 | if lo.IsEmpty(option.TimestampStart) { 35 | if parameter.CurrentNetworkStartBlock[network.Bluesky] == nil { 36 | // Default to 90 days ago 37 | option.TimestampStart = time.Now().Add(-time.Hour * 24 * 90) 38 | 39 | return &option, nil 40 | } 41 | 42 | option.TimestampStart = time.Unix(parameter.CurrentNetworkStartBlock[network.Bluesky].Timestamp, 0) 43 | } 44 | 45 | return &option, nil 46 | } 47 | -------------------------------------------------------------------------------- /provider/ipfs/gateway.go: -------------------------------------------------------------------------------- 1 | package ipfs 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "net/http" 7 | 8 | "github.com/samber/lo" 9 | ) 10 | 11 | const ( 12 | DefaultGatewayRSS3 = "https://ipfs.rss3.page/" 13 | DefaultGatewayIPFS = "https://ipfs.io/" 14 | DefaultGatewayCloudflare = "https://cloudflare-ipfs.com/" 15 | DefaultGateway4EVERLAND = "https://4everland.io/" 16 | ) 17 | 18 | var DefaultGateways = []string{ 19 | DefaultGatewayRSS3, 20 | DefaultGatewayIPFS, 21 | DefaultGatewayCloudflare, 22 | DefaultGateway4EVERLAND, 23 | } 24 | 25 | const ( 26 | DefaultGatewayList = "https://raw.githubusercontent.com/ipfs/public-gateway-checker/master/gateways.txt" 27 | ) 28 | 29 | func FetchGateways(ctx context.Context, gatewayList string) ([]string, error) { 30 | request, err := http.NewRequestWithContext(ctx, http.MethodGet, gatewayList, nil) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | // nolint:bodyclose // False positive. 36 | response, err := http.DefaultClient.Do(request) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | defer lo.Try(response.Body.Close) 42 | 43 | var ( 44 | scanner = bufio.NewScanner(response.Body) 45 | gatewayURLs = make([]string, 0) 46 | ) 47 | 48 | for scanner.Scan() { 49 | gatewayURLs = append(gatewayURLs, scanner.Text()) 50 | } 51 | 52 | return gatewayURLs, nil 53 | } 54 | -------------------------------------------------------------------------------- /provider/ethereum/contract/kiwistand/contract.go: -------------------------------------------------------------------------------- 1 | package kiwistand 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // KIWI 9 | //https://optimistic.etherscan.io/address/0x66747bdC903d17C586fA09eE5D6b54CC85bBEA45 10 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi abi/kiwi.abi --pkg kiwistand --type Kiwi --out contract_kiwi.go 11 | // ProtocolRewards 12 | // https://optimistic.etherscan.io/address/0x7777777f279eba3d3ad8f4e708545291a6fdba8b 13 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi abi/ProtocolRewards.abi --pkg kiwistand --type ProtocolRewards --out contract_protocol_rewards.go 14 | 15 | var ( 16 | AddressKIWI = common.HexToAddress("0x66747bdc903d17c586fa09ee5d6b54cc85bbea45") 17 | AddressProtocolRewards = common.HexToAddress("0x7777777f279eba3d3ad8f4e708545291a6fdba8b") 18 | 19 | EventHashRewardsDeposit = contract.EventHash("RewardsDeposit(address,address,address,address,address,address,uint256,uint256,uint256,uint256,uint256)") 20 | EventHashTransfer = contract.EventHash("Transfer(address,address,uint256)") 21 | EventHashSale = contract.EventHash("Sale(address,uint256,uint256,uint256)") 22 | EventHashMintComment = contract.EventHash("MintComment(address,address,uint256,uint256,string)") 23 | ) 24 | -------------------------------------------------------------------------------- /provider/ethereum/option.go: -------------------------------------------------------------------------------- 1 | package ethereum 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "net/http" 7 | 8 | "github.com/ethereum/go-ethereum/rpc" 9 | ) 10 | 11 | // Option used to configure the client with additional options. 12 | type Option = func(ctx context.Context, client *client) error 13 | 14 | // WithHTTP2Disabled sets the HTTP2 client to be disabled. 15 | func WithHTTP2Disabled() Option { 16 | return func(ctx context.Context, client *client) error { 17 | tr := http.DefaultTransport.(*http.Transport).Clone() 18 | tr.ForceAttemptHTTP2 = false 19 | tr.TLSNextProto = make(map[string]func(authority string, c *tls.Conn) http.RoundTripper) 20 | tr.TLSClientConfig = new(tls.Config) 21 | 22 | httpClient := &http.Client{ 23 | Transport: tr, 24 | } 25 | 26 | var err error 27 | 28 | client.rpcClient, err = rpc.DialOptions(ctx, client.endpoint, rpc.WithHTTPClient(httpClient)) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | return nil 34 | } 35 | } 36 | 37 | // WithHTTPHeader sets the HTTP header for the client. 38 | // The header can be used to set the authorization token and other headers. 39 | func WithHTTPHeader(httpHeader map[string]string) Option { 40 | return func(_ context.Context, client *client) error { 41 | for key, value := range httpHeader { 42 | client.rpcClient.SetHeader(key, value) 43 | } 44 | 45 | return nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /provider/ethereum/etherface/client_test.go: -------------------------------------------------------------------------------- 1 | package etherface_test 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | "testing" 7 | 8 | "github.com/rss3-network/node/v2/provider/ethereum/etherface" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | var ( 13 | setupOnce sync.Once 14 | etherfaceClient etherface.Client 15 | ) 16 | 17 | func setup(t *testing.T) { 18 | setupOnce.Do(func() { 19 | var err error 20 | 21 | etherfaceClient, err = etherface.NewMockEtherfaceClient() 22 | require.NoError(t, err) 23 | }) 24 | } 25 | 26 | func TestEtherfaceClient_Lookup(t *testing.T) { 27 | t.Parallel() 28 | 29 | setup(t) 30 | 31 | type arguments struct { 32 | hash string 33 | } 34 | 35 | testcases := []struct { 36 | name string 37 | arguments arguments 38 | }{ 39 | { 40 | name: "Lookup Function Signature", 41 | arguments: arguments{ 42 | hash: "8f283970", 43 | }, 44 | }, 45 | { 46 | name: "Lookup Function Signature with 0x prefix", 47 | arguments: arguments{ 48 | hash: "0x8f283970", 49 | }, 50 | }, 51 | } 52 | 53 | for _, testcase := range testcases { 54 | testcase := testcase 55 | 56 | t.Run(testcase.name, func(t *testing.T) { 57 | t.Parallel() 58 | 59 | functionName, err := etherfaceClient.Lookup(context.TODO(), testcase.arguments.hash) 60 | require.NoError(t, err) 61 | 62 | require.Equal(t, "changeAdmin", functionName) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - prod 7 | paths-ignore: 8 | - "deploy/**" 9 | pull_request: 10 | paths-ignore: 11 | - "deploy/**" 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: self-hosted 17 | steps: 18 | - name: Import Secrets 19 | uses: hashicorp/vault-action@v3.3.0 20 | with: 21 | url: ${{ secrets.VAULT_ADDR }} 22 | token: ${{ secrets.VAULT_TOKEN }} 23 | secrets: | 24 | kv/data/network/rss3-node ENDPOINT_ETHEREUM ; 25 | kv/data/network/rss3-node ENDPOINT_POLYGON ; 26 | kv/data/network/rss3-node ENDPOINT_ARBITRUM ; 27 | kv/data/network/rss3-node ENDPOINT_OPTIMISM ; 28 | kv/data/network/rss3-node ENDPOINT_BASE ; 29 | kv/data/network/rss3-node ENDPOINT_AVALANCHE ; 30 | kv/data/network/rss3-node ENDPOINT_SAVM ; 31 | kv/data/network/rss3-node ENDPOINT_GNOSIS ; 32 | kv/data/network/rss3-node ENDPOINT_BINANCE_SMART_CHAIN ; 33 | kv/data/network/rss3-node ENDPOINT_LINEA ; 34 | kv/data/network/rss3-node FARCASTER_URI 35 | - name: Setup Go 36 | uses: actions/setup-go@v5 37 | with: 38 | go-version: "1.22.7" 39 | - name: Checkout 40 | uses: actions/checkout@v4 41 | - name: Test 42 | run: make test 43 | -------------------------------------------------------------------------------- /internal/engine/protocol/arweave/data_source_test.go: -------------------------------------------------------------------------------- 1 | package arweave_test 2 | 3 | // var initializeOnce sync.Once 4 | // 5 | // func initialize(t *testing.T) { 6 | // initializeOnce.Do(func() { 7 | // zap.ReplaceGlobals(zaptest.NewLogger(t)) 8 | // }) 9 | // } 10 | 11 | // func TestSource(t *testing.T) { 12 | // t.Parallel() 13 | // 14 | // initialize(t) 15 | // 16 | // type arguments struct { 17 | // conf *config.Module 18 | // } 19 | // 20 | // var testcases []struct { 21 | // name string 22 | // arguments arguments 23 | // want require.ValueAssertionFunc 24 | // wantError require.ErrorAssertionFunc 25 | // } 26 | // 27 | // for _, testcase := range testcases { 28 | // testcase := testcase 29 | // 30 | // t.Run(testcase.name, func(t *testing.T) { 31 | // t.Parallel() 32 | // 33 | // instance, err := arweave.NewSource(testcase.arguments.conf, nil, nil) 34 | // require.NoError(t, err, "new arweave dataSource") 35 | // 36 | // var ( 37 | // tasksChan = make(chan *engine.Tasks) 38 | // errorChan = make(chan error) 39 | // ) 40 | // 41 | // instance.Start(context.Background(), tasksChan, errorChan) 42 | // 43 | // for { 44 | // select { 45 | // case tasks := <-tasksChan: 46 | // for _, task := range tasks.Tasks { 47 | // t.Logf("Task %s", task.ID()) 48 | // } 49 | // case err := <-errorChan: 50 | // require.NoError(t, err) 51 | // 52 | // return 53 | // } 54 | // } 55 | // }) 56 | // } 57 | // } 58 | -------------------------------------------------------------------------------- /internal/engine/protocol/atproto/task.go: -------------------------------------------------------------------------------- 1 | package atproto 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/rss3-network/node/v2/internal/engine" 8 | "github.com/rss3-network/node/v2/provider/atproto" 9 | activityx "github.com/rss3-network/protocol-go/schema/activity" 10 | "github.com/rss3-network/protocol-go/schema/network" 11 | "github.com/rss3-network/protocol-go/schema/typex" 12 | ) 13 | 14 | var _ engine.Task = (*Task)(nil) 15 | 16 | type Task struct { 17 | Network network.Network 18 | Message atproto.Message 19 | } 20 | 21 | func (t Task) ID() string { 22 | return strings.TrimPrefix(t.Message.URI, "at://") 23 | } 24 | 25 | func (t Task) GetNetwork() network.Network { 26 | return t.Network 27 | } 28 | 29 | func (t Task) GetTimestamp() uint64 { 30 | return uint64(t.Message.CreatedAt.Unix()) 31 | } 32 | 33 | func (t Task) Validate() error { 34 | return nil 35 | } 36 | 37 | func (t Task) BuildActivity(options ...activityx.Option) (*activityx.Activity, error) { 38 | activity := activityx.Activity{ 39 | ID: t.ID(), 40 | Network: t.Network, 41 | Type: typex.Unknown, 42 | Status: true, 43 | Actions: make([]*activityx.Action, 0), 44 | Timestamp: t.GetTimestamp(), 45 | } 46 | 47 | // Apply activity options. 48 | for _, option := range options { 49 | if err := option(&activity); err != nil { 50 | return nil, fmt.Errorf("apply option: %w", err) 51 | } 52 | } 53 | 54 | return &activity, nil 55 | } 56 | -------------------------------------------------------------------------------- /docs/path/federated/account.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetFederatedAccount 3 | summary: Get Account Activities 4 | description: This endpoint retrieves the activities associated with a specified account in the federated system. You can use various query parameters to filter and paginate the results, including limits on the number of activities and actions, timestamps, success status, direction, and more. 5 | tags: 6 | - Federated 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_account_federated.yaml" 11 | - $ref: "../../parameters/query_limit.yaml" 12 | - $ref: "../../parameters/query_action_limit.yaml" 13 | - $ref: "../../parameters/query_cursor.yaml" 14 | - $ref: "../../parameters/query_since_timestamp.yaml" 15 | - $ref: "../../parameters/query_until_timestamp.yaml" 16 | - $ref: "../../parameters/query_success.yaml" 17 | - $ref: "../../parameters/query_direction.yaml" 18 | - $ref: "../../parameters/query_network.yaml" 19 | - $ref: "../../parameters/query_tag.yaml" 20 | - $ref: "../../parameters/query_type.yaml" 21 | - $ref: "../../parameters/query_platform_federated.yaml" 22 | responses: 23 | "200": 24 | $ref: "../../responses/FederatedActivitiesResponse.yaml" 25 | "400": 26 | $ref: "../../responses/BadRequest.yaml" 27 | "404": 28 | $ref: "../../responses/NotFound.yaml" 29 | "500": 30 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /common/http/response/error.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | ) 9 | 10 | //go:generate go run --mod=mod github.com/dmarkham/enumer --type=ErrorCode --transform=snake --values --trimprefix=ErrorCode --json --output error_code.go 11 | type ErrorCode int 12 | 13 | const ( 14 | ErrorCodeBadRequest ErrorCode = iota + 1 15 | ErrorCodeValidationFailed 16 | ErrorCodeBadParams 17 | ErrorCodeInternalError 18 | ) 19 | 20 | type ErrorResponse struct { 21 | Message string `json:"message"` 22 | Code ErrorCode `json:"code"` 23 | } 24 | 25 | func BadRequestError(c echo.Context, err error) error { 26 | return c.JSON(http.StatusBadRequest, &ErrorResponse{ 27 | Code: ErrorCodeBadRequest, 28 | Message: fmt.Sprintf("Please check your request and try again, %s", err), 29 | }) 30 | } 31 | 32 | func ValidationFailedError(c echo.Context, err error) error { 33 | return c.JSON(http.StatusBadRequest, &ErrorResponse{ 34 | Code: ErrorCodeValidationFailed, 35 | Message: fmt.Sprintf("Please check your request validation and try again, %s", err), 36 | }) 37 | } 38 | 39 | // InternalError should not return the details of the error to the client for safety reasons. 40 | func InternalError(c echo.Context) error { 41 | return c.JSON(http.StatusInternalServerError, &ErrorResponse{ 42 | Code: ErrorCodeInternalError, 43 | Message: "An internal error has occurred, please try again later", 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /docs/schemas/RSSActivity.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | id: 3 | description: The unique identifier for the activity. 4 | type: string 5 | format: uri 6 | owner: 7 | $ref: "./RSSAccount.yaml" 8 | network: 9 | allOf: 10 | - $ref: "./ProtocolNetwork.yaml" 11 | - example: rsshub 12 | index: 13 | description: The index of the activity in the list. 14 | type: integer 15 | from: 16 | $ref: "./RSSAccount.yaml" 17 | to: 18 | $ref: "./RSSAccount.yaml" 19 | tag: 20 | allOf: 21 | - $ref: "./ProtocolTag.yaml" 22 | - example: rss 23 | type: 24 | $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/type/RSSType.yaml" 25 | platform: 26 | $ref: "./RSSPlatform.yaml" 27 | total_actions: 28 | description: The total number of actions within the activity. 29 | type: integer 30 | actions: 31 | description: The list of actions within the activity. 32 | items: 33 | $ref: "./RSSAction.yaml" 34 | type: array 35 | calldata: 36 | $ref: "./Calldata.yaml" 37 | fee: 38 | $ref: "./Fee.yaml" 39 | direction: 40 | $ref: "./ProtocolDirection.yaml" 41 | success: 42 | $ref: "./Success.yaml" 43 | timestamp: 44 | $ref: "./Timestamp.yaml" 45 | 46 | 47 | 48 | type: object 49 | required: 50 | - id 51 | - network 52 | - index 53 | - from 54 | - to 55 | - tag 56 | - type 57 | - total_actions 58 | - actions 59 | - success 60 | - timestamp -------------------------------------------------------------------------------- /deploy/default/config.default.yaml: -------------------------------------------------------------------------------- 1 | # Default configuration file for the RSS3 Node. 2 | environment: production 3 | 4 | discovery: 5 | operator: 6 | evm_address: 0x...address 7 | signature: 0x...signature 8 | server: 9 | endpoint: https://your.node.com 10 | global_indexer_endpoint: https://gi.rss3.io 11 | access_token: your_access_token 12 | 13 | database: 14 | uri: postgres://postgres:password@localhost:5432/postgres 15 | 16 | redis: 17 | endpoint: localhost:6379 18 | username: 19 | password: 20 | 21 | stream: 22 | enable: false 23 | uri: localhost:9092 24 | 25 | observability: 26 | opentelemetry: 27 | metrics: 28 | enable: false 29 | endpoint: 0.0.0.0:9090 30 | traces: 31 | enable: false 32 | endpoint: localhost:4318 33 | insecure: true 34 | 35 | endpoints: 36 | vsl: 37 | url: https://rpc.rss3.io 38 | 39 | component: 40 | rss: 41 | id: rsshub-core 42 | network: rsshub 43 | worker: core 44 | endpoint: https://your.rsshub.com/ 45 | parameters: 46 | authentication: 47 | access_key: 48 | ai: 49 | id: agentdata-core 50 | worker: core 51 | endpoint: https://your.agentdata.com/ 52 | parameters: 53 | agentdata_db_url: 54 | openai_api_key: 55 | ollama_host: 56 | kaito_api_token: 57 | twitter: 58 | bearer_token: 59 | api_key: 60 | api_secret: 61 | access_token: 62 | access_token_secret: 63 | -------------------------------------------------------------------------------- /internal/engine/task.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "time" 5 | 6 | activityx "github.com/rss3-network/protocol-go/schema/activity" 7 | "github.com/rss3-network/protocol-go/schema/network" 8 | "github.com/samber/lo" 9 | "go.opentelemetry.io/otel/attribute" 10 | "go.opentelemetry.io/otel/propagation" 11 | ) 12 | 13 | type Task interface { 14 | ID() string 15 | GetNetwork() network.Network 16 | GetTimestamp() uint64 17 | Validate() error 18 | BuildActivity(options ...activityx.Option) (*activityx.Activity, error) 19 | } 20 | 21 | func BuildTaskTraceAttributes(task Task) []attribute.KeyValue { 22 | return []attribute.KeyValue{ 23 | attribute.String("task.id", task.ID()), 24 | attribute.Stringer("task.network", task.GetNetwork()), 25 | attribute.Stringer("task.timestamp", time.Unix(int64(task.GetTimestamp()), 0)), 26 | } 27 | } 28 | 29 | var _ propagation.TextMapCarrier = (*Tasks)(nil) 30 | 31 | type Tasks struct { 32 | Tasks []Task 33 | 34 | // metadata is used to store OpenTelemetry trace context. 35 | metadata map[string]string 36 | } 37 | 38 | func (t *Tasks) Get(key string) string { 39 | return t.metadata[key] 40 | } 41 | 42 | func (t *Tasks) Set(key string, value string) { 43 | if t.metadata == nil { 44 | t.metadata = make(map[string]string) 45 | } 46 | 47 | t.metadata[key] = value 48 | } 49 | 50 | func (t *Tasks) Keys() []string { 51 | return lo.Keys(t.metadata) 52 | } 53 | 54 | func (t *Tasks) Len() int { 55 | return len(t.Tasks) 56 | } 57 | -------------------------------------------------------------------------------- /internal/telemetry/meter/meter.go: -------------------------------------------------------------------------------- 1 | package meter 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/labstack/echo/v4" 9 | "github.com/labstack/echo/v4/middleware" 10 | "github.com/prometheus/client_golang/prometheus/promhttp" 11 | "github.com/rss3-network/node/v2/config" 12 | ) 13 | 14 | var ( 15 | ErrorUnsupportedDriver = errors.New("unsupported driver") 16 | ) 17 | 18 | type Driver string 19 | 20 | const ( 21 | DriverPrometheus Driver = "prometheus" 22 | ) 23 | 24 | type Server interface { 25 | Run(config.OpenTelemetryMetricsConfig) error 26 | } 27 | 28 | var _ Server = (*server)(nil) 29 | 30 | type server struct { 31 | httpServer *echo.Echo 32 | } 33 | 34 | func (s *server) Run(config config.OpenTelemetryMetricsConfig) error { 35 | return s.httpServer.Start(config.Endpoint) 36 | } 37 | 38 | func New(driver Driver) (Server, error) { 39 | if driver != DriverPrometheus { 40 | return nil, fmt.Errorf("%w: %s", ErrorUnsupportedDriver, driver) 41 | } 42 | 43 | instance := server{ 44 | httpServer: echo.New(), 45 | } 46 | 47 | instance.httpServer.HideBanner = true 48 | instance.httpServer.HidePort = true 49 | 50 | instance.httpServer.Use(middleware.CORSWithConfig(middleware.DefaultCORSConfig)) 51 | instance.httpServer.GET("/metrics", echo.WrapHandler(promhttp.Handler())) 52 | instance.httpServer.GET("/healthcheck", func(c echo.Context) error { 53 | return c.String(http.StatusOK, "ok") 54 | }) 55 | 56 | return &instance, nil 57 | } 58 | -------------------------------------------------------------------------------- /docs/path/decentralized/account.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | operationId: GetDecentralizedAccount 3 | summary: Get Account Activities 4 | description: This endpoint retrieves the activities associated with a specified account in the decentralized system. You can use various query parameters to filter and paginate the results, including limits on the number of activities and actions, timestamps, success status, direction, and more. 5 | tags: 6 | - Decentralized 7 | security: 8 | - bearerAuth: [] 9 | parameters: 10 | - $ref: "../../parameters/path_account_decentralized.yaml" 11 | - $ref: "../../parameters/query_limit.yaml" 12 | - $ref: "../../parameters/query_action_limit.yaml" 13 | - $ref: "../../parameters/query_cursor.yaml" 14 | - $ref: "../../parameters/query_since_timestamp.yaml" 15 | - $ref: "../../parameters/query_until_timestamp.yaml" 16 | - $ref: "../../parameters/query_success.yaml" 17 | - $ref: "../../parameters/query_direction.yaml" 18 | - $ref: "../../parameters/query_network.yaml" 19 | - $ref: "../../parameters/query_tag.yaml" 20 | - $ref: "../../parameters/query_type.yaml" 21 | - $ref: "../../parameters/query_platform_decentralized.yaml" 22 | responses: 23 | '200': 24 | $ref: "../../responses/DecentralizedActivitiesResponse.yaml" 25 | '400': 26 | $ref: "../../responses/BadRequest.yaml" 27 | '404': 28 | $ref: "../../responses/NotFound.yaml" 29 | '500': 30 | $ref: "../../responses/InternalError.yaml" -------------------------------------------------------------------------------- /docs/schemas/FederatedActivity.yaml: -------------------------------------------------------------------------------- 1 | properties: 2 | id: 3 | description: The unique identifier for the activity. 4 | type: string 5 | format: uri 6 | owner: 7 | $ref: "./FederatedAccount.yaml" 8 | network: 9 | allOf: 10 | - $ref: "./ProtocolNetwork.yaml" 11 | - example: mastodon 12 | index: 13 | description: The index of the activity in the list. 14 | type: integer 15 | from: 16 | $ref: "./FederatedAccount.yaml" 17 | to: 18 | $ref: "./FederatedAccount.yaml" 19 | tag: 20 | allOf: 21 | - $ref: "./ProtocolTag.yaml" 22 | - example: social 23 | type: 24 | $ref: "https://raw.githubusercontent.com/RSS3-Network/Protocol-Go/refs/heads/main/openapi/type/Social.yaml" 25 | platform: 26 | $ref: "./FederatedPlatform.yaml" 27 | total_actions: 28 | description: The total number of actions within the activity. 29 | type: integer 30 | actions: 31 | description: The list of actions within the activity. 32 | items: 33 | $ref: "./FederatedAction.yaml" 34 | type: array 35 | calldata: 36 | $ref: "./Calldata.yaml" 37 | fee: 38 | $ref: "./Fee.yaml" 39 | direction: 40 | $ref: "./ProtocolDirection.yaml" 41 | success: 42 | $ref: "./Success.yaml" 43 | timestamp: 44 | $ref: "./Timestamp.yaml" 45 | 46 | 47 | 48 | type: object 49 | required: 50 | - id 51 | - network 52 | - index 53 | - from 54 | - to 55 | - tag 56 | - type 57 | - total_actions 58 | - actions 59 | - success 60 | - timestamp -------------------------------------------------------------------------------- /internal/engine/worker/ai/core/agentdata/worker.go: -------------------------------------------------------------------------------- 1 | package agentdata 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/rss3-network/node/v2/config" 10 | "github.com/rss3-network/node/v2/internal/engine" 11 | "github.com/rss3-network/protocol-go/schema" 12 | activityx "github.com/rss3-network/protocol-go/schema/activity" 13 | "github.com/rss3-network/protocol-go/schema/network" 14 | "github.com/rss3-network/protocol-go/schema/tag" 15 | ) 16 | 17 | type Worker struct { 18 | config *config.File 19 | httpClient *http.Client 20 | } 21 | 22 | func (w *Worker) Name() string { 23 | return "AgentData" 24 | } 25 | 26 | func (w *Worker) Platform() string { 27 | return "" 28 | } 29 | 30 | func (w *Worker) Network() []network.Network { 31 | return nil 32 | } 33 | 34 | func (w *Worker) Tags() []tag.Tag { 35 | return nil 36 | } 37 | 38 | func (w *Worker) Types() []schema.Type { 39 | return nil 40 | } 41 | 42 | func (w *Worker) Filter() engine.DataSourceFilter { 43 | return nil 44 | } 45 | 46 | func (w *Worker) Transform(_ context.Context, _ engine.Task) (*activityx.Activity, error) { 47 | return nil, nil 48 | } 49 | 50 | func NewWorker(config *config.File) (engine.Worker, error) { 51 | w := &Worker{ 52 | config: config, 53 | httpClient: &http.Client{ 54 | Timeout: 30 * time.Second, 55 | }, 56 | } 57 | 58 | if config.Component.AI == nil { 59 | return nil, fmt.Errorf("missing configuration for Component Agentdata") 60 | } 61 | 62 | return w, nil 63 | } 64 | -------------------------------------------------------------------------------- /provider/ethereum/contract/selector_test.go: -------------------------------------------------------------------------------- 1 | package contract_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ethereum/go-ethereum/common/hexutil" 7 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestMethodID(t *testing.T) { 12 | t.Parallel() 13 | 14 | type arguments struct { 15 | value string 16 | } 17 | 18 | testcases := []struct { 19 | name string 20 | arguments arguments 21 | want require.ValueAssertionFunc 22 | wantError require.ErrorAssertionFunc 23 | }{ 24 | { 25 | name: "implementation()", 26 | arguments: arguments{ 27 | value: "implementation()", 28 | }, 29 | want: func(t require.TestingT, value interface{}, _ ...interface{}) { 30 | methodID, ok := value.(string) 31 | require.True(t, ok) 32 | 33 | require.Equal(t, "0x5c60da1b", methodID) 34 | }, 35 | }, 36 | { 37 | name: "name()", 38 | arguments: arguments{ 39 | value: "name()", 40 | }, 41 | want: func(t require.TestingT, value interface{}, _ ...interface{}) { 42 | methodID, ok := value.(string) 43 | require.True(t, ok) 44 | 45 | require.Equal(t, "0x06fdde03", methodID) 46 | }, 47 | }, 48 | } 49 | 50 | for _, testcase := range testcases { 51 | testcase := testcase 52 | 53 | t.Run(testcase.name, func(t *testing.T) { 54 | t.Parallel() 55 | 56 | result := contract.MethodID(testcase.arguments.value) 57 | testcase.want(t, hexutil.Encode(result[:])) 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /provider/ethereum/contract/weth/contract.go: -------------------------------------------------------------------------------- 1 | package weth 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | "github.com/rss3-network/protocol-go/schema/network" 7 | ) 8 | 9 | // WETH9 https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 10 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/WETH9.abi --pkg weth --type WETH9 --out contract_weth9.go 11 | 12 | var ( 13 | AddressMainnet = common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") 14 | AddressOptimism = common.HexToAddress("0x4200000000000000000000000000000000000006") 15 | AddressGnosis = common.HexToAddress("0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1") 16 | AddressPolygon = common.HexToAddress("0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619") 17 | AddressCelo = common.HexToAddress("0x122013fd7dF1C6F636a5bb8f03108E876548b455") 18 | AddressArbitrumOne = common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1") 19 | AddressAvalanche = common.HexToAddress("0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB") 20 | 21 | EventHashDeposit = contract.EventHash("Deposit(address,uint256)") 22 | EventHashWithdrawal = contract.EventHash("Withdrawal(address,uint256)") 23 | ) 24 | 25 | func IsWETH(chainID uint64, address common.Address) bool { 26 | switch chainID { 27 | case uint64(network.EthereumChainIDMainnet): 28 | return address == AddressMainnet 29 | default: 30 | return false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /provider/ipfs/gateway_test.go: -------------------------------------------------------------------------------- 1 | package ipfs_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/rss3-network/node/v2/provider/ipfs" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestGetGatewayURLs(t *testing.T) { 13 | t.Parallel() 14 | 15 | type arguments struct { 16 | ctx context.Context 17 | timeout time.Duration 18 | gatewayList string 19 | } 20 | 21 | testcases := []struct { 22 | name string 23 | arguments arguments 24 | want require.ValueAssertionFunc 25 | wantError require.ErrorAssertionFunc 26 | }{ 27 | { 28 | name: "Default gateway list", 29 | arguments: arguments{ 30 | ctx: context.Background(), 31 | timeout: ipfs.DefaultTimeout, 32 | gatewayList: ipfs.DefaultGatewayList, 33 | }, 34 | want: func(t require.TestingT, value interface{}, _ ...interface{}) { 35 | gatewayURLs, ok := value.([]string) 36 | require.True(t, ok) 37 | 38 | require.Greater(t, len(gatewayURLs), 0) 39 | }, 40 | wantError: require.NoError, 41 | }, 42 | } 43 | 44 | for _, testcase := range testcases { 45 | testcase := testcase 46 | 47 | t.Run(testcase.name, func(t *testing.T) { 48 | t.Parallel() 49 | 50 | ctx, cancel := context.WithTimeout(testcase.arguments.ctx, testcase.arguments.timeout) 51 | defer cancel() 52 | 53 | gatewayURLs, err := ipfs.FetchGateways(ctx, testcase.arguments.gatewayList) 54 | testcase.wantError(t, err) 55 | testcase.want(t, gatewayURLs) 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /docs/requestBody/BatchGetFederatedAccountsActivities.yaml: -------------------------------------------------------------------------------- 1 | description: Request body for batch retrieving activities for multiple accounts 2 | required: true 3 | content: 4 | application/json: 5 | schema: 6 | type: object 7 | properties: 8 | accounts: 9 | type: array 10 | items: 11 | $ref: "../schemas/FederatedAccount.yaml" 12 | x-go-type-skip-optional-pointer: true 13 | limit: 14 | $ref: "../schemas/Limit.yaml" 15 | action_limit: 16 | $ref: "../schemas/ActionLimit.yaml" 17 | cursor: 18 | $ref: "../schemas/Cursor.yaml" 19 | since_timestamp: 20 | $ref: "../schemas/Timestamp.yaml" 21 | until_timestamp: 22 | $ref: "../schemas/Timestamp.yaml" 23 | success: 24 | $ref: "../schemas/Success.yaml" 25 | direction: 26 | $ref: "../schemas/ProtocolDirection.yaml" 27 | network: 28 | $ref: "../schemas/Networks.yaml" 29 | tag: 30 | $ref: "../schemas/Tags.yaml" 31 | type: 32 | items: 33 | allOf: 34 | - $ref: "../schemas/ProtocolType.yaml" 35 | - x-go-type: string 36 | type: array 37 | x-go-type-skip-optional-pointer: true 38 | platform: 39 | type: array 40 | items: 41 | $ref: "../schemas/FederatedPlatform.yaml" 42 | description: Retrieve activities from the specified platform(s) 43 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /docs/requestBody/BatchGetDecentralizedAccountsActivities.yaml: -------------------------------------------------------------------------------- 1 | description: Request body for batch retrieving activities for multiple accounts 2 | required: true 3 | content: 4 | application/json: 5 | schema: 6 | type: object 7 | properties: 8 | accounts: 9 | type: array 10 | items: 11 | $ref: "../schemas/DecentralizedAccount.yaml" 12 | x-go-type-skip-optional-pointer: true 13 | limit: 14 | $ref: "../schemas/Limit.yaml" 15 | action_limit: 16 | $ref: "../schemas/ActionLimit.yaml" 17 | cursor: 18 | $ref: "../schemas/Cursor.yaml" 19 | since_timestamp: 20 | $ref: "../schemas/Timestamp.yaml" 21 | until_timestamp: 22 | $ref: "../schemas/Timestamp.yaml" 23 | success: 24 | $ref: "../schemas/Success.yaml" 25 | direction: 26 | $ref: "../schemas/ProtocolDirection.yaml" 27 | network: 28 | $ref: "../schemas/Networks.yaml" 29 | tag: 30 | $ref: "../schemas/Tags.yaml" 31 | type: 32 | items: 33 | allOf: 34 | - $ref: "../schemas/ProtocolType.yaml" 35 | - x-go-type: string 36 | type: array 37 | x-go-type-skip-optional-pointer: true 38 | platform: 39 | type: array 40 | items: 41 | $ref: "../schemas/DecentralizedPlatform.yaml" 42 | description: Retrieve activities from the specified platform(s) 43 | x-go-type-skip-optional-pointer: true -------------------------------------------------------------------------------- /internal/database/model/activity.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/rss3-network/node/v2/schema/worker/decentralized" 5 | "github.com/rss3-network/protocol-go/schema" 6 | activityx "github.com/rss3-network/protocol-go/schema/activity" 7 | "github.com/rss3-network/protocol-go/schema/metadata" 8 | "github.com/rss3-network/protocol-go/schema/network" 9 | "github.com/rss3-network/protocol-go/schema/tag" 10 | ) 11 | 12 | type ActivityQuery struct { 13 | ID *string 14 | Network *network.Network 15 | Owner *string 16 | ActionLimit int 17 | ActionPage int 18 | } 19 | 20 | type ActivitiesQuery struct { 21 | Owner *string 22 | Cursor *activityx.Activity 23 | Status *bool 24 | Direction *activityx.Direction 25 | StartTimestamp *uint64 26 | EndTimestamp *uint64 27 | Platform string 28 | Owners []string 29 | Network []network.Network 30 | Tags []tag.Tag 31 | Types []schema.Type 32 | Platforms []string 33 | Distinct *bool 34 | RelatedActions *bool 35 | Limit int 36 | ActionLimit int 37 | } 38 | 39 | type ActivitiesMetadataQuery struct { 40 | Network *network.Network 41 | Platform *decentralized.Platform 42 | Tag *tag.Tag 43 | Type *schema.Type 44 | Accounts []string 45 | Cursor *activityx.Activity 46 | Status *bool 47 | StartTimestamp *uint64 48 | EndTimestamp *uint64 49 | Limit int 50 | ActionLimit int 51 | Metadata *metadata.Metadata 52 | } 53 | -------------------------------------------------------------------------------- /provider/arweave/gateway.go: -------------------------------------------------------------------------------- 1 | package arweave 2 | 3 | //go:generate go run --mod=mod github.com/dmarkham/enumer --values --type=Gateway --linecomment --output gateway_string.go 4 | type Gateway uint 5 | 6 | const ( 7 | GatewayArweave Gateway = iota // https://arweave.net/ 8 | GatewayARIO // https://ar-io.dev/ 9 | GatewayPermagate // https://permagate.io/ 10 | GatewayLove4Src // https://love4src.com/ 11 | GatewayARBR // https://arbr.pro/ 12 | GatewayBobInstein // https://bobinstein.com/ 13 | GatewayAleko0o // https://aleko0o.store/ 14 | GatewaySulapan // https://sulapan.com/ 15 | GatewayFllstck // https://arweave.fllstck.dev/ 16 | GatewayBicem // https://bicem.xyz 17 | GatewayDilsinay // https://dilsinay.online/ 18 | GatewayLostGame // https://lostgame.online/ 19 | GatewayKhalDrogo // https://khaldrogo.site/ 20 | GatewayDasamuka // https://dasamuka.cloud/ 21 | GatewayArendor // http://arendor.xyz/ 22 | GatewayVelaryon // https://velaryon.xyz/ 23 | ) 24 | 25 | var DefaultGateways = []string{ 26 | GatewayArweave.String(), 27 | GatewayARIO.String(), 28 | GatewayPermagate.String(), 29 | GatewayLove4Src.String(), 30 | GatewayARBR.String(), 31 | GatewayBobInstein.String(), 32 | GatewayAleko0o.String(), 33 | GatewaySulapan.String(), 34 | GatewayFllstck.String(), 35 | GatewayBicem.String(), 36 | } 37 | -------------------------------------------------------------------------------- /internal/engine/protocol/farcaster/task.go: -------------------------------------------------------------------------------- 1 | package farcaster 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ethereum/go-ethereum/common" 7 | "github.com/rss3-network/node/v2/internal/engine" 8 | "github.com/rss3-network/node/v2/provider/farcaster" 9 | activityx "github.com/rss3-network/protocol-go/schema/activity" 10 | "github.com/rss3-network/protocol-go/schema/network" 11 | "github.com/rss3-network/protocol-go/schema/typex" 12 | ) 13 | 14 | var _ engine.Task = (*Task)(nil) 15 | 16 | type Task struct { 17 | Network network.Network 18 | Message farcaster.Message 19 | } 20 | 21 | func (t Task) ID() string { 22 | return fmt.Sprintf("%s.%s", t.Network, t.Message.Hash) 23 | } 24 | 25 | func (t Task) GetNetwork() network.Network { 26 | return t.Network 27 | } 28 | 29 | func (t Task) GetTimestamp() uint64 { 30 | return uint64(farcaster.CovertFarcasterTimeToTimestamp(int64(t.Message.Data.Timestamp))) 31 | } 32 | 33 | func (t Task) Validate() error { 34 | return nil 35 | } 36 | 37 | func (t Task) BuildActivity(options ...activityx.Option) (*activityx.Activity, error) { 38 | activity := activityx.Activity{ 39 | ID: common.HexToHash(t.Message.Hash).String(), 40 | Network: t.Network, 41 | Type: typex.Unknown, 42 | Status: true, 43 | Actions: make([]*activityx.Action, 0), 44 | Timestamp: t.GetTimestamp(), 45 | } 46 | 47 | // Apply activity options. 48 | for _, option := range options { 49 | if err := option(&activity); err != nil { 50 | return nil, fmt.Errorf("apply option: %w", err) 51 | } 52 | } 53 | 54 | return &activity, nil 55 | } 56 | -------------------------------------------------------------------------------- /provider/ethereum/contract/arbitrum/abi/L1ERC20Gateway.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"address","name":"_logic","type":"address"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"admin_","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"implementation_","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}] 2 | -------------------------------------------------------------------------------- /internal/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "math/big" 7 | 8 | "github.com/rss3-network/protocol-go/schema" 9 | "github.com/rss3-network/protocol-go/schema/metadata" 10 | "github.com/rss3-network/protocol-go/schema/tag" 11 | ) 12 | 13 | // GetBigInt returns the value if not nil, otherwise returns big.NewInt(0) 14 | func GetBigInt(value *big.Int) *big.Int { 15 | if value == nil { 16 | return big.NewInt(0) 17 | } 18 | 19 | return value 20 | } 21 | 22 | // ParseTypes parses the types and returns the schema types 23 | func ParseTypes(types []string, tags []tag.Tag) ([]schema.Type, error) { 24 | if len(tags) == 0 { 25 | return nil, nil 26 | } 27 | 28 | schemaTypes := make([]schema.Type, 0) 29 | 30 | for _, typex := range types { 31 | var ( 32 | value schema.Type 33 | err error 34 | ) 35 | 36 | for _, tagx := range tags { 37 | value, err = schema.ParseTypeFromString(tagx, typex) 38 | if err == nil { 39 | schemaTypes = append(schemaTypes, value) 40 | 41 | break 42 | } 43 | } 44 | 45 | if err != nil { 46 | return nil, fmt.Errorf("invalid type: %s", typex) 47 | } 48 | } 49 | 50 | return schemaTypes, nil 51 | } 52 | 53 | // ParseMetadata parses the metadata and returns the schema metadata 54 | func ParseMetadata(metadataJSON json.RawMessage, typex schema.Type) (metadata.Metadata, error) { 55 | if len(metadataJSON) == 0 { 56 | return nil, nil 57 | } 58 | 59 | value, err := metadata.Unmarshal(typex, metadataJSON) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | return value, nil 65 | } 66 | -------------------------------------------------------------------------------- /docs/schemas/ComponentInfo.yaml: -------------------------------------------------------------------------------- 1 | example: 2 | decentralized: 3 | - index_count: 1174 4 | indexed_state: 20416808 5 | network: ethereum 6 | platform: VSL 7 | remote_state: 20416809 8 | status: Ready 9 | tags: 10 | - transaction 11 | worker: vsl 12 | worker_id: ethereum-core 13 | - index_count: 2138457 14 | indexed_state: 59974383 15 | network: polygon 16 | platform: Curve 17 | remote_state: 59974392 18 | status: Ready 19 | tags: 20 | - exchange 21 | - transaction 22 | worker: curve 23 | worker_id: polygon-curve 24 | - index_count: 697886 25 | indexed_state: 1475385 26 | network: arweave 27 | platform: Mirror 28 | remote_state: 1475386 29 | status: Ready 30 | tags: 31 | - social 32 | worker: mirror 33 | worker_id: arweave-mirror 34 | federated: 35 | - indexed_state: 0 36 | network: mastodon 37 | platform: mastodon 38 | remote_state: 0 39 | status: Ready 40 | tags: 41 | - social 42 | worker: mastodon 43 | worker_id: mastodon-core 44 | rss: 45 | indexed_state: 0 46 | network: rss 47 | platform: Unknown 48 | remote_state: 0 49 | status: Ready 50 | tags: 51 | - rss 52 | worker: rsshub 53 | properties: 54 | decentralized: 55 | description: The decentralized worker status. 56 | items: 57 | $ref: "./WorkerInfo.yaml" 58 | type: array 59 | federated: 60 | description: The federated worker status. 61 | items: 62 | $ref: "./WorkerInfo.yaml" 63 | type: array 64 | rss: 65 | $ref: "./WorkerInfo.yaml" 66 | type: object 67 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/crossbell/schema.go: -------------------------------------------------------------------------------- 1 | package crossbell 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | ) 7 | 8 | type NoteContent struct { 9 | Type string `json:"type"` 10 | Tags []string `json:"tags"` 11 | Authors []string `json:"authors"` 12 | Title string `json:"title"` 13 | Content string `json:"content"` 14 | Attachments []NoteContentAttachment `json:"attachments"` 15 | Sources []string `json:"sources"` 16 | ExternalUrls []string `json:"external_urls"` 17 | DatePublished time.Time `json:"date_published"` 18 | } 19 | 20 | type NoteContentAttachment struct { 21 | Name string `json:"name"` 22 | Address string `json:"address"` 23 | MimeType string `json:"mime_type"` 24 | SizeInBytes int `json:"size_in_bytes"` 25 | Alt string `json:"alt"` 26 | Width int `json:"width"` 27 | } 28 | 29 | type CharacterURIContent struct { 30 | Avatars []string `json:"avatars"` 31 | Bio string `json:"bio"` 32 | ConnectedAccounts json.RawMessage `json:"connected_accounts"` 33 | Name string `json:"name"` 34 | } 35 | 36 | type ProfileURIContent struct { 37 | ConnectedAccounts json.RawMessage `json:"connected_accounts"` 38 | ConnectedAvatars []string `json:"connected_avatars"` 39 | Name string `json:"name"` 40 | Bio string `json:"bio"` 41 | Type string `json:"type"` 42 | } 43 | -------------------------------------------------------------------------------- /provider/ethereum/contract/polymarket/contract.go: -------------------------------------------------------------------------------- 1 | package polymarket 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // CTF Exchange 9 | // https://polygonscan.com/address/0x4bfb41d5b3570defd03c39a9a4d8de6bd8b8982e 10 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/CTFExchange.abi --pkg polymarket --type CTFExchange --out contract_ctf_exchange.go 11 | // Neg Risk CTF Exchange 12 | // https://polygonscan.com/address/0xc5d563a36ae78145c45a50134d48a1215220f80a 13 | // go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/NegRiskCTFExchange.abi --pkg polymarket --type NegRiskCTFExchange --out contract_neg_risk_ctf_exchange.go 14 | // Condition Tokens 15 | // https://polygonscan.com/address/0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 16 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/ConditionTokens.abi --pkg polymarket --type ConditionTokens --out contract_condition_tokens.go 17 | 18 | var ( 19 | AddressPolyMarketCTFExchange = common.HexToAddress("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E") 20 | AddressPolyMarketNegRiskCTFExchange = common.HexToAddress("0xC5d563A36AE78145C45a50134d48A1215220f80a") 21 | AddressPolyMarketConditionTokens = common.HexToAddress("0x4D97DCd97eC945f40cF65F87097ACe5EA0476045") 22 | 23 | // EventOrderMatched = contract.EventHash("OrdersMatched(bytes32,address,uint256,uint256,uint256,uint256)") 24 | EventOrderFinalized = contract.EventHash("OrderFilled(bytes32,address,address,uint256,uint256,uint256,uint256,uint256)") 25 | ) 26 | -------------------------------------------------------------------------------- /internal/engine/worker/decentralized/contract/nearsocial/schema.go: -------------------------------------------------------------------------------- 1 | package nearsocial 2 | 3 | type FunctionCallArgs struct { 4 | Data map[string]UserContent `json:"data"` 5 | } 6 | 7 | type UserContent struct { 8 | Index map[string]string `json:"index,omitempty"` 9 | Post map[string]string `json:"post,omitempty"` 10 | } 11 | 12 | type IndexData struct { 13 | Key IndexKey `json:"key"` 14 | Value IndexValue `json:"value"` 15 | } 16 | 17 | type RepostIndexData []struct { 18 | Key interface{} `json:"key"` 19 | Value struct { 20 | Type string `json:"type"` 21 | Item *struct { 22 | Type string `json:"type"` 23 | Path string `json:"path"` 24 | BlockHeight int64 `json:"blockHeight"` 25 | } `json:"item,omitempty"` 26 | } `json:"value"` 27 | } 28 | 29 | type IndexKey struct { 30 | Type string `json:"type"` 31 | Path string `json:"path,omitempty"` 32 | BlockHeight int64 `json:"blockHeight,omitempty"` 33 | } 34 | 35 | type IndexValue struct { 36 | Type string `json:"type"` 37 | Path string `json:"path,omitempty"` 38 | Item *Item `json:"item,omitempty"` 39 | } 40 | 41 | type Item struct { 42 | Type string `json:"type"` 43 | Path string `json:"path"` 44 | BlockHeight int64 `json:"blockHeight,omitempty"` 45 | } 46 | 47 | type PostData struct { 48 | Type string `json:"type"` 49 | Text string `json:"text,omitempty"` 50 | Item *Item `json:"item,omitempty"` 51 | } 52 | 53 | type HashtagData struct { 54 | Key string `json:"key"` 55 | Value HashtagValue `json:"value"` 56 | } 57 | 58 | type HashtagValue struct { 59 | Type string `json:"type"` 60 | Path string `json:"path"` 61 | } 62 | -------------------------------------------------------------------------------- /provider/ethereum/contract/rainbow/contract.go: -------------------------------------------------------------------------------- 1 | package rainbow 2 | 3 | import ( 4 | "math/big" 5 | 6 | "github.com/ethereum/go-ethereum/common" 7 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 8 | ) 9 | 10 | // Router https://etherscan.io/address/0x00000000009726632680fb29d3f7a9734e3010e2 11 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/Router.abi --pkg rainbow --type Router --out contract_router.go 12 | 13 | var ( 14 | AddressRouter = common.HexToAddress("0x00000000009726632680FB29d3F7A9734E3010E2") 15 | 16 | MethodIDRouterFillQuoteEthToToken = contract.MethodID("fillQuoteEthToToken(address,address,bytes,uint256)") 17 | MethodIDRouterFillQuoteTokenToEth = contract.MethodID("fillQuoteTokenToEth(address,address,bytes,uint256,uint256)") 18 | MethodIDRouterFillQuoteTokenToToken = contract.MethodID("fillQuoteTokenToToken(address,address,address,bytes,uint256,uint256)") 19 | ) 20 | 21 | type RouterFillQuoteEthToTokenInput struct { 22 | BuyTokenAddress common.Address 23 | Target common.Address 24 | SwapCallData []byte 25 | FeeAmount *big.Int 26 | } 27 | 28 | type RouterFillQuoteTokenToEthInput struct { 29 | SellTokenAddress common.Address 30 | Target common.Address 31 | SwapCallData []byte 32 | SellAmount *big.Int 33 | FeePercentageBasisPoints *big.Int 34 | } 35 | 36 | type RouterFillQuoteTokenToTokenInput struct { 37 | SellTokenAddress common.Address 38 | BuyTokenAddress common.Address 39 | Target common.Address 40 | SwapCallData []byte 41 | SellAmount *big.Int 42 | FeeAmount *big.Int 43 | } 44 | -------------------------------------------------------------------------------- /internal/telemetry/tracer/tracer.go: -------------------------------------------------------------------------------- 1 | package tracer 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | "go.opentelemetry.io/otel/exporters/otlp/otlptrace" 9 | "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" 10 | "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" 11 | "go.opentelemetry.io/otel/sdk/trace" 12 | ) 13 | 14 | type Driver string 15 | 16 | const ( 17 | DriverLocal Driver = "local" 18 | DriverOpenTelemetryProtocol Driver = "otlp" 19 | ) 20 | 21 | func Open(driver Driver, endpoint string, insecure bool) (trace.SpanExporter, error) { 22 | switch driver { 23 | case DriverOpenTelemetryProtocol: 24 | return openOpenTelemetryProtocolExporter(endpoint, insecure) 25 | case DriverLocal: 26 | fallthrough 27 | default: 28 | return openLocalExporter(endpoint, insecure) 29 | } 30 | } 31 | 32 | func openOpenTelemetryProtocolExporter(endpoint string, insecure bool) (exporter trace.SpanExporter, err error) { 33 | options := []otlptracehttp.Option{ 34 | otlptracehttp.WithEndpoint(endpoint), 35 | } 36 | 37 | if insecure { 38 | options = append(options, otlptracehttp.WithInsecure()) 39 | } 40 | 41 | return otlptrace.New(context.Background(), otlptracehttp.NewClient(options...)) 42 | } 43 | 44 | func openLocalExporter(path string, _ bool) (exporter trace.SpanExporter, err error) { 45 | file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModePerm) 46 | if err != nil { 47 | return nil, fmt.Errorf("open local exporter file: %w", err) 48 | } 49 | 50 | return stdouttrace.New( 51 | stdouttrace.WithWriter(file), 52 | stdouttrace.WithPrettyPrint(), 53 | stdouttrace.WithoutTimestamps(), 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /provider/ethereum/contract/ens/contract_test.go: -------------------------------------------------------------------------------- 1 | package ens_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ethereum/go-ethereum/common" 7 | "github.com/rss3-network/node/v2/provider/ethereum/contract/ens" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestNameHash(t *testing.T) { 12 | t.Parallel() 13 | 14 | type arguments struct { 15 | name string 16 | } 17 | 18 | testcases := []struct { 19 | name string 20 | arguments arguments 21 | want common.Hash 22 | }{ 23 | { 24 | name: "vitalik.eth", 25 | arguments: arguments{ 26 | name: "vitalik.eth", 27 | }, 28 | want: common.HexToHash("0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835"), 29 | }, 30 | { 31 | name: "planetable.eth", 32 | arguments: arguments{ 33 | name: "planetable.eth", 34 | }, 35 | want: common.HexToHash("0x7b26d27abaced593c582148f2eb315e57ff6bf40bbf81da5326b3055c395a7bd"), 36 | }, 37 | { 38 | name: "liuguo.eth", 39 | arguments: arguments{ 40 | name: "liuguo.eth", 41 | }, 42 | want: common.HexToHash("0xd9fe12401ccda681464d15a7094bf8f7efc16dcc56d4098c466dd7d0c84030c0"), 43 | }, 44 | { 45 | name: "kallydev.eth", 46 | arguments: arguments{ 47 | name: "kallydev.eth", 48 | }, 49 | want: common.HexToHash("0x8236bd8890989e1af9188cbdad0776c6eb09640f5ab61a70d4171dc066e42f19"), 50 | }, 51 | } 52 | 53 | for _, testcase := range testcases { 54 | testcase := testcase 55 | 56 | t.Run(testcase.name, func(t *testing.T) { 57 | t.Parallel() 58 | 59 | node := ens.NameHash(testcase.arguments.name) 60 | 61 | require.Equal(t, node, testcase.want) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🍭 Feature Request 2 | description: Submit a new feature request 3 | labels: ['enhancement'] 4 | 5 | body: 6 | 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Please ensure the feature requested is not listed in [issue](https://github.com/rss3-network/node/issues), and is not a [New Worker](https://github.com/rss3-network/node/issues/new?assignees=&labels=worker&projects=&template=worker_coverage.yml), and provide all the information required by this template. 11 | Otherwise the issue will be closed immediately. 12 | 13 | - type: textarea 14 | id: feature 15 | attributes: 16 | label: What feature is it? 17 | placeholder: Please describe the feature you want to see. 18 | validations: 19 | required: true 20 | 21 | - type: textarea 22 | id: problem 23 | attributes: 24 | label: What problem does this feature solve? 25 | placeholder: Please describe the problem this feature solves. 26 | validations: 27 | required: true 28 | 29 | - type: textarea 30 | id: description 31 | attributes: 32 | label: Additional description 33 | placeholder: Any additional description. 34 | 35 | - type: checkboxes 36 | id: terms 37 | attributes: 38 | label: This is not a duplicated feature request or new worker proposal 39 | options: 40 | - label: I have searched [existing issues](https://github.com/rss3-network/node/issues) to ensure this feature has not already been requested and this is not a [New Worker](https://github.com/rss3-network/node/issues/new?assignees=&labels=worker&projects=&template=worker_coverage.yml). 41 | required: true 42 | -------------------------------------------------------------------------------- /common/sync/quickgroup_test.go: -------------------------------------------------------------------------------- 1 | package sync 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/samber/lo" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestQuickGroup(t *testing.T) { 13 | t.Parallel() 14 | 15 | quickGroup := NewQuickGroup[time.Duration](context.Background()) 16 | 17 | for duration := time.Second; duration > 0; duration -= 100 * time.Millisecond { 18 | duration := duration 19 | 20 | task := func(ctx context.Context) (time.Duration, error) { 21 | timer := time.NewTimer(duration) 22 | defer timer.Stop() 23 | 24 | select { 25 | case <-ctx.Done(): 26 | t.Logf("Task %s: %s", duration, context.Canceled) 27 | 28 | return duration, context.Canceled 29 | case <-timer.C: 30 | t.Logf("Task %s: %s", duration, "done") 31 | 32 | return duration, nil 33 | } 34 | } 35 | 36 | quickGroup.Go(task) 37 | } 38 | 39 | result, err := quickGroup.Wait() 40 | require.NoError(t, err) 41 | require.Equal(t, result, 100*time.Millisecond) 42 | } 43 | 44 | // TestQuickGroupDataRace checks if any data race exists for QuickGroup. 45 | func TestQuickGroupDataRace(t *testing.T) { 46 | t.Parallel() 47 | 48 | quickGroup := NewQuickGroup[bool](context.Background()) 49 | 50 | for range lo.Range(10000) { 51 | task := func(ctx context.Context) (bool, error) { 52 | timer := time.NewTimer(time.Second) 53 | defer timer.Stop() 54 | 55 | select { 56 | case <-ctx.Done(): 57 | return false, context.Canceled 58 | case <-timer.C: 59 | return true, nil 60 | } 61 | } 62 | 63 | quickGroup.Go(task) 64 | } 65 | 66 | result, err := quickGroup.Wait() 67 | require.NoError(t, err) 68 | require.Equal(t, result, true) 69 | } 70 | -------------------------------------------------------------------------------- /provider/ethereum/contract/benddao/contract.go: -------------------------------------------------------------------------------- 1 | package benddao 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/BendExchange.abi --pkg benddao --type BendExchange --out ./contract_bend_exchange.go 9 | //go:generate go run -mod=mod github.com/ethereum/go-ethereum/cmd/abigen@v1.13.5 --abi ./abi/LendPool.abi --pkg benddao --type LendPool --out ./contract_lend_pool.go 10 | 11 | var ( 12 | AddressBendExchange = common.HexToAddress("0x7e832eC8ad6F66E6C9ECE63acD94516Dd7fC537A") 13 | AddressLendPool = common.HexToAddress("0x70b97A0da65C15dfb0FFA02aEE6FA36e507C2762") 14 | 15 | EventTakerAsk = contract.EventHash("TakerAsk(bytes32,uint256,address,address,address,address,address,uint256,uint256,uint256)") 16 | EventTakerBid = contract.EventHash("TakerBid(bytes32,uint256,address,address,address,address,address,uint256,uint256,uint256)") 17 | 18 | EventDeposit = contract.EventHash("Deposit(address,address,uint256,address,uint16)") 19 | EventWithdraw = contract.EventHash("Withdraw(address,address,uint256,address)") 20 | EventBorrow = contract.EventHash("Borrow(address,address,uint256,address,uint256,address,uint256,uint256,uint16)") 21 | EventRepay = contract.EventHash("Repay(address,address,uint256,address,uint256,address,uint256)") 22 | EventAuction = contract.EventHash("Auction(address,address,uint256,address,uint256,address,address,uint256)") 23 | EventRedeem = contract.EventHash("Redeem(address,address,uint256,uint256,address,uint256,address,uint256)") 24 | EventLiquidate = contract.EventHash("Liquidate(address,address,uint256,uint256,address,uint256,address,uint256)") 25 | ) 26 | -------------------------------------------------------------------------------- /docs/requestBody/BatchGetDecentralizedMetadataActivities.yaml: -------------------------------------------------------------------------------- 1 | description: Request body for batch retrieving activities for specified metadata, network and tag and type is required 2 | required: true 3 | content: 4 | application/json: 5 | schema: 6 | type: object 7 | properties: 8 | accounts: 9 | type: array 10 | items: 11 | $ref: "../schemas/DecentralizedAccount.yaml" 12 | x-go-type-skip-optional-pointer: true 13 | limit: 14 | $ref: "../schemas/Limit.yaml" 15 | action_limit: 16 | $ref: "../schemas/ActionLimit.yaml" 17 | cursor: 18 | $ref: "../schemas/Cursor.yaml" 19 | since_timestamp: 20 | $ref: "../schemas/Timestamp.yaml" 21 | until_timestamp: 22 | $ref: "../schemas/Timestamp.yaml" 23 | success: 24 | $ref: "../schemas/Success.yaml" 25 | network: 26 | type: object 27 | allOf: 28 | - $ref: "../schemas/ProtocolNetwork.yaml" 29 | x-oapi-codegen-extra-tags: 30 | validate: "required" 31 | tag: 32 | type: object 33 | allOf: 34 | - $ref: "../schemas/ProtocolTag.yaml" 35 | x-oapi-codegen-extra-tags: 36 | validate: "required" 37 | type: 38 | type: string 39 | allOf: 40 | - $ref: "../schemas/ProtocolType.yaml" 41 | x-oapi-codegen-extra-tags: 42 | validate: "required" 43 | platform: 44 | $ref: "../schemas/DecentralizedPlatform.yaml" 45 | metadata: 46 | type: object 47 | allOf: 48 | - $ref: "../schemas/ProtocolMetadata.yaml" 49 | x-oapi-codegen-extra-tags: 50 | validate: "required" 51 | -------------------------------------------------------------------------------- /internal/engine/protocol/factory.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/redis/rueidis" 7 | "github.com/rss3-network/node/v2/config" 8 | "github.com/rss3-network/node/v2/internal/database" 9 | "github.com/rss3-network/node/v2/internal/engine" 10 | "github.com/rss3-network/node/v2/internal/engine/protocol/activitypub" 11 | "github.com/rss3-network/node/v2/internal/engine/protocol/arweave" 12 | "github.com/rss3-network/node/v2/internal/engine/protocol/atproto" 13 | "github.com/rss3-network/node/v2/internal/engine/protocol/ethereum" 14 | "github.com/rss3-network/node/v2/internal/engine/protocol/farcaster" 15 | "github.com/rss3-network/node/v2/internal/engine/protocol/near" 16 | "github.com/rss3-network/protocol-go/schema/network" 17 | ) 18 | 19 | // New creates a new protocol. 20 | func New(config *config.Module, sourceFilter engine.DataSourceFilter, checkpoint *engine.Checkpoint, databaseClient database.Client, redisClient rueidis.Client) (engine.DataSource, error) { 21 | switch config.Network.Protocol() { 22 | case network.EthereumProtocol: 23 | return ethereum.NewSource(config, sourceFilter, checkpoint, redisClient) 24 | case network.ArweaveProtocol: 25 | return arweave.NewSource(config, sourceFilter, checkpoint, redisClient) 26 | case network.FarcasterProtocol: 27 | return farcaster.NewSource(config, checkpoint, databaseClient) 28 | case network.ActivityPubProtocol: 29 | return activitypub.NewSource(config, checkpoint, databaseClient) 30 | case network.NearProtocol: 31 | return near.NewSource(config, sourceFilter, checkpoint, redisClient) 32 | case network.ATProtocol: 33 | return atproto.NewSource(config, sourceFilter, checkpoint, databaseClient) 34 | default: 35 | return nil, fmt.Errorf("unsupported network protocol %s", config.Network) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /provider/ethereum/contract/paraswap/contract.go: -------------------------------------------------------------------------------- 1 | package paraswap 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // Paraswap V5 https://etherscan.io/address/0xdef171fe48cf0115b1d80b88dc8eab59176fee57 9 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/V5ParaSwap.abi --pkg paraswap --type V5ParaSwap --out contract_v5_paraswap.go 10 | 11 | // https://developers.paraswap.network/smart-contracts 12 | var ( 13 | AddressV5ParaSwap = common.HexToAddress("0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57") 14 | AddressV5ParaSwapArbitrum = common.HexToAddress("0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57") 15 | AddressV5ParaSwapAvalanche = common.HexToAddress("0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57") 16 | AddressV5ParaSwapBase = common.HexToAddress("0x59C7C832e96D2568bea6db468C1aAdcbbDa08A52") 17 | AddressV5ParaSwapBinanceSmartChain = common.HexToAddress("0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57") 18 | AddressV5ParaSwapOptimism = common.HexToAddress("0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57") 19 | AddressV5ParaSwapPolygon = common.HexToAddress("0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57") 20 | 21 | AddressETH = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") 22 | 23 | EventHashV3Swapped = contract.EventHash("SwappedV3(bytes16,address,uint256,address,address,address,address,uint256,uint256,uint256)") 24 | EventHashV3Bought = contract.EventHash("BoughtV3(bytes16,address,uint256,address,address,address,address,uint256,uint256,uint256)") 25 | EventHashSwappedDirect = contract.EventHash("SwappedDirect(bytes16,address,uint256,address,uint8,address,address,address,uint256,uint256,uint256)") 26 | ) 27 | -------------------------------------------------------------------------------- /provider/ethereum/contract/selector.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/ethereum/go-ethereum/common" 7 | "github.com/ethereum/go-ethereum/crypto" 8 | ) 9 | 10 | // MethodID calculates the method ID of the function selector. 11 | func MethodID(method string) [4]byte { 12 | var ( 13 | methodID [4]byte 14 | hash = crypto.Keccak256Hash([]byte(method)) 15 | ) 16 | 17 | copy(methodID[:], hash[:4]) 18 | 19 | return methodID 20 | } 21 | 22 | // EventHash calculates the event hash of the event signature. 23 | func EventHash(event string) common.Hash { 24 | return crypto.Keccak256Hash([]byte(event)) 25 | } 26 | 27 | // MatchMethodIDs checks if the input matches any of the method IDs. 28 | func MatchMethodIDs(input []byte, methodIDs ...[4]byte) bool { 29 | for _, methodID := range methodIDs { 30 | if bytes.HasPrefix(input, methodID[:]) { 31 | return true 32 | } 33 | } 34 | 35 | return false 36 | } 37 | 38 | // MatchEventHashes checks if the hash matches any of the event hashes. 39 | func MatchEventHashes(hash common.Hash, eventHashes ...common.Hash) bool { 40 | for _, eventHash := range eventHashes { 41 | if hash == eventHash { 42 | return true 43 | } 44 | } 45 | 46 | return false 47 | } 48 | 49 | // MatchAddresses checks if the address matches any of the addresses. 50 | func MatchAddresses(address common.Address, addresses ...common.Address) bool { 51 | for _, addr := range addresses { 52 | if address == addr { 53 | return true 54 | } 55 | } 56 | 57 | return false 58 | } 59 | 60 | // ContainsMethodIDs checks if the code contains all the method IDs. 61 | func ContainsMethodIDs(code []byte, methodIDs ...[4]byte) bool { 62 | for _, methodID := range methodIDs { 63 | if exists := bytes.Contains(code, methodID[:]); !exists { 64 | return exists 65 | } 66 | } 67 | 68 | return true 69 | } 70 | -------------------------------------------------------------------------------- /provider/ipfs/url.go: -------------------------------------------------------------------------------- 1 | package ipfs 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "strings" 7 | 8 | "github.com/ipfs/go-cid" 9 | ) 10 | 11 | func ParseURL(contentURL string) (endpoint, path string, err error) { 12 | parsedURL, err := url.Parse(contentURL) 13 | if err != nil { 14 | return "", "", fmt.Errorf("parse content url: %w", err) 15 | } 16 | 17 | if parsedURL.Scheme == "ipfs" || parsedURL.Scheme == "ipns" { 18 | ipfsCid := parsedURL.Host 19 | urlPath := fmt.Sprintf("%s%s", parsedURL.Host, parsedURL.Path) 20 | 21 | if ipfsCid == "ipfs" { 22 | ipfsCid = strings.Split(parsedURL.Path, "/")[1] 23 | urlPath = parsedURL.Path[1:] 24 | } 25 | 26 | if _, err := cid.Parse(ipfsCid); err != nil { 27 | return "", "", fmt.Errorf("invalid content id %s: %w", ipfsCid, err) 28 | } 29 | 30 | return "", fmt.Sprintf("/%s/%s", parsedURL.Scheme, urlPath), nil 31 | } 32 | 33 | // Path gateway 34 | if strings.HasPrefix(parsedURL.Path, "/ipfs/") || strings.HasPrefix(parsedURL.Path, "/ipns/") { 35 | contentID := strings.TrimPrefix(strings.TrimPrefix(parsedURL.Path, "/ipfs/"), "/ipns/") 36 | 37 | if _, err := cid.Parse(contentID); err != nil { 38 | return "", "", fmt.Errorf("invalid content id %s: %w", contentID, err) 39 | } 40 | 41 | return parsedURL.Host, parsedURL.Path, nil 42 | } 43 | 44 | // Subdomain gateway 45 | if splits := strings.Split(parsedURL.Host, "."); len(splits) >= 4 && (splits[1] == "ipfs" || splits[1] == "ipns") { 46 | contentID := splits[0] 47 | 48 | if _, err := cid.Parse(contentID); err != nil { 49 | return "", "", fmt.Errorf("invalid content id %s: %w", contentID, err) 50 | } 51 | 52 | return strings.Join(splits[2:], "."), fmt.Sprintf("/%s/%s%s", splits[1], contentID, parsedURL.Path), nil 53 | } 54 | 55 | // DNSLink gateway is not supported 56 | 57 | return "", "", fmt.Errorf("invalid content url %s", contentURL) 58 | } 59 | -------------------------------------------------------------------------------- /provider/ethereum/contract/base/contract.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // OptimismPortal 9 | // https://etherscan.io/address/0x49048044D57e1C92A77f79988d21Fa8fAF74E97e 10 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/OptimismPortal.abi --pkg base --type OptimismPortal --out contract_optimism_portal.go 11 | 12 | // L1StandardBridge 13 | // https://etherscan.io/address/0x3154Cf16ccdb4C6d922629664174b904d80F2C35 14 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/L1StandardBridge.abi --pkg base --type L1StandardBridge --out contract_l1_standard_bridge.go 15 | 16 | var ( 17 | AddressOptimismPortal = common.HexToAddress("0x49048044D57e1C92A77f79988d21Fa8fAF74E97e") 18 | AddressL1StandardBridge = common.HexToAddress("0x3154Cf16ccdb4C6d922629664174b904d80F2C35") 19 | AddressL2CrossDomainMessenger = common.HexToAddress("0x4200000000000000000000000000000000000007") 20 | 21 | EventHashOptimismPortalTransactionDeposited = contract.EventHash("TransactionDeposited(address,address,uint256,bytes)") 22 | EventHashOptimismPortalTransactionWithdrawalFinalized = contract.EventHash("WithdrawalFinalized(bytes32,bool)") 23 | 24 | EventHashL1StandardBridgeETHDepositInitiated = contract.EventHash("ETHDepositInitiated(address,address,uint256,bytes)") 25 | EventHashL1StandardBridgeERC20DepositInitiated = contract.EventHash("ERC20DepositInitiated(address,address,address,address,uint256,bytes)") 26 | EventHashL1StandardBridgeETHWithdrawalFinalized = contract.EventHash("ETHWithdrawalFinalized(address,address,uint256,bytes)") 27 | EventHashL1StandardBridgeERC20WithdrawalFinalized = contract.EventHash("ERC20WithdrawalFinalized(address,address,address,address,uint256,bytes)") 28 | ) 29 | -------------------------------------------------------------------------------- /provider/ethereum/contract/nouns/contract.go: -------------------------------------------------------------------------------- 1 | package nouns 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/rss3-network/node/v2/provider/ethereum/contract" 6 | ) 7 | 8 | // NounsAuctionHouseProxy https://etherscan.io/address/0x830BD73E4184ceF73443C15111a1DF14e495C706 9 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/NounsAuctionHouse.abi --pkg nouns --type NounsAuctionHouse --out nouns_auction_house.go 10 | 11 | // NounsDAOProxy https://etherscan.io/address/0x6f3E6272A167e8AcCb32072d08E0957F9c79223d 12 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/NounsDAO.abi --pkg nouns --type NounsDAO --out nouns_dao.go 13 | 14 | // NounsToken https://etherscan.io/address/0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03 15 | //go:generate go run --mod=mod github.com/ethereum/go-ethereum/cmd/abigen --abi ./abi/NounsToken.abi --pkg nouns --type NounsToken --out nouns_token.go 16 | 17 | var ( 18 | AddressNouns = common.HexToAddress("0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03") 19 | AddressNounsAuction = common.HexToAddress("0x830BD73E4184ceF73443C15111a1DF14e495C706") 20 | AddressNounsDAO = common.HexToAddress("0x6f3E6272A167e8AcCb32072d08E0957F9c79223d") 21 | 22 | EventAuctionBid = contract.EventHash("AuctionBid(uint256,address,uint256,bool)") 23 | EventAuctionSettled = contract.EventHash("AuctionSettled(uint256,address,uint256)") 24 | EventAuctionCreated = contract.EventHash("AuctionCreated(uint256,uint256,uint256)") 25 | EventNounCreated = contract.EventHash("NounCreated(uint256,(uint48,uint48,uint48,uint48,uint48))") 26 | EventNounsProposal = contract.EventHash("ProposalCreatedWithRequirements(uint256,address,address[],uint256[],string[],bytes[],uint256,uint256,uint256,uint256,string)") 27 | EventNounsVote = contract.EventHash("VoteCast(address,uint256,uint8,uint256,string)") 28 | ) 29 | -------------------------------------------------------------------------------- /provider/redis/client.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/redis/rueidis" 10 | "github.com/rss3-network/node/v2/config" 11 | ) 12 | 13 | // NewClient creates a new Redis client. 14 | func NewClient(option config.Redis) (rueidis.Client, error) { 15 | clientOption := rueidis.ClientOption{ 16 | InitAddress: []string{option.Endpoint}, 17 | Username: option.Username, 18 | Password: option.Password, 19 | DisableCache: true, 20 | } 21 | 22 | // Enable TLS if it is configured 23 | if option.TLS.Enabled { 24 | tlsConfig, err := buildTLSConfig(option.TLS) 25 | if err != nil { 26 | return nil, fmt.Errorf("failed to build TLS config: %w", err) 27 | } 28 | 29 | clientOption.TLSConfig = tlsConfig 30 | } 31 | 32 | return rueidis.NewClient(clientOption) 33 | } 34 | 35 | // buildTLSConfig builds a TLS configuration from the given TLS configuration. 36 | func buildTLSConfig(tlsConfig config.RedisTLS) (*tls.Config, error) { 37 | tlsConf := &tls.Config{ 38 | MinVersion: tls.VersionTLS12, // Set minimum TLS version to 1.2 to address G402 warning 39 | } 40 | 41 | if tlsConfig.CAFile != "" { 42 | caCert, err := os.ReadFile(tlsConfig.CAFile) 43 | if err != nil { 44 | return nil, fmt.Errorf("failed to read CA certificate file: %w", err) 45 | } 46 | 47 | caCertPool := x509.NewCertPool() 48 | caCertPool.AppendCertsFromPEM(caCert) 49 | tlsConf.RootCAs = caCertPool 50 | } 51 | 52 | if tlsConfig.CertFile != "" && tlsConfig.KeyFile != "" { 53 | cert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile) 54 | if err != nil { 55 | return nil, fmt.Errorf("failed to load client certificate and key: %w", err) 56 | } 57 | 58 | tlsConf.Certificates = []tls.Certificate{cert} 59 | } 60 | 61 | tlsConf.InsecureSkipVerify = tlsConfig.InsecureSkipVerify 62 | 63 | return tlsConf, nil 64 | } 65 | -------------------------------------------------------------------------------- /provider/near/client_test.go: -------------------------------------------------------------------------------- 1 | package near_test 2 | 3 | // func TestNearClient(t *testing.T) { 4 | // t.Parallel() 5 | // 6 | // ctx := context.Background() 7 | // endpoint := "https://archival-rpc.mainnet.near.org" 8 | // 9 | // client, err := near.Dial(ctx, endpoint) 10 | // require.NoError(t, err) 11 | // 12 | // t.Run("GetBlockHeight", func(t *testing.T) { 13 | // t.Parallel() 14 | // 15 | // blockHeight, err := client.GetBlockHeight(ctx) 16 | // 17 | // require.NoError(t, err) 18 | // require.Greater(t, blockHeight, int64(0)) 19 | // }) 20 | // 21 | // t.Run("BlockByHeight", func(t *testing.T) { 22 | // t.Parallel() 23 | // 24 | // blockHeight := big.NewInt(127103648) 25 | // block, err := client.BlockByHeight(ctx, blockHeight) 26 | // 27 | // require.NoError(t, err) 28 | // require.NotNil(t, block) 29 | // require.Equal(t, 127103648, block.Header.Height) 30 | // }) 31 | // 32 | // t.Run("ChunkByHash", func(t *testing.T) { 33 | // t.Parallel() 34 | // 35 | // chunkID := "GWAab7TDaf5T8dfgJ2YrHHXgdEpJUdUS1Hmie2N2aWhw" 36 | // chunk, err := client.ChunkByHash(ctx, chunkID) 37 | // 38 | // require.NoError(t, err) 39 | // require.NotNil(t, chunk) 40 | // require.Equal(t, chunkID, chunk.Header.ChunkHash) 41 | // }) 42 | // 43 | // t.Run("ChunkByHeight", func(t *testing.T) { 44 | // t.Parallel() 45 | // 46 | // blockHeight := big.NewInt(127170738) 47 | // shardID := 0 48 | // chunk, err := client.ChunkByHeight(ctx, blockHeight, shardID) 49 | // 50 | // require.NoError(t, err) 51 | // require.NotNil(t, chunk) 52 | // }) 53 | // 54 | // t.Run("TransactionByHash", func(t *testing.T) { 55 | // t.Parallel() 56 | // 57 | // txHash := "9JCqrdN53VXiAVo9feEHY7FigiV1QYSyYuoXeTuee4eA" 58 | // senderID := "pseudoyu.tg" 59 | // tx, err := client.TransactionByHash(ctx, txHash, senderID) 60 | // 61 | // require.NoError(t, err) 62 | // require.NotNil(t, tx) 63 | // require.Equal(t, txHash, tx.Transaction.Hash) 64 | // }) 65 | //} 66 | -------------------------------------------------------------------------------- /internal/engine/protocol/near/option.go: -------------------------------------------------------------------------------- 1 | package near 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "time" 7 | 8 | "github.com/rss3-network/node/v2/config" 9 | "github.com/rss3-network/node/v2/config/parameter" 10 | "github.com/rss3-network/protocol-go/schema/network" 11 | "github.com/samber/lo" 12 | ) 13 | 14 | const ( 15 | defaultConcurrentBlockRequests = uint64(8) 16 | defaultRetryAttempts = uint(10) 17 | defaultRetryDelay = 500 * time.Millisecond 18 | ) 19 | 20 | type Option struct { 21 | // BlockStart is the block height on Arweave that the worker should start from. 22 | BlockStart *big.Int `json:"block_start" mapstructure:"block_start"` 23 | // BlockTarget is the block height on Arweave that the worker should stop at. 24 | BlockTarget *big.Int `json:"block_target" mapstructure:"block_target"` 25 | // ConcurrentBlockRequests is the number of blocks to request concurrently. 26 | ConcurrentBlockRequests *uint64 `json:"concurrent_block_requests" mapstructure:"concurrent_block_requests"` 27 | } 28 | 29 | func NewOption(n network.Network, parameters *config.Parameters) (*Option, error) { 30 | var option Option 31 | 32 | if parameters == nil { 33 | return &Option{ 34 | BlockStart: parameter.CurrentNetworkStartBlock[n].Block, 35 | ConcurrentBlockRequests: lo.ToPtr(defaultConcurrentBlockRequests), 36 | }, nil 37 | } 38 | 39 | if err := parameters.Decode(&option); err != nil { 40 | return nil, err 41 | } 42 | 43 | // Set default values. 44 | if option.ConcurrentBlockRequests == nil { 45 | option.ConcurrentBlockRequests = lo.ToPtr(defaultConcurrentBlockRequests) 46 | } 47 | 48 | if *option.ConcurrentBlockRequests == 0 { 49 | return nil, fmt.Errorf("concurrent block requests must be greater than 0") 50 | } 51 | 52 | if option.BlockStart == nil { 53 | option.BlockStart = parameter.CurrentNetworkStartBlock[n].Block 54 | } 55 | 56 | return &option, nil 57 | } 58 | --------------------------------------------------------------------------------