Compare commits
1 Commits
42e99c0bec
...
4115cf0419
Author | SHA1 | Date |
---|---|---|
Julian | 4115cf0419 |
|
@ -1,40 +0,0 @@
|
||||||
import "date"
|
|
||||||
|
|
||||||
|
|
||||||
runTask = (start,stop,srcBucket,destBucket,destMeasurement) => {
|
|
||||||
|
|
||||||
data = from(bucket: srcBucket)
|
|
||||||
|> range(start: start,stop: stop)
|
|
||||||
|> filter(fn: (r) => r._measurement == "vaa_volume_v2" and r.version == "v2")
|
|
||||||
|> filter(fn: (r) => r._field == "volume" and r._value > 0)
|
|
||||||
|> drop(columns:["destination_chain","app_id","token_chain","token_address","version","_measurement","_time"])
|
|
||||||
|> rename(columns: {_start: "_time"})
|
|
||||||
|> group(columns: ["emitter_chain","_time"])
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> sum(column: "_value")
|
|
||||||
|> set(key: "_field", value: "volume")
|
|
||||||
|> set(key: "to", value: string(v:stop))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|> count(column: "_value")
|
|
||||||
|> set(key: "_field", value: "count")
|
|
||||||
|> set(key: "to", value: string(v:stop))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
bucketInfinite = "wormscan"
|
|
||||||
destMeasurement = "emitter_chain_activity_1d"
|
|
||||||
|
|
||||||
stop = date.truncate(t: now(),unit: 1d)
|
|
||||||
start = date.sub(d: 1d, from: stop)
|
|
||||||
|
|
||||||
option task = {
|
|
||||||
name: "calculate chain activity per emitter every day",
|
|
||||||
every: 1d,
|
|
||||||
}
|
|
||||||
|
|
||||||
runTask(start:start, stop: stop, srcBucket: bucketInfinite, destBucket: bucketInfinite, destMeasurement: destMeasurement)
|
|
|
@ -1,40 +0,0 @@
|
||||||
import "date"
|
|
||||||
|
|
||||||
|
|
||||||
runTask = (start,stop,srcBucket,destBucket,destMeasurement) => {
|
|
||||||
|
|
||||||
data = from(bucket: srcBucket)
|
|
||||||
|> range(start: start,stop: stop)
|
|
||||||
|> filter(fn: (r) => r._measurement == "vaa_volume_v2" and r.version == "v2")
|
|
||||||
|> filter(fn: (r) => r._field == "volume" and r._value > 0)
|
|
||||||
|> drop(columns:["destination_chain","app_id","token_chain","token_address","version","_measurement","_time"])
|
|
||||||
|> rename(columns: {_start: "_time"})
|
|
||||||
|> group(columns: ["emitter_chain","_time"])
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> sum(column: "_value")
|
|
||||||
|> set(key: "_field", value: "volume")
|
|
||||||
|> set(key: "to", value: string(v:stop))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|> count(column: "_value")
|
|
||||||
|> set(key: "_field", value: "count")
|
|
||||||
|> set(key: "to", value: string(v:stop))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
bucketInfinite = "wormscan"
|
|
||||||
destMeasurement = "emitter_chain_activity_1h"
|
|
||||||
|
|
||||||
stop = date.truncate(t: now(),unit: 1h)
|
|
||||||
start = date.sub(d: 1h, from: stop)
|
|
||||||
|
|
||||||
option task = {
|
|
||||||
name: "calculate chain activity per emitter every hour",
|
|
||||||
every: 1h,
|
|
||||||
}
|
|
||||||
|
|
||||||
runTask(start:start, stop: stop, srcBucket: bucketInfinite, destBucket: bucketInfinite, destMeasurement: destMeasurement)
|
|
|
@ -1,37 +0,0 @@
|
||||||
import "date"
|
|
||||||
|
|
||||||
runTask = (start,stop,srcBucket,destBucket,destMeasurement) => {
|
|
||||||
data = from(bucket: srcBucket)
|
|
||||||
|> range(start: start,stop: stop)
|
|
||||||
|> filter(fn: (r) => r._measurement == "vaa_volume_v2" and r._field == "volume")
|
|
||||||
|> group(columns: ["emitter_chain", "destination_chain", "app_id"])
|
|
||||||
|
|
||||||
data
|
|
||||||
|> sum(column: "_value")
|
|
||||||
|> set(key: "_field", value: "volume")
|
|
||||||
|> map(fn: (r) => ({ r with _time: start }))
|
|
||||||
|> set(key: "to", value: string(v:date.add(d: 1d, to: start)))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|> count(column: "_value")
|
|
||||||
|> set(key: "_field", value: "count")
|
|
||||||
|> map(fn: (r) => ({ r with _time: start }))
|
|
||||||
|> set(key: "to", value: string(v:date.add(d: 1d, to: start)))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bucketInfinite = "wormscan"
|
|
||||||
destMeasurement = "chain_activity_1d"
|
|
||||||
stop = date.truncate(t: now(),unit: 24h)
|
|
||||||
start = date.sub(d: 1d, from: stop)
|
|
||||||
|
|
||||||
option task = {
|
|
||||||
name: "calculate chain activity every day",
|
|
||||||
every: 1d,
|
|
||||||
}
|
|
||||||
|
|
||||||
runTask(start:start, stop: stop, srcBucket: bucketInfinite, destBucket: bucketInfinite, destMeasurement: destMeasurement)
|
|
|
@ -1,40 +0,0 @@
|
||||||
import "date"
|
|
||||||
|
|
||||||
|
|
||||||
runTask = (start,stop,srcBucket,destBucket,destMeasurement) => {
|
|
||||||
|
|
||||||
data = from(bucket: srcBucket)
|
|
||||||
|> range(start: start,stop: stop)
|
|
||||||
|> filter(fn: (r) => r._measurement == "vaa_volume_v2" and r._field == "volume")
|
|
||||||
|> group(columns: ["emitter_chain", "destination_chain", "app_id"])
|
|
||||||
|
|
||||||
data
|
|
||||||
|> sum(column: "_value")
|
|
||||||
|> set(key: "_field", value: "volume")
|
|
||||||
|> map(fn: (r) => ({ r with _time: start }))
|
|
||||||
|> set(key: "to", value: string(v:date.add(d: 1h, to: start)))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|> count(column: "_value")
|
|
||||||
|> set(key: "_field", value: "count")
|
|
||||||
|> map(fn: (r) => ({ r with _time: start }))
|
|
||||||
|> set(key: "to", value: string(v:date.add(d: 1h, to: start)))
|
|
||||||
|> set(key: "_measurement", value: destMeasurement)
|
|
||||||
|> to(bucket: destBucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bucketInfinite = "wormscan"
|
|
||||||
destMeasurement = "chain_activity_1h"
|
|
||||||
|
|
||||||
stop = date.truncate(t: now(),unit: 1h)
|
|
||||||
start = date.sub(d: 1h, from: stop)
|
|
||||||
|
|
||||||
option task = {
|
|
||||||
name: "calculate chain activity every hour",
|
|
||||||
every: 1h,
|
|
||||||
}
|
|
||||||
|
|
||||||
runTask(start:start, stop: stop, srcBucket: bucketInfinite, destBucket: bucketInfinite, destMeasurement: destMeasurement)
|
|
118
api/docs/docs.go
118
api/docs/docs.go
|
@ -1760,73 +1760,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/x-chain-activity/tops": {
|
|
||||||
"get": {
|
|
||||||
"description": "Search, for a specific period of time, the number of transactions and the volume.",
|
|
||||||
"tags": [
|
|
||||||
"wormholescan"
|
|
||||||
],
|
|
||||||
"operationId": "x-chain-activity-tops",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Time span, supported values: 1d, 1mo and 1y",
|
|
||||||
"name": "timespan",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "From date, supported format 2006-01-02T15:04:05Z07:00",
|
|
||||||
"name": "from",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "To date, supported format 2006-01-02T15:04:05Z07:00",
|
|
||||||
"name": "to",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search by appId",
|
|
||||||
"name": "appId",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search by sourceChain",
|
|
||||||
"name": "sourceChain",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search by targetChain",
|
|
||||||
"name": "targetChain",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/transactions.ChainActivityTopResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request"
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/swagger.json": {
|
"/swagger.json": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns the swagger specification for this API.",
|
"description": "Returns the swagger specification for this API.",
|
||||||
|
@ -3392,29 +3325,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transactions.ChainActivityTopResult": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"count": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"destination_chain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"emitter_chain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"from": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"volume": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transactions.ChainPair": {
|
"transactions.ChainPair": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -3681,6 +3591,7 @@ const docTemplate = `{
|
||||||
14,
|
14,
|
||||||
15,
|
15,
|
||||||
16,
|
16,
|
||||||
|
17,
|
||||||
18,
|
18,
|
||||||
19,
|
19,
|
||||||
20,
|
20,
|
||||||
|
@ -3688,35 +3599,24 @@ const docTemplate = `{
|
||||||
22,
|
22,
|
||||||
23,
|
23,
|
||||||
24,
|
24,
|
||||||
25,
|
|
||||||
26,
|
26,
|
||||||
28,
|
28,
|
||||||
29,
|
29,
|
||||||
30,
|
30,
|
||||||
32,
|
32,
|
||||||
33,
|
|
||||||
34,
|
34,
|
||||||
35,
|
35,
|
||||||
36,
|
|
||||||
37,
|
|
||||||
38,
|
|
||||||
39,
|
|
||||||
3104,
|
3104,
|
||||||
4000,
|
4000,
|
||||||
4001,
|
4001,
|
||||||
4002,
|
4002,
|
||||||
4003,
|
4003,
|
||||||
4004,
|
4004,
|
||||||
4005,
|
|
||||||
4006,
|
|
||||||
4007,
|
|
||||||
4008,
|
|
||||||
10002,
|
10002,
|
||||||
10003,
|
10003,
|
||||||
10004,
|
10004,
|
||||||
10005,
|
10005,
|
||||||
10006,
|
10006
|
||||||
10007
|
|
||||||
],
|
],
|
||||||
"x-enum-varnames": [
|
"x-enum-varnames": [
|
||||||
"ChainIDUnset",
|
"ChainIDUnset",
|
||||||
|
@ -3736,6 +3636,7 @@ const docTemplate = `{
|
||||||
"ChainIDCelo",
|
"ChainIDCelo",
|
||||||
"ChainIDNear",
|
"ChainIDNear",
|
||||||
"ChainIDMoonbeam",
|
"ChainIDMoonbeam",
|
||||||
|
"ChainIDNeon",
|
||||||
"ChainIDTerra2",
|
"ChainIDTerra2",
|
||||||
"ChainIDInjective",
|
"ChainIDInjective",
|
||||||
"ChainIDOsmosis",
|
"ChainIDOsmosis",
|
||||||
|
@ -3743,35 +3644,24 @@ const docTemplate = `{
|
||||||
"ChainIDAptos",
|
"ChainIDAptos",
|
||||||
"ChainIDArbitrum",
|
"ChainIDArbitrum",
|
||||||
"ChainIDOptimism",
|
"ChainIDOptimism",
|
||||||
"ChainIDGnosis",
|
|
||||||
"ChainIDPythNet",
|
"ChainIDPythNet",
|
||||||
"ChainIDXpla",
|
"ChainIDXpla",
|
||||||
"ChainIDBtc",
|
"ChainIDBtc",
|
||||||
"ChainIDBase",
|
"ChainIDBase",
|
||||||
"ChainIDSei",
|
"ChainIDSei",
|
||||||
"ChainIDRootstock",
|
|
||||||
"ChainIDScroll",
|
"ChainIDScroll",
|
||||||
"ChainIDMantle",
|
"ChainIDMantle",
|
||||||
"ChainIDBlast",
|
|
||||||
"ChainIDXLayer",
|
|
||||||
"ChainIDLinea",
|
|
||||||
"ChainIDBerachain",
|
|
||||||
"ChainIDWormchain",
|
"ChainIDWormchain",
|
||||||
"ChainIDCosmoshub",
|
"ChainIDCosmoshub",
|
||||||
"ChainIDEvmos",
|
"ChainIDEvmos",
|
||||||
"ChainIDKujira",
|
"ChainIDKujira",
|
||||||
"ChainIDNeutron",
|
"ChainIDNeutron",
|
||||||
"ChainIDCelestia",
|
"ChainIDCelestia",
|
||||||
"ChainIDStargaze",
|
|
||||||
"ChainIDSeda",
|
|
||||||
"ChainIDDymension",
|
|
||||||
"ChainIDProvenance",
|
|
||||||
"ChainIDSepolia",
|
"ChainIDSepolia",
|
||||||
"ChainIDArbitrumSepolia",
|
"ChainIDArbitrumSepolia",
|
||||||
"ChainIDBaseSepolia",
|
"ChainIDBaseSepolia",
|
||||||
"ChainIDOptimismSepolia",
|
"ChainIDOptimismSepolia",
|
||||||
"ChainIDHolesky",
|
"ChainIDHolesky"
|
||||||
"ChainIDPolygonSepolia"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"vaa.VaaDoc": {
|
"vaa.VaaDoc": {
|
||||||
|
|
|
@ -1753,73 +1753,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/x-chain-activity/tops": {
|
|
||||||
"get": {
|
|
||||||
"description": "Search, for a specific period of time, the number of transactions and the volume.",
|
|
||||||
"tags": [
|
|
||||||
"wormholescan"
|
|
||||||
],
|
|
||||||
"operationId": "x-chain-activity-tops",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Time span, supported values: 1d, 1mo and 1y",
|
|
||||||
"name": "timespan",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "From date, supported format 2006-01-02T15:04:05Z07:00",
|
|
||||||
"name": "from",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "To date, supported format 2006-01-02T15:04:05Z07:00",
|
|
||||||
"name": "to",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search by appId",
|
|
||||||
"name": "appId",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search by sourceChain",
|
|
||||||
"name": "sourceChain",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search by targetChain",
|
|
||||||
"name": "targetChain",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/transactions.ChainActivityTopResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request"
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/swagger.json": {
|
"/swagger.json": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns the swagger specification for this API.",
|
"description": "Returns the swagger specification for this API.",
|
||||||
|
@ -3385,29 +3318,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transactions.ChainActivityTopResult": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"count": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"destination_chain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"emitter_chain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"from": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"volume": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transactions.ChainPair": {
|
"transactions.ChainPair": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -3674,6 +3584,7 @@
|
||||||
14,
|
14,
|
||||||
15,
|
15,
|
||||||
16,
|
16,
|
||||||
|
17,
|
||||||
18,
|
18,
|
||||||
19,
|
19,
|
||||||
20,
|
20,
|
||||||
|
@ -3681,35 +3592,24 @@
|
||||||
22,
|
22,
|
||||||
23,
|
23,
|
||||||
24,
|
24,
|
||||||
25,
|
|
||||||
26,
|
26,
|
||||||
28,
|
28,
|
||||||
29,
|
29,
|
||||||
30,
|
30,
|
||||||
32,
|
32,
|
||||||
33,
|
|
||||||
34,
|
34,
|
||||||
35,
|
35,
|
||||||
36,
|
|
||||||
37,
|
|
||||||
38,
|
|
||||||
39,
|
|
||||||
3104,
|
3104,
|
||||||
4000,
|
4000,
|
||||||
4001,
|
4001,
|
||||||
4002,
|
4002,
|
||||||
4003,
|
4003,
|
||||||
4004,
|
4004,
|
||||||
4005,
|
|
||||||
4006,
|
|
||||||
4007,
|
|
||||||
4008,
|
|
||||||
10002,
|
10002,
|
||||||
10003,
|
10003,
|
||||||
10004,
|
10004,
|
||||||
10005,
|
10005,
|
||||||
10006,
|
10006
|
||||||
10007
|
|
||||||
],
|
],
|
||||||
"x-enum-varnames": [
|
"x-enum-varnames": [
|
||||||
"ChainIDUnset",
|
"ChainIDUnset",
|
||||||
|
@ -3729,6 +3629,7 @@
|
||||||
"ChainIDCelo",
|
"ChainIDCelo",
|
||||||
"ChainIDNear",
|
"ChainIDNear",
|
||||||
"ChainIDMoonbeam",
|
"ChainIDMoonbeam",
|
||||||
|
"ChainIDNeon",
|
||||||
"ChainIDTerra2",
|
"ChainIDTerra2",
|
||||||
"ChainIDInjective",
|
"ChainIDInjective",
|
||||||
"ChainIDOsmosis",
|
"ChainIDOsmosis",
|
||||||
|
@ -3736,35 +3637,24 @@
|
||||||
"ChainIDAptos",
|
"ChainIDAptos",
|
||||||
"ChainIDArbitrum",
|
"ChainIDArbitrum",
|
||||||
"ChainIDOptimism",
|
"ChainIDOptimism",
|
||||||
"ChainIDGnosis",
|
|
||||||
"ChainIDPythNet",
|
"ChainIDPythNet",
|
||||||
"ChainIDXpla",
|
"ChainIDXpla",
|
||||||
"ChainIDBtc",
|
"ChainIDBtc",
|
||||||
"ChainIDBase",
|
"ChainIDBase",
|
||||||
"ChainIDSei",
|
"ChainIDSei",
|
||||||
"ChainIDRootstock",
|
|
||||||
"ChainIDScroll",
|
"ChainIDScroll",
|
||||||
"ChainIDMantle",
|
"ChainIDMantle",
|
||||||
"ChainIDBlast",
|
|
||||||
"ChainIDXLayer",
|
|
||||||
"ChainIDLinea",
|
|
||||||
"ChainIDBerachain",
|
|
||||||
"ChainIDWormchain",
|
"ChainIDWormchain",
|
||||||
"ChainIDCosmoshub",
|
"ChainIDCosmoshub",
|
||||||
"ChainIDEvmos",
|
"ChainIDEvmos",
|
||||||
"ChainIDKujira",
|
"ChainIDKujira",
|
||||||
"ChainIDNeutron",
|
"ChainIDNeutron",
|
||||||
"ChainIDCelestia",
|
"ChainIDCelestia",
|
||||||
"ChainIDStargaze",
|
|
||||||
"ChainIDSeda",
|
|
||||||
"ChainIDDymension",
|
|
||||||
"ChainIDProvenance",
|
|
||||||
"ChainIDSepolia",
|
"ChainIDSepolia",
|
||||||
"ChainIDArbitrumSepolia",
|
"ChainIDArbitrumSepolia",
|
||||||
"ChainIDBaseSepolia",
|
"ChainIDBaseSepolia",
|
||||||
"ChainIDOptimismSepolia",
|
"ChainIDOptimismSepolia",
|
||||||
"ChainIDHolesky",
|
"ChainIDHolesky"
|
||||||
"ChainIDPolygonSepolia"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"vaa.VaaDoc": {
|
"vaa.VaaDoc": {
|
||||||
|
|
|
@ -824,21 +824,6 @@ definitions:
|
||||||
$ref: '#/definitions/transactions.Tx'
|
$ref: '#/definitions/transactions.Tx'
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
transactions.ChainActivityTopResult:
|
|
||||||
properties:
|
|
||||||
count:
|
|
||||||
type: integer
|
|
||||||
destination_chain:
|
|
||||||
type: string
|
|
||||||
emitter_chain:
|
|
||||||
type: string
|
|
||||||
from:
|
|
||||||
type: string
|
|
||||||
to:
|
|
||||||
type: string
|
|
||||||
volume:
|
|
||||||
type: integer
|
|
||||||
type: object
|
|
||||||
transactions.ChainPair:
|
transactions.ChainPair:
|
||||||
properties:
|
properties:
|
||||||
destinationChain:
|
destinationChain:
|
||||||
|
@ -1027,6 +1012,7 @@ definitions:
|
||||||
- 14
|
- 14
|
||||||
- 15
|
- 15
|
||||||
- 16
|
- 16
|
||||||
|
- 17
|
||||||
- 18
|
- 18
|
||||||
- 19
|
- 19
|
||||||
- 20
|
- 20
|
||||||
|
@ -1034,35 +1020,24 @@ definitions:
|
||||||
- 22
|
- 22
|
||||||
- 23
|
- 23
|
||||||
- 24
|
- 24
|
||||||
- 25
|
|
||||||
- 26
|
- 26
|
||||||
- 28
|
- 28
|
||||||
- 29
|
- 29
|
||||||
- 30
|
- 30
|
||||||
- 32
|
- 32
|
||||||
- 33
|
|
||||||
- 34
|
- 34
|
||||||
- 35
|
- 35
|
||||||
- 36
|
|
||||||
- 37
|
|
||||||
- 38
|
|
||||||
- 39
|
|
||||||
- 3104
|
- 3104
|
||||||
- 4000
|
- 4000
|
||||||
- 4001
|
- 4001
|
||||||
- 4002
|
- 4002
|
||||||
- 4003
|
- 4003
|
||||||
- 4004
|
- 4004
|
||||||
- 4005
|
|
||||||
- 4006
|
|
||||||
- 4007
|
|
||||||
- 4008
|
|
||||||
- 10002
|
- 10002
|
||||||
- 10003
|
- 10003
|
||||||
- 10004
|
- 10004
|
||||||
- 10005
|
- 10005
|
||||||
- 10006
|
- 10006
|
||||||
- 10007
|
|
||||||
type: integer
|
type: integer
|
||||||
x-enum-varnames:
|
x-enum-varnames:
|
||||||
- ChainIDUnset
|
- ChainIDUnset
|
||||||
|
@ -1082,6 +1057,7 @@ definitions:
|
||||||
- ChainIDCelo
|
- ChainIDCelo
|
||||||
- ChainIDNear
|
- ChainIDNear
|
||||||
- ChainIDMoonbeam
|
- ChainIDMoonbeam
|
||||||
|
- ChainIDNeon
|
||||||
- ChainIDTerra2
|
- ChainIDTerra2
|
||||||
- ChainIDInjective
|
- ChainIDInjective
|
||||||
- ChainIDOsmosis
|
- ChainIDOsmosis
|
||||||
|
@ -1089,35 +1065,24 @@ definitions:
|
||||||
- ChainIDAptos
|
- ChainIDAptos
|
||||||
- ChainIDArbitrum
|
- ChainIDArbitrum
|
||||||
- ChainIDOptimism
|
- ChainIDOptimism
|
||||||
- ChainIDGnosis
|
|
||||||
- ChainIDPythNet
|
- ChainIDPythNet
|
||||||
- ChainIDXpla
|
- ChainIDXpla
|
||||||
- ChainIDBtc
|
- ChainIDBtc
|
||||||
- ChainIDBase
|
- ChainIDBase
|
||||||
- ChainIDSei
|
- ChainIDSei
|
||||||
- ChainIDRootstock
|
|
||||||
- ChainIDScroll
|
- ChainIDScroll
|
||||||
- ChainIDMantle
|
- ChainIDMantle
|
||||||
- ChainIDBlast
|
|
||||||
- ChainIDXLayer
|
|
||||||
- ChainIDLinea
|
|
||||||
- ChainIDBerachain
|
|
||||||
- ChainIDWormchain
|
- ChainIDWormchain
|
||||||
- ChainIDCosmoshub
|
- ChainIDCosmoshub
|
||||||
- ChainIDEvmos
|
- ChainIDEvmos
|
||||||
- ChainIDKujira
|
- ChainIDKujira
|
||||||
- ChainIDNeutron
|
- ChainIDNeutron
|
||||||
- ChainIDCelestia
|
- ChainIDCelestia
|
||||||
- ChainIDStargaze
|
|
||||||
- ChainIDSeda
|
|
||||||
- ChainIDDymension
|
|
||||||
- ChainIDProvenance
|
|
||||||
- ChainIDSepolia
|
- ChainIDSepolia
|
||||||
- ChainIDArbitrumSepolia
|
- ChainIDArbitrumSepolia
|
||||||
- ChainIDBaseSepolia
|
- ChainIDBaseSepolia
|
||||||
- ChainIDOptimismSepolia
|
- ChainIDOptimismSepolia
|
||||||
- ChainIDHolesky
|
- ChainIDHolesky
|
||||||
- ChainIDPolygonSepolia
|
|
||||||
vaa.VaaDoc:
|
vaa.VaaDoc:
|
||||||
properties:
|
properties:
|
||||||
appId:
|
appId:
|
||||||
|
@ -2361,52 +2326,6 @@ paths:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
tags:
|
tags:
|
||||||
- wormholescan
|
- wormholescan
|
||||||
/api/v1/x-chain-activity/tops:
|
|
||||||
get:
|
|
||||||
description: Search, for a specific period of time, the number of transactions
|
|
||||||
and the volume.
|
|
||||||
operationId: x-chain-activity-tops
|
|
||||||
parameters:
|
|
||||||
- description: 'Time span, supported values: 1d, 1mo and 1y'
|
|
||||||
in: query
|
|
||||||
name: timespan
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- description: From date, supported format 2006-01-02T15:04:05Z07:00
|
|
||||||
in: query
|
|
||||||
name: from
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- description: To date, supported format 2006-01-02T15:04:05Z07:00
|
|
||||||
in: query
|
|
||||||
name: to
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- description: Search by appId
|
|
||||||
in: query
|
|
||||||
name: appId
|
|
||||||
type: string
|
|
||||||
- description: Search by sourceChain
|
|
||||||
in: query
|
|
||||||
name: sourceChain
|
|
||||||
type: string
|
|
||||||
- description: Search by targetChain
|
|
||||||
in: query
|
|
||||||
name: targetChain
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/transactions.ChainActivityTopResult'
|
|
||||||
type: array
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
tags:
|
|
||||||
- wormholescan
|
|
||||||
/swagger.json:
|
/swagger.json:
|
||||||
get:
|
get:
|
||||||
description: Returns the swagger specification for this API.
|
description: Returns the swagger specification for this API.
|
||||||
|
|
|
@ -143,17 +143,6 @@ type ChainActivityResult struct {
|
||||||
Volume uint64 `mapstructure:"_value" json:"volume"`
|
Volume uint64 `mapstructure:"_value" json:"volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainActivityTopResult struct {
|
|
||||||
Time time.Time `json:"from" mapstructure:"_time"`
|
|
||||||
To string `json:"to" mapstructure:"to"`
|
|
||||||
ChainSourceID string `mapstructure:"emitter_chain" json:"emitter_chain"`
|
|
||||||
ChainDestinationID string `mapstructure:"destination_chain" json:"destination_chain,omitempty"`
|
|
||||||
Volume uint64 `mapstructure:"volume" json:"volume"`
|
|
||||||
Txs uint64 `mapstructure:"count" json:"count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChainActivityTopResults []ChainActivityTopResult
|
|
||||||
|
|
||||||
type ChainActivityTimeSpan string
|
type ChainActivityTimeSpan string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -213,25 +202,3 @@ type TransactionDto struct {
|
||||||
Payload map[string]interface{} `bson:"payload"`
|
Payload map[string]interface{} `bson:"payload"`
|
||||||
StandardizedProperties map[string]interface{} `bson:"standardizedProperties"`
|
StandardizedProperties map[string]interface{} `bson:"standardizedProperties"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainActivityTopsQuery struct {
|
|
||||||
SourceChain *sdk.ChainID `json:"source_chain"`
|
|
||||||
TargetChain *sdk.ChainID `json:"target_chain"`
|
|
||||||
AppId string `json:"app_id"`
|
|
||||||
From time.Time `json:"from"`
|
|
||||||
To time.Time `json:"to"`
|
|
||||||
Timespan Timespan `json:"timespan"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Timespan string
|
|
||||||
|
|
||||||
const (
|
|
||||||
Hour Timespan = "1h"
|
|
||||||
Day Timespan = "1d"
|
|
||||||
Month Timespan = "1mo"
|
|
||||||
Year Timespan = "1y"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t Timespan) IsValid() bool {
|
|
||||||
return t == Hour || t == Day || t == Month || t == Year
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package transactions
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -1049,338 +1048,3 @@ func (r *Repository) ListTransactionsByAddress(
|
||||||
|
|
||||||
return documents, nil
|
return documents, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) FindChainActivityTops(ctx *fasthttp.RequestCtx, q ChainActivityTopsQuery) ([]ChainActivityTopResult, error) {
|
|
||||||
query := r.buildChainActivityQueryTops(q)
|
|
||||||
result, err := r.queryAPI.Query(ctx, query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if result.Err() != nil {
|
|
||||||
return nil, result.Err()
|
|
||||||
}
|
|
||||||
var response []ChainActivityTopResult
|
|
||||||
for result.Next() {
|
|
||||||
var row ChainActivityTopResult
|
|
||||||
if err = mapstructure.Decode(result.Record().Values(), &row); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
parsedTime, errTime := time.Parse(time.RFC3339Nano, row.To)
|
|
||||||
if errTime == nil {
|
|
||||||
row.To = parsedTime.Format(time.RFC3339)
|
|
||||||
}
|
|
||||||
response = append(response, row)
|
|
||||||
}
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) buildChainActivityQueryTops(q ChainActivityTopsQuery) string {
|
|
||||||
|
|
||||||
var start, stop string
|
|
||||||
|
|
||||||
switch q.Timespan {
|
|
||||||
case Hour:
|
|
||||||
start = q.From.Truncate(1 * time.Hour).UTC().Format(time.RFC3339)
|
|
||||||
stop = q.To.Truncate(1 * time.Hour).UTC().Format(time.RFC3339)
|
|
||||||
case Day:
|
|
||||||
start = q.From.Truncate(24 * time.Hour).UTC().Format(time.RFC3339)
|
|
||||||
stop = q.To.Truncate(24 * time.Hour).UTC().Format(time.RFC3339)
|
|
||||||
case Month:
|
|
||||||
start = time.Date(q.From.Year(), q.From.Month(), 1, 0, 0, 0, 0, q.From.Location()).UTC().Format(time.RFC3339)
|
|
||||||
stop = time.Date(q.To.Year(), q.To.Month(), 1, 0, 0, 0, 0, q.To.Location()).UTC().Format(time.RFC3339)
|
|
||||||
default:
|
|
||||||
start = time.Date(q.From.Year(), 1, 1, 0, 0, 0, 0, q.From.Location()).UTC().Format(time.RFC3339)
|
|
||||||
stop = time.Date(q.To.Year(), 1, 1, 0, 0, 0, 0, q.To.Location()).UTC().Format(time.RFC3339)
|
|
||||||
}
|
|
||||||
|
|
||||||
filterTargetChain := ""
|
|
||||||
if q.TargetChain != nil {
|
|
||||||
filterTargetChain = "|> filter(fn: (r) => r.destination_chain == \"" + strconv.Itoa(int(*q.TargetChain)) + "\")"
|
|
||||||
}
|
|
||||||
|
|
||||||
filterSourceChain := ""
|
|
||||||
if q.SourceChain != nil {
|
|
||||||
filterSourceChain = "|> filter(fn: (r) => r.emitter_chain == \"" + strconv.Itoa(int(*q.SourceChain)) + "\")"
|
|
||||||
}
|
|
||||||
|
|
||||||
filterAppId := ""
|
|
||||||
if q.AppId != "" {
|
|
||||||
filterAppId = "|> filter(fn: (r) => r.app_id == \"" + q.AppId + "\")"
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.TargetChain == nil && q.AppId == "" {
|
|
||||||
return r.buildQueryChainActivityTopsByEmitter(q, start, stop, filterSourceChain)
|
|
||||||
}
|
|
||||||
|
|
||||||
var query string
|
|
||||||
switch q.Timespan {
|
|
||||||
case Hour:
|
|
||||||
query = r.buildQueryChainActivityHourly(start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
case Day:
|
|
||||||
query = r.buildQueryChainActivityDaily(start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
case Month:
|
|
||||||
query = r.buildQueryChainActivityMonthly(start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
default:
|
|
||||||
query = r.buildQueryChainActivityYearly(start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
}
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) buildQueryChainActivityTopsByEmitter(q ChainActivityTopsQuery, start, stop, filterSourceChain string) string {
|
|
||||||
|
|
||||||
measurement := ""
|
|
||||||
switch q.Timespan {
|
|
||||||
case Hour:
|
|
||||||
measurement = "emitter_chain_activity_1h"
|
|
||||||
default:
|
|
||||||
measurement = "emitter_chain_activity_1d"
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Timespan == Hour || q.Timespan == Day {
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
|
|
||||||
from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "%s")
|
|
||||||
%s
|
|
||||||
|> pivot(rowKey:["_time","emitter_chain"], columnKey: ["_field"], valueColumn: "_value")
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, measurement, filterSourceChain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Timespan == Month {
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
import "join"
|
|
||||||
|
|
||||||
data = from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "%s")
|
|
||||||
%s
|
|
||||||
|> drop(columns:["to"])
|
|
||||||
|> window(every: 1mo, period:1mo)
|
|
||||||
|> drop(columns:["_time"])
|
|
||||||
|> rename(columns: {_start: "_time"})
|
|
||||||
|> map(fn: (r) => ({r with to: string(v: r._stop)}))
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> filter(fn: (r) => (r._field == "volume" and r._value > 0))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "volume"})
|
|
||||||
|
|
||||||
counts = data
|
|
||||||
|> filter(fn: (r) => (r._field == "count"))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "count"})
|
|
||||||
|
|
||||||
join.inner(
|
|
||||||
left: vols,
|
|
||||||
right: counts,
|
|
||||||
on: (l, r) => l._time == r._time and l.emitter_chain == r.emitter_chain,
|
|
||||||
as: (l, r) => ({l with count: r.count}),
|
|
||||||
)
|
|
||||||
|> group()
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, measurement, filterSourceChain)
|
|
||||||
}
|
|
||||||
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
import "join"
|
|
||||||
|
|
||||||
data = from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "%s")
|
|
||||||
%s
|
|
||||||
|> drop(columns:["to"])
|
|
||||||
|> window(every: 1y, period:1y)
|
|
||||||
|> drop(columns:["_time"])
|
|
||||||
|> rename(columns: {_start: "_time"})
|
|
||||||
|> map(fn: (r) => ({r with to: string(v: r._stop)}))
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "volume"})
|
|
||||||
|
|
||||||
counts = data
|
|
||||||
|> filter(fn: (r) => (r._field == "count"))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "count"})
|
|
||||||
|
|
||||||
join.inner(
|
|
||||||
left: vols,
|
|
||||||
right: counts,
|
|
||||||
on: (l, r) => l._time == r._time and l.emitter_chain == r.emitter_chain,
|
|
||||||
as: (l, r) => ({l with count: r.count}),
|
|
||||||
)
|
|
||||||
|> group()
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, measurement, filterSourceChain)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) buildQueryChainActivityHourly(start, stop, filterSourceChain, filterTargetChain, filterAppId string) string {
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
import "join"
|
|
||||||
|
|
||||||
data = from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "chain_activity_1h")
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|> drop(columns:["destination_chain"])
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> filter(fn: (r) => (r._field == "volume" and r._value > 0))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "volume"})
|
|
||||||
|
|
||||||
counts = data
|
|
||||||
|> filter(fn: (r) => (r._field == "count"))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "count"})
|
|
||||||
|
|
||||||
join.inner(
|
|
||||||
left: vols,
|
|
||||||
right: counts,
|
|
||||||
on: (l, r) => l._time == r._time and l.to == r.to and l.emitter_chain == r.emitter_chain,
|
|
||||||
as: (l, r) => ({l with count: r.count}),
|
|
||||||
)
|
|
||||||
|> group()
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) buildQueryChainActivityDaily(start, stop, filterSourceChain, filterTargetChain, filterAppId string) string {
|
|
||||||
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
import "join"
|
|
||||||
|
|
||||||
data = from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "chain_activity_1d")
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|> drop(columns:["destination_chain"])
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> filter(fn: (r) => (r._field == "volume" and r._value > 0))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "volume"})
|
|
||||||
|
|
||||||
counts = data
|
|
||||||
|> filter(fn: (r) => (r._field == "count"))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "count"})
|
|
||||||
|
|
||||||
join.inner(
|
|
||||||
left: vols,
|
|
||||||
right: counts,
|
|
||||||
on: (l, r) => l._time == r._time and l.to == r.to and l.emitter_chain == r.emitter_chain,
|
|
||||||
as: (l, r) => ({l with count: r.count}),
|
|
||||||
)
|
|
||||||
|> group()
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) buildQueryChainActivityMonthly(start, stop, filterSourceChain, filterTargetChain, filterAppId string) string {
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
import "join"
|
|
||||||
|
|
||||||
data = from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "chain_activity_1d")
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|> drop(columns:["destination_chain","to","app_id"])
|
|
||||||
|> window(every: 1mo, period:1mo)
|
|
||||||
|> drop(columns:["_time"])
|
|
||||||
|> rename(columns: {_start: "_time"})
|
|
||||||
|> map(fn: (r) => ({r with to: string(v: r._stop)}))
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> filter(fn: (r) => (r._field == "volume" and r._value > 0))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "volume"})
|
|
||||||
|
|
||||||
counts = data
|
|
||||||
|> filter(fn: (r) => (r._field == "count"))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "count"})
|
|
||||||
|
|
||||||
join.inner(
|
|
||||||
left: vols,
|
|
||||||
right: counts,
|
|
||||||
on: (l, r) => l._time == r._time and l.emitter_chain == r.emitter_chain,
|
|
||||||
as: (l, r) => ({l with count: r.count}),
|
|
||||||
)
|
|
||||||
|> group()
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) buildQueryChainActivityYearly(start, stop, filterSourceChain, filterTargetChain, filterAppId string) string {
|
|
||||||
query := `
|
|
||||||
import "date"
|
|
||||||
import "join"
|
|
||||||
|
|
||||||
data = from(bucket: "%s")
|
|
||||||
|> range(start: %s,stop: %s)
|
|
||||||
|> filter(fn: (r) => r._measurement == "chain_activity_1d")
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|> drop(columns:["destination_chain","to","app_id"])
|
|
||||||
|> window(every: 1y, period:1y)
|
|
||||||
|> drop(columns:["_time"])
|
|
||||||
|> rename(columns: {_start: "_time"})
|
|
||||||
|> map(fn: (r) => ({r with to: string(v: r._stop)}))
|
|
||||||
|
|
||||||
vols = data
|
|
||||||
|> filter(fn: (r) => (r._field == "volume" and r._value > 0))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "volume"})
|
|
||||||
|
|
||||||
counts = data
|
|
||||||
|> filter(fn: (r) => (r._field == "count"))
|
|
||||||
|> group(columns:["_time","to","emitter_chain"])
|
|
||||||
|> sum()
|
|
||||||
|> rename(columns: {_value: "count"})
|
|
||||||
|
|
||||||
join.inner(
|
|
||||||
left: vols,
|
|
||||||
right: counts,
|
|
||||||
on: (l, r) => l._time == r._time and l.emitter_chain == r.emitter_chain,
|
|
||||||
as: (l, r) => ({l with count: r.count}),
|
|
||||||
)
|
|
||||||
|> group()
|
|
||||||
|> sort(columns:["emitter_chain","_time"],desc:false)
|
|
||||||
`
|
|
||||||
return fmt.Sprintf(query, r.bucketInfiniteRetention, start, stop, filterSourceChain, filterTargetChain, filterAppId)
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,13 +2,12 @@ package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
errors "errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"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/metrics"
|
"github.com/wormhole-foundation/wormhole-explorer/api/internal/metrics"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
||||||
|
@ -35,7 +34,6 @@ const (
|
||||||
topAssetsByVolumeKey = "wormscan:top-assets-by-volume"
|
topAssetsByVolumeKey = "wormscan:top-assets-by-volume"
|
||||||
topChainPairsByNumTransfersKey = "wormscan:top-chain-pairs-by-num-transfers"
|
topChainPairsByNumTransfersKey = "wormscan:top-chain-pairs-by-num-transfers"
|
||||||
chainActivityKey = "wormscan:chain-activity"
|
chainActivityKey = "wormscan:chain-activity"
|
||||||
chainActivityTopsKey = "wormscan:chain-activity-tops"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewService create a new Service.
|
// NewService create a new Service.
|
||||||
|
@ -159,7 +157,7 @@ func (s *Service) GetTransactionByID(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(output) == 0 {
|
if len(output) == 0 {
|
||||||
return nil, errs.ErrNotFound
|
return nil, errors.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return matching document
|
// Return matching document
|
||||||
|
@ -169,44 +167,3 @@ func (s *Service) GetTransactionByID(
|
||||||
func (s *Service) GetTokenProvider() *domain.TokenProvider {
|
func (s *Service) GetTokenProvider() *domain.TokenProvider {
|
||||||
return s.tokenProvider
|
return s.tokenProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetChainActivityTops(ctx *fasthttp.RequestCtx, q ChainActivityTopsQuery) (ChainActivityTopResults, error) {
|
|
||||||
|
|
||||||
timeDuration := q.To.Sub(q.From)
|
|
||||||
|
|
||||||
if q.Timespan == Hour && timeDuration > 15*24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too large for hourly data. Max time range allowed: 15 days")
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Timespan == Day {
|
|
||||||
if timeDuration < 24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too small for daily data. Min time range allowed: 2 day")
|
|
||||||
}
|
|
||||||
|
|
||||||
if timeDuration > 365*24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too large for daily data. Max time range allowed: 1 year")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Timespan == Month {
|
|
||||||
if timeDuration < 30*24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too small for monthly data. Min time range allowed: 60 days")
|
|
||||||
}
|
|
||||||
|
|
||||||
if timeDuration > 10*365*24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too large for monthly data. Max time range allowed: 1 year")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Timespan == Year {
|
|
||||||
if timeDuration < 365*24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too small for yearly data. Min time range allowed: 1 year")
|
|
||||||
}
|
|
||||||
|
|
||||||
if timeDuration > 10*365*24*time.Hour {
|
|
||||||
return nil, errors.New("time range is too large for yearly data. Max time range allowed: 10 year")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.repo.FindChainActivityTops(ctx, q)
|
|
||||||
}
|
|
||||||
|
|
|
@ -61,6 +61,10 @@ func ExtractToChain(c *fiber.Ctx, l *zap.Logger) (*sdk.ChainID, error) {
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExtractChain(c *fiber.Ctx, l *zap.Logger) (*sdk.ChainID, error) {
|
||||||
|
return extractChainQueryParam(c, l, "chain")
|
||||||
|
}
|
||||||
|
|
||||||
func ExtractSourceChain(c *fiber.Ctx, l *zap.Logger) (*sdk.ChainID, error) {
|
func ExtractSourceChain(c *fiber.Ctx, l *zap.Logger) (*sdk.ChainID, error) {
|
||||||
return extractChainQueryParam(c, l, "sourceChain")
|
return extractChainQueryParam(c, l, "sourceChain")
|
||||||
}
|
}
|
||||||
|
@ -70,10 +74,12 @@ func ExtractTargetChain(c *fiber.Ctx, l *zap.Logger) (*sdk.ChainID, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractChainQueryParam(c *fiber.Ctx, l *zap.Logger, queryParam string) (*sdk.ChainID, error) {
|
func extractChainQueryParam(c *fiber.Ctx, l *zap.Logger, queryParam string) (*sdk.ChainID, error) {
|
||||||
|
|
||||||
param := c.Query(queryParam)
|
param := c.Query(queryParam)
|
||||||
if param == "" {
|
if param == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, err := strconv.ParseInt(param, 10, 16)
|
chain, err := strconv.ParseInt(param, 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
requestID := fmt.Sprintf("%v", c.Locals("requestid"))
|
requestID := fmt.Sprintf("%v", c.Locals("requestid"))
|
||||||
|
@ -84,6 +90,7 @@ func extractChainQueryParam(c *fiber.Ctx, l *zap.Logger, queryParam string) (*sd
|
||||||
|
|
||||||
return nil, response.NewInvalidParamError(c, "INVALID CHAIN VALUE", errors.WithStack(err))
|
return nil, response.NewInvalidParamError(c, "INVALID CHAIN VALUE", errors.WithStack(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := sdk.ChainID(chain)
|
result := sdk.ChainID(chain)
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
@ -351,13 +358,14 @@ func ExtractTimeSpanAndSampleRate(c *fiber.Ctx, l *zap.Logger) (string, string,
|
||||||
return timeSpan, sampleRate, nil
|
return timeSpan, sampleRate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExtractTime(c *fiber.Ctx, timeLayout, queryParam string) (*time.Time, error) {
|
func ExtractTime(c *fiber.Ctx, queryParam string) (*time.Time, error) {
|
||||||
// get the start_time from query params
|
// get the start_time from query params
|
||||||
date := c.Query(queryParam, "")
|
date := c.Query(queryParam, "")
|
||||||
if date == "" {
|
if date == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
t, err := time.Parse(timeLayout, date)
|
|
||||||
|
t, err := time.Parse("20060102T150405Z", date)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInvalidQueryParamError(c, fmt.Sprintf("INVALID <%s> QUERY PARAMETER", queryParam), nil)
|
return nil, response.NewInvalidQueryParamError(c, fmt.Sprintf("INVALID <%s> QUERY PARAMETER", queryParam), nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,6 @@ func RegisterRoutes(
|
||||||
api.Get("/last-txs", transactionCtrl.GetLastTransactions)
|
api.Get("/last-txs", transactionCtrl.GetLastTransactions)
|
||||||
api.Get("/scorecards", transactionCtrl.GetScorecards)
|
api.Get("/scorecards", transactionCtrl.GetScorecards)
|
||||||
api.Get("/x-chain-activity", transactionCtrl.GetChainActivity)
|
api.Get("/x-chain-activity", transactionCtrl.GetChainActivity)
|
||||||
api.Get("/x-chain-activity/tops", transactionCtrl.GetChainActivityTops)
|
|
||||||
api.Get("/top-assets-by-volume", transactionCtrl.GetTopAssets)
|
api.Get("/top-assets-by-volume", transactionCtrl.GetTopAssets)
|
||||||
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)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
|
@ -183,75 +182,6 @@ func (c *Controller) GetTopAssets(ctx *fiber.Ctx) error {
|
||||||
return ctx.JSON(response)
|
return ctx.JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainActivityTops godoc
|
|
||||||
// @Description Search for a specific period of time the number of transactions and the volume.
|
|
||||||
// @Tags wormholescan
|
|
||||||
// @ID x-chain-activity-tops
|
|
||||||
// @Method Get
|
|
||||||
// @Param timespan query string true "Time span, supported values: 1d, 1mo and 1y"
|
|
||||||
// @Param from query string true "From date, supported format 2006-01-02T15:04:05Z07:00"
|
|
||||||
// @Param to query string true "To date, supported format 2006-01-02T15:04:05Z07:00"
|
|
||||||
// @Param appId query string false "Search by appId"
|
|
||||||
// @Param sourceChain query string false "Search by sourceChain"
|
|
||||||
// @Param targetChain query string false "Search by targetChain"
|
|
||||||
// @Success 200 {object} transactions.ChainActivityTopResults
|
|
||||||
// @Failure 400
|
|
||||||
// @Failure 500
|
|
||||||
// @Router /api/v1/x-chain-activity/tops [get]
|
|
||||||
func (c *Controller) GetChainActivityTops(ctx *fiber.Ctx) error {
|
|
||||||
|
|
||||||
sourceChain, err := middleware.ExtractSourceChain(ctx, c.logger)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
targetChain, err := middleware.ExtractTargetChain(ctx, c.logger)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
from, err := middleware.ExtractTime(ctx, time.RFC3339, "from")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
to, err := middleware.ExtractTime(ctx, time.RFC3339, "to")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if from == nil || to == nil {
|
|
||||||
return response.NewInvalidParamError(ctx, "missing from/to query params ", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := transactions.ChainActivityTopsQuery{
|
|
||||||
SourceChain: sourceChain,
|
|
||||||
TargetChain: targetChain,
|
|
||||||
From: *from,
|
|
||||||
To: *to,
|
|
||||||
AppId: middleware.ExtractAppId(ctx, c.logger),
|
|
||||||
Timespan: transactions.Timespan(ctx.Query("timespan")),
|
|
||||||
}
|
|
||||||
|
|
||||||
if !payload.Timespan.IsValid() {
|
|
||||||
return response.NewInvalidParamError(ctx, "invalid timespan", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
nowUTC := time.Now().UTC()
|
|
||||||
if nowUTC.Before(payload.To.UTC()) {
|
|
||||||
payload.To = nowUTC
|
|
||||||
}
|
|
||||||
|
|
||||||
if payload.To.Sub(payload.From) <= 0 {
|
|
||||||
return response.NewInvalidParamError(ctx, "invalid time range", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the chain activity.
|
|
||||||
activity, err := c.srv.GetChainActivityTops(ctx.Context(), payload)
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Error("Error getting chain activity", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.JSON(activity)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChainActivity godoc
|
// GetChainActivity godoc
|
||||||
// @Description Returns a list of chain pairs by origin chain and destination chain.
|
// @Description Returns a list of chain pairs by origin chain and destination chain.
|
||||||
// @Description The list could be rendered by notional or transaction count.
|
// @Description The list could be rendered by notional or transaction count.
|
||||||
|
|
Loading…
Reference in New Issue