diff --git a/api/Makefile b/api/Makefile new file mode 100644 index 00000000..dc9d1298 --- /dev/null +++ b/api/Makefile @@ -0,0 +1,21 @@ +SHELL := /bin/bash + + +## help: print this help message +.PHONY: help +help: + @echo 'Usage:' + @sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /' + +build: + go build -o api main.go + +doc: + swag init -pd + + +test: + go test -v -cover ./... + + +.PHONY: build doc test diff --git a/api/README.md b/api/README.md new file mode 100644 index 00000000..56fb696b --- /dev/null +++ b/api/README.md @@ -0,0 +1,38 @@ +# API + +## How to build + +```bash +make build +``` + +## Config + +You will need to set some env variables with the prefix `WORMSCAN` + +- WORMSCAN_DB_MONGO +- WORMSCAN_DB_NAME +- WORMSCAN_PORT + +for example: + +```bash +WORMSCAN_DB_URL=mongodb://localhost:27017/wormhole WORMSCAN_PORT=5555 ./api +``` + +## API Documentation + +Documentation is automagically generated via swaggo using annotations on code +and placed inside `doc/` folder. + +To install swag tool run this + +```bash +go install github.com/swaggo/swag/cmd/swag@latest +``` + +To generate or update the doc run: + +```bash +make doc +``` \ No newline at end of file diff --git a/api/docs/docs.go b/api/docs/docs.go new file mode 100644 index 00000000..ae009df7 --- /dev/null +++ b/api/docs/docs.go @@ -0,0 +1,559 @@ +// Package docs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "termsOfService": "https://wormhole.com/", + "contact": { + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/v1/governor/available_notional_by_chain": { + "get": { + "description": "Get available notional by chainID\nSince from the wormhole-explorer point of view it is not a node, but has the information of all nodes,\nin order to build the endpoints it was assumed:\nThere are N number of remainingAvailableNotional values in the GovernorConfig collection. N = number of guardians\nfor a chainID. The smallest remainingAvailableNotional value for a chainID is used for the endpoint response.", + "tags": [ + "Guardian" + ], + "operationId": "governor-available-notional-by-chain", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/governor.AvailableNotionalResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/governor/enqueued_vaas": { + "get": { + "description": "Get enqueued vaa's", + "tags": [ + "Guardian" + ], + "operationId": "guardians-enqueued-vaas", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/governor.EnqueuedVaaResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/governor/is_vaa_enqueued/{chain_id}/{emitter}/{seq}": { + "get": { + "description": "Check if vaa is enqueued", + "tags": [ + "Guardian" + ], + "operationId": "guardians-is-vaa-enqueued", + "parameters": [ + { + "type": "integer", + "description": "id of the blockchain", + "name": "chain_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "address of the emitter", + "name": "emitter", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "sequence of the vaa", + "name": "seq", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/governor.EnqueuedVaaResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/governor/token_list": { + "get": { + "description": "Get token list\nSince from the wormhole-explorer point of view it is not a node, but has the information of all nodes,\nin order to build the endpoints it was assumed:\nFor tokens with the same originChainId and originAddress and different price values for each node,\nthe price that has most occurrences in all the nodes for an originChainId and originAddress is returned.", + "tags": [ + "Guardian" + ], + "operationId": "guardians-token-list", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/governor.TokenList" + } + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/guardianset/current": { + "get": { + "description": "Get current guardian set.", + "tags": [ + "Guardian" + ], + "operationId": "guardian-set", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/guardian.GuardianSetResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/heartbeats": { + "get": { + "description": "Get heartbeats for guardians", + "tags": [ + "Guardian" + ], + "operationId": "guardians-hearbeats", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/heartbeats.HeartbeatsResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/signed_batch_vaa/{chain_id}/{emitter}/sequence/{seq}": { + "get": { + "description": "get a batch of VAA []byte from a chainID, emitter address and sequence.", + "tags": [ + "Guardian" + ], + "operationId": "guardians-find-signed-batch-vaa", + "parameters": [ + { + "type": "integer", + "description": "id of the blockchain", + "name": "chain_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "address of the emitter", + "name": "emitter", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "sequence of the vaa", + "name": "seq", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "type": "object" + }, + { + "type": "object", + "properties": { + "vaaBytes": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/signed_vaa/{chain_id}/{emitter}/{seq}": { + "get": { + "description": "get a VAA []byte from a chainID, emitter address and sequence.", + "tags": [ + "Guardian" + ], + "operationId": "guardians-find-signed-vaa", + "parameters": [ + { + "type": "integer", + "description": "id of the blockchain", + "name": "chain_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "address of the emitter", + "name": "emitter", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "sequence of the vaa", + "name": "seq", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "type": "object" + }, + { + "type": "object", + "properties": { + "vaaBytes": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } + }, + "definitions": { + "governor.AvailableNotionalItemResponse": { + "type": "object", + "properties": { + "bigTransactionSize": { + "type": "string" + }, + "chainId": { + "$ref": "#/definitions/vaa.ChainID" + }, + "notionalLimit": { + "type": "string" + }, + "remainingAvailableNotional": { + "type": "string" + } + } + }, + "governor.AvailableNotionalResponse": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/governor.AvailableNotionalItemResponse" + } + } + } + }, + "governor.EnqueuedVaaItemResponse": { + "type": "object", + "properties": { + "emitterAddress": { + "type": "string" + }, + "emitterChain": { + "$ref": "#/definitions/vaa.ChainID" + }, + "notionalValue": { + "type": "string" + }, + "releaseTime": { + "type": "integer" + }, + "sequence": { + "type": "integer" + }, + "txHash": { + "type": "string" + } + } + }, + "governor.EnqueuedVaaResponse": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/governor.EnqueuedVaaItemResponse" + } + } + } + }, + "governor.TokenList": { + "type": "object", + "properties": { + "originAddress": { + "type": "string" + }, + "originChainId": { + "$ref": "#/definitions/vaa.ChainID" + }, + "price": { + "type": "number" + } + } + }, + "guardian.GuardianSet": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "index": { + "type": "integer" + } + } + }, + "guardian.GuardianSetResponse": { + "type": "object", + "properties": { + "guardianSet": { + "$ref": "#/definitions/guardian.GuardianSet" + } + } + }, + "heartbeats.HeartbeatNetworkResponse": { + "type": "object", + "properties": { + "contractAddress": { + "type": "string" + }, + "errorCount": { + "type": "string" + }, + "height": { + "type": "string" + }, + "id": { + "type": "integer" + } + } + }, + "heartbeats.HeartbeatResponse": { + "type": "object", + "properties": { + "p2pNodeAddr": { + "type": "string" + }, + "rawHeartbeat": { + "$ref": "#/definitions/heartbeats.RawHeartbeat" + }, + "verifiedGuardianAddr": { + "type": "string" + } + } + }, + "heartbeats.HeartbeatsResponse": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/heartbeats.HeartbeatResponse" + } + } + } + }, + "heartbeats.RawHeartbeat": { + "type": "object", + "properties": { + "bootTimestamp": { + "type": "string" + }, + "counter": { + "type": "integer" + }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, + "guardianAddr": { + "type": "string" + }, + "networks": { + "type": "array", + "items": { + "$ref": "#/definitions/heartbeats.HeartbeatNetworkResponse" + } + }, + "nodeName": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "vaa.ChainID": { + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 26, + 10001 + ], + "x-enum-varnames": [ + "ChainIDUnset", + "ChainIDSolana", + "ChainIDEthereum", + "ChainIDTerra", + "ChainIDBSC", + "ChainIDPolygon", + "ChainIDAvalanche", + "ChainIDOasis", + "ChainIDAlgorand", + "ChainIDAurora", + "ChainIDFantom", + "ChainIDKarura", + "ChainIDAcala", + "ChainIDKlaytn", + "ChainIDCelo", + "ChainIDNear", + "ChainIDMoonbeam", + "ChainIDNeon", + "ChainIDTerra2", + "ChainIDInjective", + "ChainIDPythNet", + "ChainIDEthereumRopsten" + ] + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "/v1", + Schemes: []string{}, + Title: "Wormhole Guardian API", + Description: "Wormhole Guardian API\n\nIt is used to provide a way to interact with the Wormhole Network.\nCheck each endpoint documentation for more information.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/api/docs/swagger.json b/api/docs/swagger.json new file mode 100644 index 00000000..1e1f1821 --- /dev/null +++ b/api/docs/swagger.json @@ -0,0 +1,535 @@ +{ + "swagger": "2.0", + "info": { + "description": "Wormhole Guardian API\n\nIt is used to provide a way to interact with the Wormhole Network.\nCheck each endpoint documentation for more information.", + "title": "Wormhole Guardian API", + "termsOfService": "https://wormhole.com/", + "contact": { + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0" + }, + "basePath": "/v1", + "paths": { + "/v1/governor/available_notional_by_chain": { + "get": { + "description": "Get available notional by chainID\nSince from the wormhole-explorer point of view it is not a node, but has the information of all nodes,\nin order to build the endpoints it was assumed:\nThere are N number of remainingAvailableNotional values in the GovernorConfig collection. N = number of guardians\nfor a chainID. The smallest remainingAvailableNotional value for a chainID is used for the endpoint response.", + "tags": [ + "Guardian" + ], + "operationId": "governor-available-notional-by-chain", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/governor.AvailableNotionalResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/governor/enqueued_vaas": { + "get": { + "description": "Get enqueued vaa's", + "tags": [ + "Guardian" + ], + "operationId": "guardians-enqueued-vaas", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/governor.EnqueuedVaaResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/governor/is_vaa_enqueued/{chain_id}/{emitter}/{seq}": { + "get": { + "description": "Check if vaa is enqueued", + "tags": [ + "Guardian" + ], + "operationId": "guardians-is-vaa-enqueued", + "parameters": [ + { + "type": "integer", + "description": "id of the blockchain", + "name": "chain_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "address of the emitter", + "name": "emitter", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "sequence of the vaa", + "name": "seq", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/governor.EnqueuedVaaResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/governor/token_list": { + "get": { + "description": "Get token list\nSince from the wormhole-explorer point of view it is not a node, but has the information of all nodes,\nin order to build the endpoints it was assumed:\nFor tokens with the same originChainId and originAddress and different price values for each node,\nthe price that has most occurrences in all the nodes for an originChainId and originAddress is returned.", + "tags": [ + "Guardian" + ], + "operationId": "guardians-token-list", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/governor.TokenList" + } + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/guardianset/current": { + "get": { + "description": "Get current guardian set.", + "tags": [ + "Guardian" + ], + "operationId": "guardian-set", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/guardian.GuardianSetResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/heartbeats": { + "get": { + "description": "Get heartbeats for guardians", + "tags": [ + "Guardian" + ], + "operationId": "guardians-hearbeats", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/heartbeats.HeartbeatsResponse" + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/signed_batch_vaa/{chain_id}/{emitter}/sequence/{seq}": { + "get": { + "description": "get a batch of VAA []byte from a chainID, emitter address and sequence.", + "tags": [ + "Guardian" + ], + "operationId": "guardians-find-signed-batch-vaa", + "parameters": [ + { + "type": "integer", + "description": "id of the blockchain", + "name": "chain_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "address of the emitter", + "name": "emitter", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "sequence of the vaa", + "name": "seq", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "type": "object" + }, + { + "type": "object", + "properties": { + "vaaBytes": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/v1/signed_vaa/{chain_id}/{emitter}/{seq}": { + "get": { + "description": "get a VAA []byte from a chainID, emitter address and sequence.", + "tags": [ + "Guardian" + ], + "operationId": "guardians-find-signed-vaa", + "parameters": [ + { + "type": "integer", + "description": "id of the blockchain", + "name": "chain_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "address of the emitter", + "name": "emitter", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "sequence of the vaa", + "name": "seq", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "type": "object" + }, + { + "type": "object", + "properties": { + "vaaBytes": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } + }, + "definitions": { + "governor.AvailableNotionalItemResponse": { + "type": "object", + "properties": { + "bigTransactionSize": { + "type": "string" + }, + "chainId": { + "$ref": "#/definitions/vaa.ChainID" + }, + "notionalLimit": { + "type": "string" + }, + "remainingAvailableNotional": { + "type": "string" + } + } + }, + "governor.AvailableNotionalResponse": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/governor.AvailableNotionalItemResponse" + } + } + } + }, + "governor.EnqueuedVaaItemResponse": { + "type": "object", + "properties": { + "emitterAddress": { + "type": "string" + }, + "emitterChain": { + "$ref": "#/definitions/vaa.ChainID" + }, + "notionalValue": { + "type": "string" + }, + "releaseTime": { + "type": "integer" + }, + "sequence": { + "type": "integer" + }, + "txHash": { + "type": "string" + } + } + }, + "governor.EnqueuedVaaResponse": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/governor.EnqueuedVaaItemResponse" + } + } + } + }, + "governor.TokenList": { + "type": "object", + "properties": { + "originAddress": { + "type": "string" + }, + "originChainId": { + "$ref": "#/definitions/vaa.ChainID" + }, + "price": { + "type": "number" + } + } + }, + "guardian.GuardianSet": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "index": { + "type": "integer" + } + } + }, + "guardian.GuardianSetResponse": { + "type": "object", + "properties": { + "guardianSet": { + "$ref": "#/definitions/guardian.GuardianSet" + } + } + }, + "heartbeats.HeartbeatNetworkResponse": { + "type": "object", + "properties": { + "contractAddress": { + "type": "string" + }, + "errorCount": { + "type": "string" + }, + "height": { + "type": "string" + }, + "id": { + "type": "integer" + } + } + }, + "heartbeats.HeartbeatResponse": { + "type": "object", + "properties": { + "p2pNodeAddr": { + "type": "string" + }, + "rawHeartbeat": { + "$ref": "#/definitions/heartbeats.RawHeartbeat" + }, + "verifiedGuardianAddr": { + "type": "string" + } + } + }, + "heartbeats.HeartbeatsResponse": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/heartbeats.HeartbeatResponse" + } + } + } + }, + "heartbeats.RawHeartbeat": { + "type": "object", + "properties": { + "bootTimestamp": { + "type": "string" + }, + "counter": { + "type": "integer" + }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, + "guardianAddr": { + "type": "string" + }, + "networks": { + "type": "array", + "items": { + "$ref": "#/definitions/heartbeats.HeartbeatNetworkResponse" + } + }, + "nodeName": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "vaa.ChainID": { + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 26, + 10001 + ], + "x-enum-varnames": [ + "ChainIDUnset", + "ChainIDSolana", + "ChainIDEthereum", + "ChainIDTerra", + "ChainIDBSC", + "ChainIDPolygon", + "ChainIDAvalanche", + "ChainIDOasis", + "ChainIDAlgorand", + "ChainIDAurora", + "ChainIDFantom", + "ChainIDKarura", + "ChainIDAcala", + "ChainIDKlaytn", + "ChainIDCelo", + "ChainIDNear", + "ChainIDMoonbeam", + "ChainIDNeon", + "ChainIDTerra2", + "ChainIDInjective", + "ChainIDPythNet", + "ChainIDEthereumRopsten" + ] + } + } +} \ No newline at end of file diff --git a/api/docs/swagger.yaml b/api/docs/swagger.yaml new file mode 100644 index 00000000..32f5134a --- /dev/null +++ b/api/docs/swagger.yaml @@ -0,0 +1,375 @@ +basePath: /v1 +definitions: + governor.AvailableNotionalItemResponse: + properties: + bigTransactionSize: + type: string + chainId: + $ref: '#/definitions/vaa.ChainID' + notionalLimit: + type: string + remainingAvailableNotional: + type: string + type: object + governor.AvailableNotionalResponse: + properties: + entries: + items: + $ref: '#/definitions/governor.AvailableNotionalItemResponse' + type: array + type: object + governor.EnqueuedVaaItemResponse: + properties: + emitterAddress: + type: string + emitterChain: + $ref: '#/definitions/vaa.ChainID' + notionalValue: + type: string + releaseTime: + type: integer + sequence: + type: integer + txHash: + type: string + type: object + governor.EnqueuedVaaResponse: + properties: + entries: + items: + $ref: '#/definitions/governor.EnqueuedVaaItemResponse' + type: array + type: object + governor.TokenList: + properties: + originAddress: + type: string + originChainId: + $ref: '#/definitions/vaa.ChainID' + price: + type: number + type: object + guardian.GuardianSet: + properties: + addresses: + items: + type: string + type: array + index: + type: integer + type: object + guardian.GuardianSetResponse: + properties: + guardianSet: + $ref: '#/definitions/guardian.GuardianSet' + type: object + heartbeats.HeartbeatNetworkResponse: + properties: + contractAddress: + type: string + errorCount: + type: string + height: + type: string + id: + type: integer + type: object + heartbeats.HeartbeatResponse: + properties: + p2pNodeAddr: + type: string + rawHeartbeat: + $ref: '#/definitions/heartbeats.RawHeartbeat' + verifiedGuardianAddr: + type: string + type: object + heartbeats.HeartbeatsResponse: + properties: + entries: + items: + $ref: '#/definitions/heartbeats.HeartbeatResponse' + type: array + type: object + heartbeats.RawHeartbeat: + properties: + bootTimestamp: + type: string + counter: + type: integer + features: + items: + type: string + type: array + guardianAddr: + type: string + networks: + items: + $ref: '#/definitions/heartbeats.HeartbeatNetworkResponse' + type: array + nodeName: + type: string + timestamp: + type: string + version: + type: string + type: object + vaa.ChainID: + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 26 + - 10001 + type: integer + x-enum-varnames: + - ChainIDUnset + - ChainIDSolana + - ChainIDEthereum + - ChainIDTerra + - ChainIDBSC + - ChainIDPolygon + - ChainIDAvalanche + - ChainIDOasis + - ChainIDAlgorand + - ChainIDAurora + - ChainIDFantom + - ChainIDKarura + - ChainIDAcala + - ChainIDKlaytn + - ChainIDCelo + - ChainIDNear + - ChainIDMoonbeam + - ChainIDNeon + - ChainIDTerra2 + - ChainIDInjective + - ChainIDPythNet + - ChainIDEthereumRopsten +info: + contact: + email: support@swagger.io + name: API Support + url: http://www.swagger.io/support + description: |- + Wormhole Guardian API + + It is used to provide a way to interact with the Wormhole Network. + Check each endpoint documentation for more information. + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://wormhole.com/ + title: Wormhole Guardian API + version: "1.0" +paths: + /v1/governor/available_notional_by_chain: + get: + description: |- + Get available notional by chainID + Since from the wormhole-explorer point of view it is not a node, but has the information of all nodes, + in order to build the endpoints it was assumed: + There are N number of remainingAvailableNotional values in the GovernorConfig collection. N = number of guardians + for a chainID. The smallest remainingAvailableNotional value for a chainID is used for the endpoint response. + operationId: governor-available-notional-by-chain + responses: + "200": + description: OK + schema: + $ref: '#/definitions/governor.AvailableNotionalResponse' + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/governor/enqueued_vaas: + get: + description: Get enqueued vaa's + operationId: guardians-enqueued-vaas + responses: + "200": + description: OK + schema: + $ref: '#/definitions/governor.EnqueuedVaaResponse' + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/governor/is_vaa_enqueued/{chain_id}/{emitter}/{seq}: + get: + description: Check if vaa is enqueued + operationId: guardians-is-vaa-enqueued + parameters: + - description: id of the blockchain + in: path + name: chain_id + required: true + type: integer + - description: address of the emitter + in: path + name: emitter + required: true + type: string + - description: sequence of the vaa + in: path + name: seq + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/governor.EnqueuedVaaResponse' + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/governor/token_list: + get: + description: |- + Get token list + Since from the wormhole-explorer point of view it is not a node, but has the information of all nodes, + in order to build the endpoints it was assumed: + For tokens with the same originChainId and originAddress and different price values for each node, + the price that has most occurrences in all the nodes for an originChainId and originAddress is returned. + operationId: guardians-token-list + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/governor.TokenList' + type: array + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/guardianset/current: + get: + description: Get current guardian set. + operationId: guardian-set + responses: + "200": + description: OK + schema: + $ref: '#/definitions/guardian.GuardianSetResponse' + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/heartbeats: + get: + description: Get heartbeats for guardians + operationId: guardians-hearbeats + responses: + "200": + description: OK + schema: + $ref: '#/definitions/heartbeats.HeartbeatsResponse' + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/signed_batch_vaa/{chain_id}/{emitter}/sequence/{seq}: + get: + description: get a batch of VAA []byte from a chainID, emitter address and sequence. + operationId: guardians-find-signed-batch-vaa + parameters: + - description: id of the blockchain + in: path + name: chain_id + required: true + type: integer + - description: address of the emitter + in: path + name: emitter + required: true + type: string + - description: sequence of the vaa + in: path + name: seq + required: true + type: integer + responses: + "200": + description: OK + schema: + allOf: + - type: object + - properties: + vaaBytes: + items: + type: integer + type: array + type: object + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian + /v1/signed_vaa/{chain_id}/{emitter}/{seq}: + get: + description: get a VAA []byte from a chainID, emitter address and sequence. + operationId: guardians-find-signed-vaa + parameters: + - description: id of the blockchain + in: path + name: chain_id + required: true + type: integer + - description: address of the emitter + in: path + name: emitter + required: true + type: string + - description: sequence of the vaa + in: path + name: seq + required: true + type: integer + responses: + "200": + description: OK + schema: + allOf: + - type: object + - properties: + vaaBytes: + items: + type: integer + type: array + type: object + "400": + description: Bad Request + "500": + description: Internal Server Error + tags: + - Guardian +swagger: "2.0" diff --git a/api/handlers/governor/controller.go b/api/handlers/governor/controller.go index d636ffbb..5d2a830a 100644 --- a/api/handlers/governor/controller.go +++ b/api/handlers/governor/controller.go @@ -177,12 +177,18 @@ type AvailableNotionalItemResponse struct { MaxTransactionSize string `json:"bigTransactionSize"` } -// GetAvailNotionByChain handler for the endpoint /guardian_public_api/v1/governor/available_notional_by_chain -// This endpoint has been migrated from the guardian grpc api. -// Since from the wormhole-explorer point of view it is not a node, but has the information of all nodes, -// in order to build the endpoints it was assumed: -// There are N number of remainingAvailableNotional values in the GovernorConfig collection. N = number of guardians -// for a chainID. The smallest remainingAvailableNotional value for a chainID is used for the endpoint response. +// GetAvailNotionByChain godoc +// @Description Get available notional by chainID +// @Description Since from the wormhole-explorer point of view it is not a node, but has the information of all nodes, +// @Description in order to build the endpoints it was assumed: +// @Description There are N number of remainingAvailableNotional values in the GovernorConfig collection. N = number of guardians +// @Description for a chainID. The smallest remainingAvailableNotional value for a chainID is used for the endpoint response. +// @Tags Guardian +// @ID governor-available-notional-by-chain +// @Success 200 {object} AvailableNotionalResponse +// @Failure 400 +// @Failure 500 +// @Router /v1/governor/available_notional_by_chain [get] func (c *Controller) GetAvailNotionByChain(ctx *fiber.Ctx) error { // call service to get available notional by chainID availableNotional, err := c.srv.GetAvailNotionByChain(ctx.Context()) @@ -221,9 +227,14 @@ type EnqueuedVaaItemResponse struct { TxHash string `json:"txHash"` } -// GetEnqueuedVaas handler for the endpoint /guardian_public_api/v1/governor/enqueued_vaas -// This endpoint has been migrated from the guardian grpc api. -// The endpoint returns the enqueued VAA for all guardian nodes. +// GetEnqueuedVaas godoc +// @Description Get enqueued vaa's +// @Tags Guardian +// @ID guardians-enqueued-vaas +// @Success 200 {object} EnqueuedVaaResponse +// @Failure 400 +// @Failure 500 +// @Router /v1/governor/enqueued_vaas [get] func (c *Controller) GetEnqueuedVaas(ctx *fiber.Ctx) error { enqueuedVaa, err := c.srv.GetEnqueuedVaas(ctx.Context()) if err != nil { @@ -254,8 +265,17 @@ func (c *Controller) GetEnqueuedVaas(ctx *fiber.Ctx) error { return ctx.JSON(response) } -// IsVaaEnqueued handler for the endpoint /guardian_public_api/v1/governor/is_vaa_enqueued -// This endpoint has been migrated from the guardian grpc api. +// IsVaaEnqueued godoc +// @Description Check if vaa is enqueued +// @Tags Guardian +// @ID guardians-is-vaa-enqueued +// @Param chain_id path integer true "id of the blockchain" +// @Param emitter path string true "address of the emitter" +// @Param seq path integer true "sequence of the vaa" +// @Success 200 {object} EnqueuedVaaResponse +// @Failure 400 +// @Failure 500 +// @Router /v1/governor/is_vaa_enqueued/{chain_id}/{emitter}/{seq} [get] func (c *Controller) IsVaaEnqueued(ctx *fiber.Ctx) error { chainID, emitter, seq, err := middleware.ExtractVAAParams(ctx, c.logger) if err != nil { @@ -275,12 +295,18 @@ func (c *Controller) IsVaaEnqueued(ctx *fiber.Ctx) error { return ctx.JSON(response) } -// GetTokenList handler for the endpoint /guardian_public_api/v1/governor/token_list -// This endpoint has been migrated from the guardian grpc api. -// Since from the wormhole-explorer point of view it is not a node, but has the information of all nodes, -// in order to build the endpoints it was assumed: -// For tokens with the same originChainId and originAddress and different price values for each node, -// the price that has most occurrences in all the nodes for an originChainId and originAddress is returned. +// GetTokenList godoc +// @Description Get token list +// @Description Since from the wormhole-explorer point of view it is not a node, but has the information of all nodes, +// @Description in order to build the endpoints it was assumed: +// @Description For tokens with the same originChainId and originAddress and different price values for each node, +// @Description the price that has most occurrences in all the nodes for an originChainId and originAddress is returned. +// @Tags Guardian +// @ID guardians-token-list +// @Success 200 {object} []TokenList +// @Failure 400 +// @Failure 500 +// @Router /v1/governor/token_list [get] func (c *Controller) GetTokenList(ctx *fiber.Ctx) error { tokenList, err := c.srv.GetTokenList(ctx.Context()) if err != nil { diff --git a/api/handlers/guardian/controller.go b/api/handlers/guardian/controller.go index 29a23ea7..3d15f13c 100644 --- a/api/handlers/guardian/controller.go +++ b/api/handlers/guardian/controller.go @@ -27,8 +27,14 @@ type GuardianSet struct { Addresses []string `json:"addresses"` } -// GetGuardianSet handler for the endpoint /guardian_public_api/v1/guardianset/current -// This endpoint has been migrated from the guardian grpc api. +// GetGuardianSet godoc +// @Description Get current guardian set. +// @Tags Guardian +// @ID guardian-set +// @Success 200 {object} GuardianSetResponse +// @Failure 400 +// @Failure 500 +// @Router /v1/guardianset/current [get] func (c *Controller) GetGuardianSet(ctx *fiber.Ctx) error { // check guardianSet exists. if len(ByIndex) == 0 { diff --git a/api/handlers/heartbeats/controller.go b/api/handlers/heartbeats/controller.go index a9e7cb2e..a9ed572d 100644 --- a/api/handlers/heartbeats/controller.go +++ b/api/handlers/heartbeats/controller.go @@ -53,8 +53,14 @@ type HeartbeatNetworkResponse struct { ErrorCount string `bson:"errorcount" json:"errorCount"` } -// GetLastHeartbeats handler for the endpoint /guardian_public_api/v1/heartbeats -// This endpoint has been migrated from the guardian grpc api. +// GetGuardianSet godoc +// @Description Get heartbeats for guardians +// @Tags Guardian +// @ID guardians-hearbeats +// @Success 200 {object} HeartbeatsResponse +// @Failure 400 +// @Failure 500 +// @Router /v1/heartbeats [get] func (c *Controller) GetLastHeartbeats(ctx *fiber.Ctx) error { // check guardianSet exists. if len(guardian.ByIndex) == 0 { diff --git a/api/handlers/vaa/controller.go b/api/handlers/vaa/controller.go index 6af4f699..dfb6c1da 100644 --- a/api/handlers/vaa/controller.go +++ b/api/handlers/vaa/controller.go @@ -73,8 +73,17 @@ func (c *Controller) FindById(ctx *fiber.Ctx) error { return ctx.JSON(vaa) } -// FindSignedVAAByID get a VAA []byte from a chainID, emitter address and sequence. -// This endpoint has been migrated from the guardian grpc api. +// FindSignedVAAByID godoc +// @Description get a VAA []byte from a chainID, emitter address and sequence. +// @Tags Guardian +// @ID guardians-find-signed-vaa +// @Param chain_id path integer true "id of the blockchain" +// @Param emitter path string true "address of the emitter" +// @Param seq path integer true "sequence of the vaa" +// @Success 200 {object} object{vaaBytes=[]byte} +// @Failure 400 +// @Failure 500 +// @Router /v1/signed_vaa/{chain_id}/{emitter}/{seq} [get] func (c *Controller) FindSignedVAAByID(ctx *fiber.Ctx) error { chainID, emitter, seq, err := middleware.ExtractVAAParams(ctx, c.logger) if err != nil { @@ -99,8 +108,17 @@ func (c *Controller) FindSignedVAAByID(ctx *fiber.Ctx) error { return ctx.JSON(response) } -// FindSignedBatchVAAByID get a Batch VAA from a chainID, emitter address and sequence. -// This endpoint has been migrated from the guardian grpc api. +// FindSignedBatchVAAByID godoc +// @Description get a batch of VAA []byte from a chainID, emitter address and sequence. +// @Tags Guardian +// @ID guardians-find-signed-batch-vaa +// @Param chain_id path integer true "id of the blockchain" +// @Param emitter path string true "address of the emitter" +// @Param seq path integer true "sequence of the vaa" +// @Success 200 {object} object{vaaBytes=[]byte} +// @Failure 400 +// @Failure 500 +// @Router /v1/signed_batch_vaa/{chain_id}/{emitter}/sequence/{seq} [get] func (c *Controller) FindSignedBatchVAAByID(ctx *fiber.Ctx) error { return response.NewApiError(ctx, fiber.StatusNotImplemented, response.Unimplemented, "not yet implemented", nil) } diff --git a/api/main.go b/api/main.go index 7e217683..117a1aa6 100644 --- a/api/main.go +++ b/api/main.go @@ -42,6 +42,18 @@ func healthOk(ctx *fiber.Ctx) error { return ctx.SendString("Ok") } +// @title Wormhole Guardian API +// @version 1.0 +// @description Wormhole Guardian API +// @description To get information from the Wormhole Network. +// @description Check each endpoint documentation for more information. +// @termsOfService https://wormhole.com/ +// @contact.name API Support +// @contact.url http://wormhole.com/support +// @contact.email info@wormhole.com +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @BasePath /v1 func main() { appCtx, cancel := context.WithCancel(context.Background()) defer cancel()