[API] Standard payload changes (#520)
### Summary This pull request modifies the API service to expose two endpoints for the Wormhole Scan UI: * `GET /api/v1/transactions`: data needed to render the transactions list page. * `GET /api/v1/transactions/{chain}/{id}/{sequence}`: data needed to render the transaction detail page.
This commit is contained in:
parent
4f1987c698
commit
fe196e35f0
216
api/docs/docs.go
216
api/docs/docs.go
|
@ -1077,6 +1077,52 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/transactions/{chain_id}/{emitter}/{seq}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Find VAA metadata by ID.",
|
||||||
|
"tags": [
|
||||||
|
"Wormscan"
|
||||||
|
],
|
||||||
|
"operationId": "get-transaction-by-id",
|
||||||
|
"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/transactions.TransactionDetail"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request"
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/vaas/": {
|
"/api/v1/vaas/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
||||||
|
@ -1734,52 +1780,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"github_com_wormhole-foundation_wormhole-explorer_api_routes_wormscan_transactions.TransactionOverview": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"destinationAddress": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"destinationChain": {
|
|
||||||
"$ref": "#/definitions/vaa.ChainID"
|
|
||||||
},
|
|
||||||
"emitterAddress": {
|
|
||||||
"description": "EmitterAddress contains the VAA's emitter address, encoded in hex.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"emitterNativeAddress": {
|
|
||||||
"description": "EmitterNativeAddress contains the VAA's emitter address, encoded in the emitter chain's native format.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"originAddress": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"originChain": {
|
|
||||||
"$ref": "#/definitions/vaa.ChainID"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"$ref": "#/definitions/transactions.TxStatus"
|
|
||||||
},
|
|
||||||
"symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tokenAmount": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"txHash": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"usdAmount": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"governor.AvailableNotionalItemResponse": {
|
"governor.AvailableNotionalItemResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2531,17 +2531,83 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.DestinationTx": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"blockNumber": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"chainId": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"txHash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transactions.GlobalTransactionDoc": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"destinationTx": {
|
||||||
|
"$ref": "#/definitions/transactions.DestinationTx"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"originTx": {
|
||||||
|
"$ref": "#/definitions/transactions.OriginTx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.ListTransactionsResponse": {
|
"transactions.ListTransactionsResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"transactions": {
|
"transactions": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/github_com_wormhole-foundation_wormhole-explorer_api_routes_wormscan_transactions.TransactionOverview"
|
"$ref": "#/definitions/transactions.TransactionDetail"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.OriginTx": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"chainId": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"txHash": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.ScorecardsResponse": {
|
"transactions.ScorecardsResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2617,6 +2683,51 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.TransactionDetail": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"emitterAddress": {
|
||||||
|
"description": "EmitterAddress contains the VAA's emitter address, encoded in hex.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"emitterChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"emitterNativeAddress": {
|
||||||
|
"description": "EmitterNativeAddress contains the VAA's emitter address, encoded in the emitter chain's native format.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"globalTx": {
|
||||||
|
"$ref": "#/definitions/transactions.GlobalTransactionDoc"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"standardizedProperties": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"symbol": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tokenAmount": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"txHash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"usdAmount": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.Tx": {
|
"transactions.Tx": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2637,17 +2748,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transactions.TxStatus": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"ongoing",
|
|
||||||
"completed"
|
|
||||||
],
|
|
||||||
"x-enum-varnames": [
|
|
||||||
"TxStatusOngoing",
|
|
||||||
"TxStatusCompleted"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"vaa.ChainID": {
|
"vaa.ChainID": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
|
@ -1070,6 +1070,52 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/transactions/{chain_id}/{emitter}/{seq}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Find VAA metadata by ID.",
|
||||||
|
"tags": [
|
||||||
|
"Wormscan"
|
||||||
|
],
|
||||||
|
"operationId": "get-transaction-by-id",
|
||||||
|
"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/transactions.TransactionDetail"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request"
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/vaas/": {
|
"/api/v1/vaas/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
"description": "Returns all VAAs. Output is paginated and can also be be sorted.",
|
||||||
|
@ -1727,52 +1773,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"github_com_wormhole-foundation_wormhole-explorer_api_routes_wormscan_transactions.TransactionOverview": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"destinationAddress": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"destinationChain": {
|
|
||||||
"$ref": "#/definitions/vaa.ChainID"
|
|
||||||
},
|
|
||||||
"emitterAddress": {
|
|
||||||
"description": "EmitterAddress contains the VAA's emitter address, encoded in hex.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"emitterNativeAddress": {
|
|
||||||
"description": "EmitterNativeAddress contains the VAA's emitter address, encoded in the emitter chain's native format.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"originAddress": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"originChain": {
|
|
||||||
"$ref": "#/definitions/vaa.ChainID"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"$ref": "#/definitions/transactions.TxStatus"
|
|
||||||
},
|
|
||||||
"symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tokenAmount": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"txHash": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"usdAmount": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"governor.AvailableNotionalItemResponse": {
|
"governor.AvailableNotionalItemResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2524,17 +2524,83 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.DestinationTx": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"blockNumber": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"chainId": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"txHash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transactions.GlobalTransactionDoc": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"destinationTx": {
|
||||||
|
"$ref": "#/definitions/transactions.DestinationTx"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"originTx": {
|
||||||
|
"$ref": "#/definitions/transactions.OriginTx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.ListTransactionsResponse": {
|
"transactions.ListTransactionsResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"transactions": {
|
"transactions": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/github_com_wormhole-foundation_wormhole-explorer_api_routes_wormscan_transactions.TransactionOverview"
|
"$ref": "#/definitions/transactions.TransactionDetail"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.OriginTx": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"chainId": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"txHash": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.ScorecardsResponse": {
|
"transactions.ScorecardsResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2610,6 +2676,51 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"transactions.TransactionDetail": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"emitterAddress": {
|
||||||
|
"description": "EmitterAddress contains the VAA's emitter address, encoded in hex.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"emitterChain": {
|
||||||
|
"$ref": "#/definitions/vaa.ChainID"
|
||||||
|
},
|
||||||
|
"emitterNativeAddress": {
|
||||||
|
"description": "EmitterNativeAddress contains the VAA's emitter address, encoded in the emitter chain's native format.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"globalTx": {
|
||||||
|
"$ref": "#/definitions/transactions.GlobalTransactionDoc"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"standardizedProperties": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"symbol": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tokenAmount": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"txHash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"usdAmount": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactions.Tx": {
|
"transactions.Tx": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2630,17 +2741,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transactions.TxStatus": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"ongoing",
|
|
||||||
"completed"
|
|
||||||
],
|
|
||||||
"x-enum-varnames": [
|
|
||||||
"TxStatusOngoing",
|
|
||||||
"TxStatusCompleted"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"vaa.ChainID": {
|
"vaa.ChainID": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
|
@ -16,39 +16,6 @@ definitions:
|
||||||
index:
|
index:
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
github_com_wormhole-foundation_wormhole-explorer_api_routes_wormscan_transactions.TransactionOverview:
|
|
||||||
properties:
|
|
||||||
destinationAddress:
|
|
||||||
type: string
|
|
||||||
destinationChain:
|
|
||||||
$ref: '#/definitions/vaa.ChainID'
|
|
||||||
emitterAddress:
|
|
||||||
description: EmitterAddress contains the VAA's emitter address, encoded in
|
|
||||||
hex.
|
|
||||||
type: string
|
|
||||||
emitterNativeAddress:
|
|
||||||
description: EmitterNativeAddress contains the VAA's emitter address, encoded
|
|
||||||
in the emitter chain's native format.
|
|
||||||
type: string
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
originAddress:
|
|
||||||
type: string
|
|
||||||
originChain:
|
|
||||||
$ref: '#/definitions/vaa.ChainID'
|
|
||||||
status:
|
|
||||||
$ref: '#/definitions/transactions.TxStatus'
|
|
||||||
symbol:
|
|
||||||
type: string
|
|
||||||
timestamp:
|
|
||||||
type: string
|
|
||||||
tokenAmount:
|
|
||||||
type: string
|
|
||||||
txHash:
|
|
||||||
type: string
|
|
||||||
usdAmount:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
governor.AvailableNotionalItemResponse:
|
governor.AvailableNotionalItemResponse:
|
||||||
properties:
|
properties:
|
||||||
bigTransactionSize:
|
bigTransactionSize:
|
||||||
|
@ -535,13 +502,56 @@ definitions:
|
||||||
volume:
|
volume:
|
||||||
type: number
|
type: number
|
||||||
type: object
|
type: object
|
||||||
|
transactions.DestinationTx:
|
||||||
|
properties:
|
||||||
|
blockNumber:
|
||||||
|
type: string
|
||||||
|
chainId:
|
||||||
|
$ref: '#/definitions/vaa.ChainID'
|
||||||
|
from:
|
||||||
|
type: string
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
to:
|
||||||
|
type: string
|
||||||
|
txHash:
|
||||||
|
type: string
|
||||||
|
updatedAt:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
transactions.GlobalTransactionDoc:
|
||||||
|
properties:
|
||||||
|
destinationTx:
|
||||||
|
$ref: '#/definitions/transactions.DestinationTx'
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
originTx:
|
||||||
|
$ref: '#/definitions/transactions.OriginTx'
|
||||||
|
type: object
|
||||||
transactions.ListTransactionsResponse:
|
transactions.ListTransactionsResponse:
|
||||||
properties:
|
properties:
|
||||||
transactions:
|
transactions:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/github_com_wormhole-foundation_wormhole-explorer_api_routes_wormscan_transactions.TransactionOverview'
|
$ref: '#/definitions/transactions.TransactionDetail'
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
|
transactions.OriginTx:
|
||||||
|
properties:
|
||||||
|
chainId:
|
||||||
|
$ref: '#/definitions/vaa.ChainID'
|
||||||
|
from:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
txHash:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
transactions.ScorecardsResponse:
|
transactions.ScorecardsResponse:
|
||||||
properties:
|
properties:
|
||||||
24h_messages:
|
24h_messages:
|
||||||
|
@ -595,6 +605,39 @@ definitions:
|
||||||
time:
|
time:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
transactions.TransactionDetail:
|
||||||
|
properties:
|
||||||
|
emitterAddress:
|
||||||
|
description: EmitterAddress contains the VAA's emitter address, encoded in
|
||||||
|
hex.
|
||||||
|
type: string
|
||||||
|
emitterChain:
|
||||||
|
$ref: '#/definitions/vaa.ChainID'
|
||||||
|
emitterNativeAddress:
|
||||||
|
description: EmitterNativeAddress contains the VAA's emitter address, encoded
|
||||||
|
in the emitter chain's native format.
|
||||||
|
type: string
|
||||||
|
globalTx:
|
||||||
|
$ref: '#/definitions/transactions.GlobalTransactionDoc'
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
payload:
|
||||||
|
additionalProperties: true
|
||||||
|
type: object
|
||||||
|
standardizedProperties:
|
||||||
|
additionalProperties: true
|
||||||
|
type: object
|
||||||
|
symbol:
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
tokenAmount:
|
||||||
|
type: string
|
||||||
|
txHash:
|
||||||
|
type: string
|
||||||
|
usdAmount:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
transactions.Tx:
|
transactions.Tx:
|
||||||
properties:
|
properties:
|
||||||
chain:
|
chain:
|
||||||
|
@ -608,14 +651,6 @@ definitions:
|
||||||
volume:
|
volume:
|
||||||
type: number
|
type: number
|
||||||
type: object
|
type: object
|
||||||
transactions.TxStatus:
|
|
||||||
enum:
|
|
||||||
- ongoing
|
|
||||||
- completed
|
|
||||||
type: string
|
|
||||||
x-enum-varnames:
|
|
||||||
- TxStatusOngoing
|
|
||||||
- TxStatusCompleted
|
|
||||||
vaa.ChainID:
|
vaa.ChainID:
|
||||||
enum:
|
enum:
|
||||||
- 0
|
- 0
|
||||||
|
@ -1455,6 +1490,37 @@ paths:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
tags:
|
tags:
|
||||||
- Wormscan
|
- Wormscan
|
||||||
|
/api/v1/transactions/{chain_id}/{emitter}/{seq}:
|
||||||
|
get:
|
||||||
|
description: Find VAA metadata by ID.
|
||||||
|
operationId: get-transaction-by-id
|
||||||
|
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/transactions.TransactionDetail'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
tags:
|
||||||
|
- Wormscan
|
||||||
/api/v1/vaas/:
|
/api/v1/vaas/:
|
||||||
get:
|
get:
|
||||||
description: Returns all VAAs. Output is paginated and can also be be sorted.
|
description: Returns all VAAs. Output is paginated and can also be be sorted.
|
||||||
|
|
|
@ -181,22 +181,16 @@ type Token struct {
|
||||||
Decimals int64 `json:"decimals"`
|
Decimals int64 `json:"decimals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionOverview models a brief overview of a transactions (ID, txHash, status, etc.)
|
type TransactionDto struct {
|
||||||
type TransactionOverview struct {
|
ID string `bson:"_id"`
|
||||||
ID string `bson:"_id"`
|
EmitterChain sdk.ChainID `bson:"emitterChain"`
|
||||||
EmitterChain sdk.ChainID `bson:"emitterChain"`
|
EmitterAddr string `bson:"emitterAddr"`
|
||||||
EmitterAddr string `bson:"emitterAddr"`
|
TxHash string `bson:"txHash"`
|
||||||
TxHash string `bson:"txHash"`
|
Timestamp time.Time `bson:"timestamp"`
|
||||||
Timestamp time.Time `bson:"timestamp"`
|
Symbol string `bson:"symbol"`
|
||||||
ToAddress string `bson:"toAddress"`
|
UsdAmount string `bson:"usdAmount"`
|
||||||
ToChain sdk.ChainID `bson:"toChain"`
|
TokenAmount string `bson:"tokenAmount"`
|
||||||
Symbol string `bson:"symbol"`
|
GlobalTransations []GlobalTransactionDoc `bson:"globalTransactions"`
|
||||||
UsdAmount string `bson:"usdAmount"`
|
Payload map[string]interface{} `bson:"payload"`
|
||||||
TokenAmount string `bson:"tokenAmount"`
|
StandardizedProperties map[string]interface{} `bson:"standardizedProperties"`
|
||||||
GlobalTransations []GlobalTransactionDoc `bson:"globalTransactions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListTransactionsInput is used as the output for the function `ListTransactions`
|
|
||||||
type ListTransactonsOutput struct {
|
|
||||||
Transactions []TransactionOverview
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -726,24 +726,43 @@ func (r *Repository) findGlobalTransactionByID(ctx context.Context, q *GlobalTra
|
||||||
return &globalTranstaction, nil
|
return &globalTranstaction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTransactions returns a sorted list of transactions.
|
// FindTransactionsInput is used to pass parameters to the `FindTransactions` method.
|
||||||
//
|
type FindTransactionsInput struct {
|
||||||
// Pagination is implemented using a keyset cursor pattern, based on the (timestamp, ID) pair.
|
// id specifies the VAA ID of the transaction to be found.
|
||||||
func (r *Repository) ListTransactions(
|
id string
|
||||||
|
// sort specifies whether the results should be sorted
|
||||||
|
//
|
||||||
|
// If set to true, the results will be sorted by descending timestamp and ID.
|
||||||
|
// If set to false, the results will not be sorted.
|
||||||
|
sort bool
|
||||||
|
pagination *pagination.Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindTransactions returns transactions matching a specified search criteria.
|
||||||
|
func (r *Repository) FindTransactions(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
pagination *pagination.Pagination,
|
input *FindTransactionsInput,
|
||||||
) (*ListTransactonsOutput, error) {
|
) ([]TransactionDto, error) {
|
||||||
|
|
||||||
// Build the aggregation pipeline
|
// Build the aggregation pipeline
|
||||||
var pipeline mongo.Pipeline
|
var pipeline mongo.Pipeline
|
||||||
{
|
{
|
||||||
// Specify sorting criteria
|
// Specify sorting criteria
|
||||||
pipeline = append(pipeline, bson.D{
|
if input.sort {
|
||||||
{"$sort", bson.D{
|
pipeline = append(pipeline, bson.D{
|
||||||
bson.E{"timestamp", -1},
|
{"$sort", bson.D{
|
||||||
bson.E{"_id", -1},
|
bson.E{"timestamp", -1},
|
||||||
}},
|
bson.E{"_id", -1},
|
||||||
})
|
}},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by ID
|
||||||
|
if input.id != "" {
|
||||||
|
pipeline = append(pipeline, bson.D{
|
||||||
|
{"$match", bson.D{{"_id", input.id}}},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// left outer join on the `transferPrices` collection
|
// left outer join on the `transferPrices` collection
|
||||||
pipeline = append(pipeline, bson.D{
|
pipeline = append(pipeline, bson.D{
|
||||||
|
@ -789,8 +808,8 @@ func (r *Repository) ListTransactions(
|
||||||
pipeline = append(pipeline, bson.D{
|
pipeline = append(pipeline, bson.D{
|
||||||
{"$addFields", bson.D{
|
{"$addFields", bson.D{
|
||||||
{"txHash", bson.M{"$arrayElemAt": []interface{}{"$vaaIdTxHash.txHash", 0}}},
|
{"txHash", bson.M{"$arrayElemAt": []interface{}{"$vaaIdTxHash.txHash", 0}}},
|
||||||
{"toAddress", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.result.toAddress", 0}}},
|
{"payload", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.parsedPayload", 0}}},
|
||||||
{"toChain", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.result.toChain", 0}}},
|
{"standardizedProperties", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.standardizedProperties", 0}}},
|
||||||
{"symbol", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.symbol", 0}}},
|
{"symbol", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.symbol", 0}}},
|
||||||
{"usdAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.usdAmount", 0}}},
|
{"usdAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.usdAmount", 0}}},
|
||||||
{"tokenAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.tokenAmount", 0}}},
|
{"tokenAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.tokenAmount", 0}}},
|
||||||
|
@ -803,14 +822,18 @@ func (r *Repository) ListTransactions(
|
||||||
})
|
})
|
||||||
|
|
||||||
// Skip initial results
|
// Skip initial results
|
||||||
pipeline = append(pipeline, bson.D{
|
if input.pagination != nil {
|
||||||
{"$skip", pagination.Skip},
|
pipeline = append(pipeline, bson.D{
|
||||||
})
|
{"$skip", input.pagination.Skip},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Limit size of results
|
// Limit size of results
|
||||||
pipeline = append(pipeline, bson.D{
|
if input.pagination != nil {
|
||||||
{"$limit", pagination.Limit},
|
pipeline = append(pipeline, bson.D{
|
||||||
})
|
{"$limit", input.pagination.Limit},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the aggregation pipeline
|
// Execute the aggregation pipeline
|
||||||
|
@ -821,18 +844,14 @@ func (r *Repository) ListTransactions(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read results from cursor
|
// Read results from cursor
|
||||||
var documents []TransactionOverview
|
var documents []TransactionDto
|
||||||
err = cur.All(ctx, &documents)
|
err = cur.All(ctx, &documents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Error("failed to decode cursor", zap.Error(err))
|
r.logger.Error("failed to decode cursor", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build result and return
|
return documents, nil
|
||||||
response := ListTransactonsOutput{
|
|
||||||
Transactions: documents,
|
|
||||||
}
|
|
||||||
return &response, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTransactionsByAddress returns a sorted list of transactions for a given address.
|
// ListTransactionsByAddress returns a sorted list of transactions for a given address.
|
||||||
|
@ -842,14 +861,14 @@ func (r *Repository) ListTransactionsByAddress(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
address *types.Address,
|
address *types.Address,
|
||||||
pagination *pagination.Pagination,
|
pagination *pagination.Pagination,
|
||||||
) (*ListTransactonsOutput, error) {
|
) ([]TransactionDto, error) {
|
||||||
|
|
||||||
// Build the aggregation pipeline
|
// Build the aggregation pipeline
|
||||||
var pipeline mongo.Pipeline
|
var pipeline mongo.Pipeline
|
||||||
{
|
{
|
||||||
// filter by address
|
// filter by address
|
||||||
pipeline = append(pipeline, bson.D{
|
pipeline = append(pipeline, bson.D{
|
||||||
{"$match", bson.D{{"result.toAddress", bson.M{"$eq": "0x" + address.Hex()}}}},
|
{"$match", bson.D{{"parsedPayload.toAddress", bson.M{"$eq": "0x" + address.Hex()}}}},
|
||||||
})
|
})
|
||||||
|
|
||||||
// specify sorting criteria
|
// specify sorting criteria
|
||||||
|
@ -912,8 +931,8 @@ func (r *Repository) ListTransactionsByAddress(
|
||||||
{"$addFields", bson.D{
|
{"$addFields", bson.D{
|
||||||
{"txHash", bson.M{"$arrayElemAt": []interface{}{"$vaaIdTxHash.txHash", 0}}},
|
{"txHash", bson.M{"$arrayElemAt": []interface{}{"$vaaIdTxHash.txHash", 0}}},
|
||||||
{"timestamp", bson.M{"$arrayElemAt": []interface{}{"$vaas.timestamp", 0}}},
|
{"timestamp", bson.M{"$arrayElemAt": []interface{}{"$vaas.timestamp", 0}}},
|
||||||
{"toAddress", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.result.toAddress", 0}}},
|
{"payload", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.parsedPayload", 0}}},
|
||||||
{"toChain", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.result.toChain", 0}}},
|
{"standardizedProperties", bson.M{"$arrayElemAt": []interface{}{"$parsedVaa.standardizedProperties", 0}}},
|
||||||
{"symbol", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.symbol", 0}}},
|
{"symbol", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.symbol", 0}}},
|
||||||
{"usdAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.usdAmount", 0}}},
|
{"usdAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.usdAmount", 0}}},
|
||||||
{"tokenAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.tokenAmount", 0}}},
|
{"tokenAmount", bson.M{"$arrayElemAt": []interface{}{"$transferPrices.tokenAmount", 0}}},
|
||||||
|
@ -944,16 +963,12 @@ func (r *Repository) ListTransactionsByAddress(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read results from cursor
|
// Read results from cursor
|
||||||
var documents []TransactionOverview
|
var documents []TransactionDto
|
||||||
err = cur.All(ctx, &documents)
|
err = cur.All(ctx, &documents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Error("failed to decode cursor", zap.Error(err))
|
r.logger.Error("failed to decode cursor", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build result and return
|
return documents, nil
|
||||||
response := ListTransactonsOutput{
|
|
||||||
Transactions: documents,
|
|
||||||
}
|
|
||||||
return &response, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/api/cacheable"
|
"github.com/wormhole-foundation/wormhole-explorer/api/cacheable"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
||||||
errs "github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
errs "github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||||
|
@ -118,16 +119,43 @@ func (s *Service) GetTokenByChainAndAddress(ctx context.Context, chainID vaa.Cha
|
||||||
func (s *Service) ListTransactions(
|
func (s *Service) ListTransactions(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
pagination *pagination.Pagination,
|
pagination *pagination.Pagination,
|
||||||
) (*ListTransactonsOutput, error) {
|
) ([]TransactionDto, error) {
|
||||||
|
|
||||||
return s.repo.ListTransactions(ctx, pagination)
|
input := FindTransactionsInput{
|
||||||
|
sort: true,
|
||||||
|
pagination: pagination,
|
||||||
|
}
|
||||||
|
return s.repo.FindTransactions(ctx, &input)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ListTransactionsByAddress(
|
func (s *Service) ListTransactionsByAddress(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
address *types.Address,
|
address *types.Address,
|
||||||
pagination *pagination.Pagination,
|
pagination *pagination.Pagination,
|
||||||
) (*ListTransactonsOutput, error) {
|
) ([]TransactionDto, error) {
|
||||||
|
|
||||||
return s.repo.ListTransactionsByAddress(ctx, address, pagination)
|
return s.repo.ListTransactionsByAddress(ctx, address, pagination)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetTransactionByID(
|
||||||
|
ctx context.Context,
|
||||||
|
chain vaa.ChainID,
|
||||||
|
emitter *types.Address,
|
||||||
|
seq string,
|
||||||
|
) (*TransactionDto, error) {
|
||||||
|
|
||||||
|
// Execute the database query
|
||||||
|
input := FindTransactionsInput{
|
||||||
|
id: fmt.Sprintf("%d/%s/%s", chain, emitter.Hex(), seq),
|
||||||
|
}
|
||||||
|
output, err := s.repo.FindTransactions(ctx, &input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(output) == 0 {
|
||||||
|
return nil, errors.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return matching document
|
||||||
|
return &output[0], nil
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ func RegisterRoutes(
|
||||||
api.Get("/top-chain-pairs-by-num-transfers", transactionCtrl.GetTopChainPairs)
|
api.Get("/top-chain-pairs-by-num-transfers", transactionCtrl.GetTopChainPairs)
|
||||||
api.Get("token/:chain/:token_address", transactionCtrl.GetTokenByChainAndAddress)
|
api.Get("token/:chain/:token_address", transactionCtrl.GetTokenByChainAndAddress)
|
||||||
api.Get("/transactions", transactionCtrl.ListTransactions)
|
api.Get("/transactions", transactionCtrl.ListTransactions)
|
||||||
|
api.Get("/transactions/:chain/:emitter/:sequence", transactionCtrl.GetTransactionByID)
|
||||||
|
|
||||||
// vaas resource
|
// vaas resource
|
||||||
vaas := api.Group("/vaas")
|
vaas := api.Group("/vaas")
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/api/handlers/transactions"
|
"github.com/wormhole-foundation/wormhole-explorer/api/handlers/transactions"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/api/middleware"
|
"github.com/wormhole-foundation/wormhole-explorer/api/middleware"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
||||||
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||||
|
@ -370,55 +371,55 @@ func (c *Controller) ListTransactions(ctx *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query transactions from the database
|
// Query transactions from the database
|
||||||
var queryResult *transactions.ListTransactonsOutput
|
var dtos []transactions.TransactionDto
|
||||||
if address != nil {
|
if address != nil {
|
||||||
queryResult, err = c.srv.ListTransactionsByAddress(ctx.Context(), address, pagination)
|
dtos, err = c.srv.ListTransactionsByAddress(ctx.Context(), address, pagination)
|
||||||
} else {
|
} else {
|
||||||
queryResult, err = c.srv.ListTransactions(ctx.Context(), pagination)
|
dtos, err = c.srv.ListTransactions(ctx.Context(), pagination)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the response struct and return
|
// Populate the response struct and return
|
||||||
response := c.makeTransactionsResponse(queryResult)
|
response := c.makeTransactionsResponse(dtos)
|
||||||
return ctx.JSON(response)
|
return ctx.JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) makeTransactionsResponse(queryResult *transactions.ListTransactonsOutput) ListTransactionsResponse {
|
func (c *Controller) makeTransactionsResponse(dtos []transactions.TransactionDto) ListTransactionsResponse {
|
||||||
|
|
||||||
response := ListTransactionsResponse{
|
response := ListTransactionsResponse{
|
||||||
Transactions: make([]*TransactionOverview, 0, len(queryResult.Transactions)),
|
Transactions: make([]*TransactionDetail, 0, len(dtos)),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range queryResult.Transactions {
|
for i := range dtos {
|
||||||
tx := c.makeTransactionOverview(&queryResult.Transactions[i])
|
tx := c.makeTransactionDetail(&dtos[i])
|
||||||
response.Transactions = append(response.Transactions, tx)
|
response.Transactions = append(response.Transactions, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) makeTransactionOverview(input *transactions.TransactionOverview) *TransactionOverview {
|
func (c *Controller) makeTransactionDetail(input *transactions.TransactionDto) *TransactionDetail {
|
||||||
|
|
||||||
tx := TransactionOverview{
|
tx := TransactionDetail{
|
||||||
ID: input.ID,
|
ID: input.ID,
|
||||||
OriginChain: input.EmitterChain,
|
EmitterChain: input.EmitterChain,
|
||||||
EmitterAddress: input.EmitterAddr,
|
EmitterAddress: input.EmitterAddr,
|
||||||
Timestamp: input.Timestamp,
|
Timestamp: input.Timestamp,
|
||||||
DestinationAddress: input.ToAddress,
|
Symbol: input.Symbol,
|
||||||
DestinationChain: input.ToChain,
|
TokenAmount: input.TokenAmount,
|
||||||
Symbol: input.Symbol,
|
UsdAmount: input.UsdAmount,
|
||||||
TokenAmount: input.TokenAmount,
|
Payload: input.Payload,
|
||||||
UsdAmount: input.UsdAmount,
|
StandardizedProperties: input.StandardizedProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate the emitter address into the emitter chain's native format
|
// Translate the emitter address into the emitter chain's native format
|
||||||
var err error
|
var err error
|
||||||
tx.EmitterNativeAddress, err = domain.TranslateEmitterAddress(tx.OriginChain, tx.EmitterAddress)
|
tx.EmitterNativeAddress, err = domain.TranslateEmitterAddress(tx.EmitterChain, tx.EmitterAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Warn("failed to translate emitter address",
|
c.logger.Warn("failed to translate emitter address",
|
||||||
zap.Stringer("chain", tx.OriginChain),
|
zap.Stringer("chain", tx.EmitterChain),
|
||||||
zap.String("address", tx.EmitterAddress),
|
zap.String("address", tx.EmitterAddress),
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
|
@ -429,29 +430,54 @@ func (c *Controller) makeTransactionOverview(input *transactions.TransactionOver
|
||||||
if isSolanaOrAptos {
|
if isSolanaOrAptos {
|
||||||
// For Solana and Aptos VAAs, the txHash that we get from the gossip network is
|
// For Solana and Aptos VAAs, the txHash that we get from the gossip network is
|
||||||
// not the real transacion hash. We have to overwrite it with the real one.
|
// not the real transacion hash. We have to overwrite it with the real one.
|
||||||
if len(input.GlobalTransations) == 1 &&
|
if len(input.GlobalTransations) == 1 && input.GlobalTransations[0].OriginTx != nil {
|
||||||
input.GlobalTransations[0].OriginTx != nil {
|
|
||||||
|
|
||||||
tx.TxHash = input.GlobalTransations[0].OriginTx.TxHash
|
tx.TxHash = input.GlobalTransations[0].OriginTx.TxHash
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tx.TxHash = input.TxHash
|
tx.TxHash = input.TxHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the status based on the outcome of the redeem transaction.
|
// Set the global transaction, if available
|
||||||
if len(input.GlobalTransations) == 1 &&
|
|
||||||
input.GlobalTransations[0].DestinationTx != nil &&
|
|
||||||
input.GlobalTransations[0].DestinationTx.Status == domain.DstTxStatusConfirmed {
|
|
||||||
|
|
||||||
tx.Status = TxStatusCompleted
|
|
||||||
} else {
|
|
||||||
tx.Status = TxStatusOngoing
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the origin address, if available
|
|
||||||
if len(input.GlobalTransations) == 1 && input.GlobalTransations[0].OriginTx != nil {
|
if len(input.GlobalTransations) == 1 && input.GlobalTransations[0].OriginTx != nil {
|
||||||
tx.OriginAddress = input.GlobalTransations[0].OriginTx.From
|
tx.GlobalTx = &input.GlobalTransations[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tx
|
return &tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTransactionByID godoc
|
||||||
|
// @Description Find VAA metadata by ID.
|
||||||
|
// @Tags Wormscan
|
||||||
|
// @ID get-transaction-by-id
|
||||||
|
// @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} TransactionDetail
|
||||||
|
// @Failure 400
|
||||||
|
// @Failure 500
|
||||||
|
// @Router /api/v1/transactions/{chain_id}/{emitter}/{seq} [get]
|
||||||
|
func (c *Controller) GetTransactionByID(ctx *fiber.Ctx) error {
|
||||||
|
|
||||||
|
// Extract query params
|
||||||
|
chainID, emitter, seq, err := middleware.ExtractVAAParams(ctx, c.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up the VAA by ID
|
||||||
|
dto, err := c.srv.GetTransactionByID(
|
||||||
|
ctx.Context(),
|
||||||
|
chainID,
|
||||||
|
emitter,
|
||||||
|
strconv.FormatUint(seq, 10),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dto == nil {
|
||||||
|
return errors.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
tx := c.makeTransactionDetail(dto)
|
||||||
|
return ctx.JSON(tx)
|
||||||
|
}
|
||||||
|
|
|
@ -3,36 +3,29 @@ package transactions
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/api/handlers/transactions"
|
||||||
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TxStatus string
|
// TransactionDetail is a brief description of a transaction (e.g. ID, txHash, payload, etc.)
|
||||||
|
type TransactionDetail struct {
|
||||||
const (
|
ID string `json:"id"`
|
||||||
TxStatusOngoing TxStatus = "ongoing"
|
Timestamp time.Time `json:"timestamp"`
|
||||||
TxStatusCompleted TxStatus = "completed"
|
TxHash string `json:"txHash,omitempty"`
|
||||||
)
|
EmitterChain sdk.ChainID `json:"emitterChain"`
|
||||||
|
|
||||||
// TransactionOverview is a brief description of a transaction (e.g. ID, txHash, status, etc.).
|
|
||||||
type TransactionOverview struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Timestamp time.Time `json:"timestamp"`
|
|
||||||
TxHash string `json:"txHash,omitempty"`
|
|
||||||
OriginAddress string `json:"originAddress,omitempty"`
|
|
||||||
OriginChain sdk.ChainID `json:"originChain"`
|
|
||||||
// EmitterAddress contains the VAA's emitter address, encoded in hex.
|
// EmitterAddress contains the VAA's emitter address, encoded in hex.
|
||||||
EmitterAddress string `json:"emitterAddress"`
|
EmitterAddress string `json:"emitterAddress"`
|
||||||
// EmitterNativeAddress contains the VAA's emitter address, encoded in the emitter chain's native format.
|
// EmitterNativeAddress contains the VAA's emitter address, encoded in the emitter chain's native format.
|
||||||
EmitterNativeAddress string `json:"emitterNativeAddress,omitempty"`
|
EmitterNativeAddress string `json:"emitterNativeAddress,omitempty"`
|
||||||
DestinationAddress string `json:"destinationAddress,omitempty"`
|
TokenAmount string `json:"tokenAmount,omitempty"`
|
||||||
DestinationChain sdk.ChainID `json:"destinationChain,omitempty"`
|
UsdAmount string `json:"usdAmount,omitempty"`
|
||||||
TokenAmount string `json:"tokenAmount,omitempty"`
|
Symbol string `json:"symbol,omitempty"`
|
||||||
UsdAmount string `json:"usdAmount,omitempty"`
|
Payload map[string]interface{} `json:"payload,omitempty"`
|
||||||
Symbol string `json:"symbol,omitempty"`
|
StandardizedProperties map[string]interface{} `json:"standardizedProperties,omitempty"`
|
||||||
Status TxStatus `json:"status"`
|
GlobalTx *transactions.GlobalTransactionDoc `json:"globalTx,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTransactionsResponse is the "200 OK" response model for `GET /api/v1/transactions`.
|
// ListTransactionsResponse is the "200 OK" response model for `GET /api/v1/transactions`.
|
||||||
type ListTransactionsResponse struct {
|
type ListTransactionsResponse struct {
|
||||||
Transactions []*TransactionOverview `json:"transactions"`
|
Transactions []*TransactionDetail `json:"transactions"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue