mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 12:26:19 +00:00
Remove Uniswap watchers and related artifacts (#163)
* Remove Uniswap watchers and related code * Remove Uniswap artifacts from graph-node * Remove Uniswap artifacts from graph-test-watcher
This commit is contained in:
parent
bc1c267813
commit
80682e2755
28
README.md
28
README.md
@ -81,8 +81,6 @@ Create the databases for the watchers:
|
|||||||
```
|
```
|
||||||
createdb erc20-watcher
|
createdb erc20-watcher
|
||||||
createdb address-watcher
|
createdb address-watcher
|
||||||
createdb uni-watcher
|
|
||||||
createdb uni-info-watcher
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Create the databases for the job queues and enable the `pgcrypto` extension on them (https://github.com/timgit/pg-boss/blob/master/docs/usage.md#intro):
|
Create the databases for the job queues and enable the `pgcrypto` extension on them (https://github.com/timgit/pg-boss/blob/master/docs/usage.md#intro):
|
||||||
@ -90,8 +88,6 @@ Create the databases for the job queues and enable the `pgcrypto` extension on t
|
|||||||
```
|
```
|
||||||
createdb erc20-watcher-job-queue
|
createdb erc20-watcher-job-queue
|
||||||
createdb address-watcher-job-queue
|
createdb address-watcher-job-queue
|
||||||
createdb uni-watcher-job-queue
|
|
||||||
createdb uni-info-watcher-job-queue
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -118,30 +114,6 @@ CREATE EXTENSION
|
|||||||
address-watcher-job-queue=# exit
|
address-watcher-job-queue=# exit
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
|
||||||
postgres@tesla:~$ psql -U postgres -h localhost uni-watcher-job-queue
|
|
||||||
Password for user postgres:
|
|
||||||
psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1))
|
|
||||||
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
|
|
||||||
Type "help" for help.
|
|
||||||
|
|
||||||
uni-watcher-job-queue=# CREATE EXTENSION pgcrypto;
|
|
||||||
CREATE EXTENSION
|
|
||||||
uni-watcher-job-queue=# exit
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
postgres@tesla:~$ psql -U postgres -h localhost uni-info-watcher-job-queue
|
|
||||||
Password for user postgres:
|
|
||||||
psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1))
|
|
||||||
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
|
|
||||||
Type "help" for help.
|
|
||||||
|
|
||||||
uni-info-watcher-job-queue=# CREATE EXTENSION pgcrypto;
|
|
||||||
CREATE EXTENSION
|
|
||||||
uni-info-watcher-job-queue=# exit
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Reset
|
#### Reset
|
||||||
|
|
||||||
Reset the databases used by the watchers:
|
Reset the databases used by the watchers:
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
"test": "lerna run test --stream --ignore @vulcanize/*-watcher",
|
"test": "lerna run test --stream --ignore @vulcanize/*-watcher",
|
||||||
"build": "lerna run build --stream",
|
"build": "lerna run build --stream",
|
||||||
"build:watch": "lerna run build --stream --parallel -- -w",
|
"build:watch": "lerna run build --stream --parallel -- -w",
|
||||||
"build:contracts": "lerna run build:contracts",
|
|
||||||
"db:reset": "sudo ./scripts/reset-dbs.sh",
|
"db:reset": "sudo ./scripts/reset-dbs.sh",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
}
|
}
|
||||||
|
@ -1,148 +0,0 @@
|
|||||||
[
|
|
||||||
{ "inputs": [], "stateMutability": "nonpayable", "type": "constructor" },
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "FeeAmountEnabled",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "oldOwner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "newOwner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "OwnerChanged",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "pool",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "PoolCreated",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "tokenA", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "tokenB", "type": "address" },
|
|
||||||
{ "internalType": "uint24", "name": "fee", "type": "uint24" }
|
|
||||||
],
|
|
||||||
"name": "createPool",
|
|
||||||
"outputs": [
|
|
||||||
{ "internalType": "address", "name": "pool", "type": "address" }
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "uint24", "name": "fee", "type": "uint24" },
|
|
||||||
{ "internalType": "int24", "name": "tickSpacing", "type": "int24" }
|
|
||||||
],
|
|
||||||
"name": "enableFeeAmount",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [{ "internalType": "uint24", "name": "", "type": "uint24" }],
|
|
||||||
"name": "feeAmountTickSpacing",
|
|
||||||
"outputs": [{ "internalType": "int24", "name": "", "type": "int24" }],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "", "type": "address" },
|
|
||||||
{ "internalType": "uint24", "name": "", "type": "uint24" }
|
|
||||||
],
|
|
||||||
"name": "getPool",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "owner",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "parameters",
|
|
||||||
"outputs": [
|
|
||||||
{ "internalType": "address", "name": "factory", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "token0", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "token1", "type": "address" },
|
|
||||||
{ "internalType": "uint24", "name": "fee", "type": "uint24" },
|
|
||||||
{ "internalType": "int24", "name": "tickSpacing", "type": "int24" }
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "_owner", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "setOwner",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,988 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Burn",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Collect",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "CollectProtocol",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "paid0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "paid1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Flash",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNextOld",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNextNew",
|
|
||||||
"type": "uint16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "IncreaseObservationCardinalityNext",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Initialize",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Mint",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0Old",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1Old",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0New",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1New",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "SetFeeProtocol",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "liquidity",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Swap",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "burn",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "collect",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "collectProtocol",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "factory",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "fee",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "feeGrowthGlobal0X128",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "feeGrowthGlobal1X128",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "flash",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNext",
|
|
||||||
"type": "uint16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "increaseObservationCardinalityNext",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "initialize",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "liquidity",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "maxLiquidityPerTick",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "mint",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "index",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "observations",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "blockTimestamp",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulative",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityCumulativeX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "initialized",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32[]",
|
|
||||||
"name": "secondsAgos",
|
|
||||||
"type": "uint32[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "observe",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int56[]",
|
|
||||||
"name": "tickCumulatives",
|
|
||||||
"type": "int56[]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160[]",
|
|
||||||
"name": "secondsPerLiquidityCumulativeX128s",
|
|
||||||
"type": "uint160[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "bytes32",
|
|
||||||
"name": "key",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "positions",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "_liquidity",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthInside0LastX128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthInside1LastX128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "tokensOwed0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "tokensOwed1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "protocolFees",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setFeeProtocol",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "slot0",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationIndex",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinality",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNext",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "unlocked",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "snapshotCumulativesInside",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulativeInside",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityInsideX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "secondsInside",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "zeroForOne",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amountSpecified",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceLimitX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "swap",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "int256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int16",
|
|
||||||
"name": "wordPosition",
|
|
||||||
"type": "int16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "tickBitmap",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ticks",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "liquidityGross",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int128",
|
|
||||||
"name": "liquidityNet",
|
|
||||||
"type": "int128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthOutside0X128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthOutside1X128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulativeOutside",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityOutsideX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "secondsOutside",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "initialized",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "token0",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "token1",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,10 +0,0 @@
|
|||||||
import { PoolCreated } from '../../generated/Factory/Factory';
|
|
||||||
import { Pool as PoolTemplate } from '../../generated/templates';
|
|
||||||
import { log } from '@graphprotocol/graph-ts';
|
|
||||||
|
|
||||||
export function handlePoolCreated (event: PoolCreated): void {
|
|
||||||
log.debug('PoolCreated event', []);
|
|
||||||
|
|
||||||
// create the tracked contract based on the template
|
|
||||||
PoolTemplate.create(event.params.pool);
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { dataSource, ethereum, log } from '@graphprotocol/graph-ts';
|
|
||||||
|
|
||||||
import { Initialize } from '../../generated/templates/Pool/Pool';
|
|
||||||
|
|
||||||
export function handleInitialize (event: Initialize): void {
|
|
||||||
log.debug('event.address: {}', [event.address.toHexString()]);
|
|
||||||
log.debug('event.params.sqrtPriceX96: {}', [event.params.sqrtPriceX96.toString()]);
|
|
||||||
log.debug('event.params.tick: {}', [event.params.tick.toString()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleBlock (block: ethereum.Block): void {
|
|
||||||
log.debug('block info: {}', [block.number.toString()]);
|
|
||||||
log.debug('dataSource address: {}', [dataSource.address().toHex()]);
|
|
||||||
}
|
|
@ -1,238 +0,0 @@
|
|||||||
{
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "FeeAmountEnabled",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "oldOwner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "newOwner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "OwnerChanged",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "pool",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "PoolCreated",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "tokenA",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "tokenB",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "createPool",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "pool",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "enableFeeAmount",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "feeAmountTickSpacing",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "getPool",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "owner",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "parameters",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "factory",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setOwner",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,990 +0,0 @@
|
|||||||
{
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Burn",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Collect",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "CollectProtocol",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "paid0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "paid1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Flash",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNextOld",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNextNew",
|
|
||||||
"type": "uint16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "IncreaseObservationCardinalityNext",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Initialize",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Mint",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0Old",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1Old",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0New",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1New",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "SetFeeProtocol",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "liquidity",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Swap",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "burn",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "collect",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "collectProtocol",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "factory",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "fee",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "feeGrowthGlobal0X128",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "feeGrowthGlobal1X128",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "flash",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNext",
|
|
||||||
"type": "uint16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "increaseObservationCardinalityNext",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "initialize",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "liquidity",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "maxLiquidityPerTick",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "mint",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "index",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "observations",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "blockTimestamp",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulative",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityCumulativeX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "initialized",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32[]",
|
|
||||||
"name": "secondsAgos",
|
|
||||||
"type": "uint32[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "observe",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int56[]",
|
|
||||||
"name": "tickCumulatives",
|
|
||||||
"type": "int56[]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160[]",
|
|
||||||
"name": "secondsPerLiquidityCumulativeX128s",
|
|
||||||
"type": "uint160[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "bytes32",
|
|
||||||
"name": "key",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "positions",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "_liquidity",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthInside0LastX128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthInside1LastX128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "tokensOwed0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "tokensOwed1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "protocolFees",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setFeeProtocol",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "slot0",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationIndex",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinality",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNext",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "unlocked",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "snapshotCumulativesInside",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulativeInside",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityInsideX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "secondsInside",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "zeroForOne",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amountSpecified",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceLimitX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "swap",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "int256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int16",
|
|
||||||
"name": "wordPosition",
|
|
||||||
"type": "int16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "tickBitmap",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ticks",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "liquidityGross",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int128",
|
|
||||||
"name": "liquidityNet",
|
|
||||||
"type": "int128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthOutside0X128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthOutside1X128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulativeOutside",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityOutsideX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "secondsOutside",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "initialized",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "token0",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "token1",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -38,8 +38,6 @@ import { IpldStatus } from './entity/IpldStatus';
|
|||||||
import { BlockProgress } from './entity/BlockProgress';
|
import { BlockProgress } from './entity/BlockProgress';
|
||||||
import { IPLDBlock } from './entity/IPLDBlock';
|
import { IPLDBlock } from './entity/IPLDBlock';
|
||||||
import Example1Artifacts from './artifacts/Example.json';
|
import Example1Artifacts from './artifacts/Example.json';
|
||||||
import FactoryArtifacts from './artifacts/Factory.json';
|
|
||||||
import PoolArtifacts from './artifacts/Pool.json';
|
|
||||||
import { createInitialState, handleEvent, createStateDiff, createStateCheckpoint } from './hooks';
|
import { createInitialState, handleEvent, createStateDiff, createStateCheckpoint } from './hooks';
|
||||||
import { Author } from './entity/Author';
|
import { Author } from './entity/Author';
|
||||||
import { Blog } from './entity/Blog';
|
import { Blog } from './entity/Blog';
|
||||||
@ -49,8 +47,6 @@ const log = debug('vulcanize:indexer');
|
|||||||
const JSONbigNative = JSONbig({ useNativeBigInt: true });
|
const JSONbigNative = JSONbig({ useNativeBigInt: true });
|
||||||
|
|
||||||
const KIND_EXAMPLE1 = 'Example1';
|
const KIND_EXAMPLE1 = 'Example1';
|
||||||
const KIND_FACTORY = 'Factory';
|
|
||||||
const KIND_POOL = 'Pool';
|
|
||||||
|
|
||||||
export type ResultEvent = {
|
export type ResultEvent = {
|
||||||
block: {
|
block: {
|
||||||
@ -128,28 +124,12 @@ export class Indexer implements IPLDIndexerInterface {
|
|||||||
storageLayout: Example1StorageLayout
|
storageLayout: Example1StorageLayout
|
||||||
} = Example1Artifacts;
|
} = Example1Artifacts;
|
||||||
|
|
||||||
const {
|
|
||||||
abi: FactoryABI
|
|
||||||
} = FactoryArtifacts;
|
|
||||||
|
|
||||||
const {
|
|
||||||
abi: PoolABI
|
|
||||||
} = PoolArtifacts;
|
|
||||||
|
|
||||||
assert(Example1ABI);
|
assert(Example1ABI);
|
||||||
assert(Example1StorageLayout);
|
assert(Example1StorageLayout);
|
||||||
this._abiMap.set(KIND_EXAMPLE1, Example1ABI);
|
this._abiMap.set(KIND_EXAMPLE1, Example1ABI);
|
||||||
this._storageLayoutMap.set(KIND_EXAMPLE1, Example1StorageLayout);
|
this._storageLayoutMap.set(KIND_EXAMPLE1, Example1StorageLayout);
|
||||||
this._contractMap.set(KIND_EXAMPLE1, new ethers.utils.Interface(Example1ABI));
|
this._contractMap.set(KIND_EXAMPLE1, new ethers.utils.Interface(Example1ABI));
|
||||||
|
|
||||||
assert(FactoryABI);
|
|
||||||
this._abiMap.set(KIND_FACTORY, FactoryABI);
|
|
||||||
this._contractMap.set(KIND_FACTORY, new ethers.utils.Interface(FactoryABI));
|
|
||||||
|
|
||||||
assert(PoolABI);
|
|
||||||
this._abiMap.set(KIND_POOL, PoolABI);
|
|
||||||
this._contractMap.set(KIND_POOL, new ethers.utils.Interface(PoolABI));
|
|
||||||
|
|
||||||
this._entityTypesMap = new Map();
|
this._entityTypesMap = new Map();
|
||||||
this._populateEntityTypesMap();
|
this._populateEntityTypesMap();
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ type ResultEvent {
|
|||||||
proof: Proof
|
proof: Proof
|
||||||
}
|
}
|
||||||
|
|
||||||
union Event = TestEvent | PoolCreatedEvent | InitializeEvent
|
union Event = TestEvent
|
||||||
|
|
||||||
type TestEvent {
|
type TestEvent {
|
||||||
param1: String!
|
param1: String!
|
||||||
@ -65,19 +65,6 @@ type TestEvent {
|
|||||||
param3: BigInt!
|
param3: BigInt!
|
||||||
}
|
}
|
||||||
|
|
||||||
type PoolCreatedEvent {
|
|
||||||
token0: String!
|
|
||||||
token1: String!
|
|
||||||
fee: Int!
|
|
||||||
tickSpacing: Int!
|
|
||||||
pool: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
type InitializeEvent {
|
|
||||||
sqrtPriceX96: BigInt!
|
|
||||||
tick: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultIPLDBlock {
|
type ResultIPLDBlock {
|
||||||
block: Block!
|
block: Block!
|
||||||
contractAddress: String!
|
contractAddress: String!
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
# Don't lint node_modules.
|
|
||||||
node_modules
|
|
||||||
|
|
||||||
# Don't lint build output.
|
|
||||||
dist
|
|
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"semistandard",
|
|
||||||
"plugin:@typescript-eslint/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 12,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"allowArgumentsExplicitlyTypedAsAny": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.test.ts", "test/*.ts"],
|
|
||||||
"rules": {
|
|
||||||
"no-unused-expressions": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
6
packages/uni-info-watcher/.gitignore
vendored
6
packages/uni-info-watcher/.gitignore
vendored
@ -1,6 +0,0 @@
|
|||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
node_modules/
|
|
||||||
build/
|
|
||||||
tmp/
|
|
||||||
temp/
|
|
@ -1,4 +0,0 @@
|
|||||||
timeout: '60000'
|
|
||||||
bail: true
|
|
||||||
exit: true # TODO: Find out why the program doesn't exit on its own.
|
|
||||||
require: 'ts-node/register'
|
|
@ -1,298 +0,0 @@
|
|||||||
# uni-info-watcher
|
|
||||||
|
|
||||||
## Instructions
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
Create a postgres12 database for the job queue:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo su - postgres
|
|
||||||
createdb uni-info-watcher-job-queue
|
|
||||||
```
|
|
||||||
|
|
||||||
Enable the `pgcrypto` extension on the job queue database (https://github.com/timgit/pg-boss/blob/master/docs/usage.md#intro).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
postgres@tesla:~$ psql -U postgres -h localhost uni-info-watcher-job-queue
|
|
||||||
Password for user postgres:
|
|
||||||
psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1))
|
|
||||||
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
|
|
||||||
Type "help" for help.
|
|
||||||
|
|
||||||
uni-watcher-job-queue=# CREATE EXTENSION pgcrypto;
|
|
||||||
CREATE EXTENSION
|
|
||||||
uni-info-watcher-job-queue=# exit
|
|
||||||
```
|
|
||||||
|
|
||||||
Create a postgres12 database for the uni-info watcher:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo su - postgres
|
|
||||||
createdb uni-info-watcher
|
|
||||||
```
|
|
||||||
|
|
||||||
Update `environments/local.toml` with database connection settings for both the databases.
|
|
||||||
|
|
||||||
### Run
|
|
||||||
|
|
||||||
* Build files:
|
|
||||||
```bash
|
|
||||||
$ yarn build
|
|
||||||
```
|
|
||||||
|
|
||||||
* Start the server:
|
|
||||||
```bash
|
|
||||||
$ yarn server
|
|
||||||
|
|
||||||
# For development.
|
|
||||||
$ yarn server:dev
|
|
||||||
|
|
||||||
# For specifying config file.
|
|
||||||
$ yarn server -f environments/local.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
* Start the job runner:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn job-runner
|
|
||||||
|
|
||||||
# For development.
|
|
||||||
$ yarn job-runner:dev
|
|
||||||
|
|
||||||
# For specifying config file.
|
|
||||||
$ yarn job-runner -f environments/local.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
* Run `yarn server:mock` to run server with mock data.
|
|
||||||
|
|
||||||
## Mock Queries
|
|
||||||
|
|
||||||
```graphql
|
|
||||||
{
|
|
||||||
bundle(id: "1", block: { number: 2 }) {
|
|
||||||
id
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
bundles(first: 1, block: { number: 2 }) {
|
|
||||||
id
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
burns(first: 2, orderBy: timestamp) {
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
id
|
|
||||||
origin
|
|
||||||
owner
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
factories(first: 1, block: { number: 2 }) {
|
|
||||||
id
|
|
||||||
totalFeesUSD
|
|
||||||
totalValueLockedUSD
|
|
||||||
totalVolumeUSD
|
|
||||||
txCount
|
|
||||||
}
|
|
||||||
|
|
||||||
mints(first: 2) {
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
id
|
|
||||||
origin
|
|
||||||
owner
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
sender
|
|
||||||
}
|
|
||||||
|
|
||||||
pools(first: 2, block: { number:2 }) {
|
|
||||||
feeTier
|
|
||||||
id
|
|
||||||
liquidity
|
|
||||||
sqrtPrice
|
|
||||||
tick
|
|
||||||
token0 {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token0Price
|
|
||||||
token1 {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token1Price
|
|
||||||
totalValueLockedToken0
|
|
||||||
totalValueLockedToken1
|
|
||||||
totalValueLockedUSD
|
|
||||||
txCount
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens {
|
|
||||||
derivedETH
|
|
||||||
feesUSD
|
|
||||||
id
|
|
||||||
name
|
|
||||||
symbol
|
|
||||||
totalValueLocked
|
|
||||||
totalValueLockedUSD
|
|
||||||
txCount
|
|
||||||
volume
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions(first: 2) {
|
|
||||||
burns {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
id
|
|
||||||
mints {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
swaps{
|
|
||||||
id
|
|
||||||
}
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
swaps(first: 2) {
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
id
|
|
||||||
origin
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
poolDayDatas(skip: 1, first: 2) {
|
|
||||||
date
|
|
||||||
id
|
|
||||||
tvlUSD
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenDayDatas(first: 2, where: {}) {
|
|
||||||
date
|
|
||||||
id
|
|
||||||
totalValueLockedUSD
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
uniswapDayDatas(skip:1, first: 2) {
|
|
||||||
date
|
|
||||||
id
|
|
||||||
tvlUSD
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
ticks(skip: 1, first: 2, block: { number: 2 }) {
|
|
||||||
id
|
|
||||||
liquidityGross
|
|
||||||
liquidityNet
|
|
||||||
price0
|
|
||||||
price1
|
|
||||||
tickIdx
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenHourDatas(skip: 1, first: 2) {
|
|
||||||
close
|
|
||||||
high
|
|
||||||
id
|
|
||||||
low
|
|
||||||
open
|
|
||||||
periodStartUnix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Queries with ID param
|
|
||||||
```graphql
|
|
||||||
{
|
|
||||||
pool(id: "0x38bb4e5eb41aeaeec59e60ba075298f4d4dfd2a2") {
|
|
||||||
feeTier
|
|
||||||
id
|
|
||||||
liquidity
|
|
||||||
sqrtPrice
|
|
||||||
tick
|
|
||||||
token0 {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token0Price
|
|
||||||
token1 {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token1Price
|
|
||||||
totalValueLockedToken0
|
|
||||||
totalValueLockedToken1
|
|
||||||
totalValueLockedUSD
|
|
||||||
txCount
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
token(id: "0xb87ddd8af3242e56e52318bacf27fe9dcc75c15a", block: { number:2}) {
|
|
||||||
derivedETH
|
|
||||||
feesUSD
|
|
||||||
id
|
|
||||||
name
|
|
||||||
symbol
|
|
||||||
totalValueLocked
|
|
||||||
totalValueLockedUSD
|
|
||||||
txCount
|
|
||||||
volume
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Scripts
|
|
||||||
|
|
||||||
* **generate:schema**
|
|
||||||
|
|
||||||
Generate schema for uniswap subgraph in graphql format. The `get-graphql-schema` tool is used to generate the schema (https://github.com/prisma-labs/get-graphql-schema). The uniswap subgraph graphql endpoint is provided in the script to generate the schema.
|
|
||||||
|
|
||||||
* **lint:schema**
|
|
||||||
|
|
||||||
Lint schema graphql files:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn lint:schema docs/analysis/schema/frontend.graphql
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test
|
|
||||||
|
|
||||||
### Smoke test
|
|
||||||
|
|
||||||
To run a smoke test:
|
|
||||||
|
|
||||||
* Start the server in `packages/erc-20-watcher`.
|
|
||||||
* Start the server and the job-runner in `packages/uni-watcher`.
|
|
||||||
* Start the server and the job-runner in `packages/uni-info-watcher`.
|
|
||||||
* Run the smoke test in `packages/uni-watcher` atleast once.
|
|
||||||
* Run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn smoke-test
|
|
||||||
```
|
|
||||||
|
|
@ -1,965 +0,0 @@
|
|||||||
# Aggregation in Entities
|
|
||||||
|
|
||||||
- Pool
|
|
||||||
* id (pool address)
|
|
||||||
- Factory PoolCreated event
|
|
||||||
```ts
|
|
||||||
let pool = new Pool(event.params.pool.toHexString()) as Pool
|
|
||||||
```
|
|
||||||
|
|
||||||
* feeTier (fee amount)
|
|
||||||
- Factory PoolCreated event
|
|
||||||
```ts
|
|
||||||
pool.feeTier = BigInt(event.params.fee)
|
|
||||||
```
|
|
||||||
|
|
||||||
* sqrtPrice (current price tracker)
|
|
||||||
- Pool Initialize event, Swap event
|
|
||||||
```ts
|
|
||||||
pool.sqrtPrice = event.params.sqrtPriceX96
|
|
||||||
```
|
|
||||||
|
|
||||||
* tick (current tick)
|
|
||||||
- Pool Initialize event, Swap event
|
|
||||||
```ts
|
|
||||||
pool.tick = BigInt(event.params.tick)
|
|
||||||
```
|
|
||||||
|
|
||||||
* token0Price (token0 per token1), token1Price(token1 per token0)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token)
|
|
||||||
pool.token0Price = prices[0]
|
|
||||||
pool.token1Price = prices[1]
|
|
||||||
```
|
|
||||||
* sqrtPriceX96ToTokenPrices (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/pricing.ts#L39)
|
|
||||||
- Uses Token entity `decimals` field
|
|
||||||
|
|
||||||
* totalValueLockedToken0 (total token 0 across all ticks), totalValueLockedToken1 (total token 1 across all ticks)
|
|
||||||
- Pool Mint event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0)
|
|
||||||
pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1)
|
|
||||||
```
|
|
||||||
* convertTokenToDecimal (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/index.ts#L72)
|
|
||||||
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
pool.totalValueLockedToken0 = pool.totalValueLockedToken0.minus(amount0)
|
|
||||||
pool.totalValueLockedToken1 = pool.totalValueLockedToken1.minus(amount1)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLockedUSD (tvl USD)
|
|
||||||
- Pool Initialize event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLockedETH (tvl derived ETH)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(poolAddress)
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
|
|
||||||
pool.totalValueLockedETH = pool.totalValueLockedToken0
|
|
||||||
.times(token0.derivedETH)
|
|
||||||
.plus(pool.totalValueLockedToken1.times(token1.derivedETH))
|
|
||||||
```
|
|
||||||
|
|
||||||
* txCount (all time number of transactions)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
|
|
||||||
// Constant ONE_BI is BigInt.fromI32(1)
|
|
||||||
pool.txCount = pool.txCount.plus(ONE_BI)
|
|
||||||
```
|
|
||||||
|
|
||||||
* volumeUSD (all time USD swapped)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
// Constant ZERO_BD is BigDecimal.fromString('0')
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
pool.volumeUSD = pool.volumeUSD.plus(amountTotalUSDTracked)
|
|
||||||
```
|
|
||||||
* getTrackedAmountUSD (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/pricing.ts#L110)
|
|
||||||
- Uses Bundle entity `ethPriceUSD` field
|
|
||||||
- Uses Token entity `derivedEth` field
|
|
||||||
|
|
||||||
* convertTokenToDecimal (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/index.ts#L72)
|
|
||||||
|
|
||||||
* liquidity (in range liquidity)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
|
|
||||||
if (
|
|
||||||
pool.tick !== null &&
|
|
||||||
BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) &&
|
|
||||||
BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt)
|
|
||||||
) {
|
|
||||||
pool.liquidity = pool.liquidity.plus(event.params.amount)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Token
|
|
||||||
* id (pool address)
|
|
||||||
- Factory PoolCreated event
|
|
||||||
```ts
|
|
||||||
let token0 = Token.load(event.params.token0.toHexString())
|
|
||||||
```
|
|
||||||
|
|
||||||
* decimals (token decimals)
|
|
||||||
- Factory PoolCreated event
|
|
||||||
```ts
|
|
||||||
let token0 = Token.load(event.params.token0.toHexString())
|
|
||||||
let decimals = fetchTokenDecimals(event.params.token0)
|
|
||||||
token0.decimals = decimals
|
|
||||||
```
|
|
||||||
* fetchTokenDecimals(https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/token.ts#L75)
|
|
||||||
- Uses ERC20 contract view method call `decimals`
|
|
||||||
|
|
||||||
* derivedETH (derived price in ETH)
|
|
||||||
- Pool Initialize event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
token0.derivedETH = findEthPerToken(token0 as Token)
|
|
||||||
```
|
|
||||||
* findEthPerToken (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/pricing.ts#L65)
|
|
||||||
- Uses Token entity `whitelistPools` field
|
|
||||||
- Uses Pool entity `liquidity`, `totalValueLockedToken1`, `token0Price` fields
|
|
||||||
|
|
||||||
* whitelistPools (pools token is in that are white listed for USD pricing)
|
|
||||||
- Factory PoolCreated event
|
|
||||||
```ts
|
|
||||||
let pool = new Pool(event.params.pool.toHexString()) as Pool
|
|
||||||
let token1 = Token.load(event.params.token1.toHexString())
|
|
||||||
|
|
||||||
if (WHITELIST_TOKENS.includes(token0.id)) {
|
|
||||||
let newPools = token1.whitelistPools
|
|
||||||
newPools.push(pool.id)
|
|
||||||
token1.whitelistPools = newPools
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* Constant WHITELIST_TOKENS (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/pricing.ts#L12)
|
|
||||||
|
|
||||||
* feesUSD (fees in USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
let feesUSD = amountTotalUSDTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000'))
|
|
||||||
token0.feesUSD = token0.feesUSD.plus(feesUSD)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLocked (liquidity across all pools in token units)
|
|
||||||
- Pool Mint event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
token0.totalValueLocked = token0.totalValueLocked.plus(amount0)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
token0.totalValueLocked = token0.totalValueLocked.minus(amount0)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLockedUSD (liquidity across all pools in derived USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD))
|
|
||||||
```
|
|
||||||
|
|
||||||
* txCount (transactions across all pools that include this token)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
token0.txCount = token0.txCount.plus(ONE_BI)
|
|
||||||
```
|
|
||||||
|
|
||||||
* volume (volume in token units)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount0Abs = amount0
|
|
||||||
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
token0.volume = token0.volume.plus(amount0Abs)
|
|
||||||
```
|
|
||||||
|
|
||||||
* volumeUSD (volume in derived USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
token0.volumeUSD = token0.volumeUSD.plus(amountTotalUSDTracked)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Factory
|
|
||||||
* id (factory address)
|
|
||||||
- Factory PoolCreated event
|
|
||||||
```ts
|
|
||||||
let factory = Factory.load(FACTORY_ADDRESS)
|
|
||||||
```
|
|
||||||
* Constant FACTORY_ADDRESS is in https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/constants.ts#L6
|
|
||||||
|
|
||||||
* totalFeesUSD (total swap fees all time in USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let factory = Factory.load(FACTORY_ADDRESS)
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
let feesUSD = amountTotalUSDTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000'))
|
|
||||||
factory.totalFeesUSD = factory.totalFeesUSD.plus(feesUSD)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLockedUSD (TVL derived in USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let factory = Factory.load(FACTORY_ADDRESS)
|
|
||||||
factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLockedETH (TVL derived in ETH)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let factory = Factory.load(FACTORY_ADDRESS)
|
|
||||||
factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH)
|
|
||||||
|
|
||||||
// After change in pool.totalValueLockedETH
|
|
||||||
factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH)
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalVolumeUSD (total volume all time in derived USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let factory = Factory.load(FACTORY_ADDRESS)
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
factory.totalVolumeUSD = factory.totalVolumeUSD.plus(amountTotalUSDTracked)
|
|
||||||
```
|
|
||||||
|
|
||||||
* txCount (amount of transactions all time)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let factory = Factory.load(FACTORY_ADDRESS)
|
|
||||||
factory.txCount = factory.txCount.plus(ONE_BI)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Bundle
|
|
||||||
Stores for USD calculations.
|
|
||||||
* id - Stores only one instance.
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
```
|
|
||||||
|
|
||||||
* ethPriceUSD (price of ETH in usd)
|
|
||||||
- Pool Initialize event, Swap event
|
|
||||||
```ts
|
|
||||||
bundle.ethPriceUSD = getEthPriceInUSD()
|
|
||||||
```
|
|
||||||
* getEthPriceInUSD (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/pricing.ts#L51)
|
|
||||||
- Uses Pool entity `token0Price` field
|
|
||||||
|
|
||||||
- Tick
|
|
||||||
* id (format: `<pool address>#<tick index>`)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let poolAddress = event.address.toHexString()
|
|
||||||
let pool = Pool.load(poolAddress)
|
|
||||||
let lowerTickIdx = event.params.tickLower
|
|
||||||
let lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString()
|
|
||||||
let lowerTick = Tick.load(lowerTickId)
|
|
||||||
|
|
||||||
if (lowerTick === null) {
|
|
||||||
lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* createTick (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/tick.ts#L8)
|
|
||||||
|
|
||||||
* liquidityGross (total liquidity pool has as tick lower or upper)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
lowerTick.liquidityGross = lowerTick.liquidityGross.plus(event.params.amount)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
lowerTick.liquidityGross = lowerTick.liquidityGross.minus(event.params.amount)
|
|
||||||
```
|
|
||||||
|
|
||||||
* liquidityNet (how much liquidity changes when tick crossed)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
lowerTick.liquidityNet = lowerTick.liquidityNet.plus(event.params.amount)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
lowerTick.liquidityNet = lowerTick.liquidityNet.minus(event.params.amount)
|
|
||||||
```
|
|
||||||
|
|
||||||
* price0 (calculated price of token0 of tick within this pool - constant)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event)
|
|
||||||
|
|
||||||
// Inside createTick
|
|
||||||
// tickIdx = lowerTickIdx
|
|
||||||
tick.price0 = bigDecimalExponated(BigDecimal.fromString('1.0001'), BigInt.fromI32(tickIdx))
|
|
||||||
```
|
|
||||||
|
|
||||||
* price1 (calculated price of token0 of tick within this pool - constant)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event)
|
|
||||||
|
|
||||||
// Inside createTick
|
|
||||||
// tickIdx = lowerTickIdx
|
|
||||||
let price0 = bigDecimalExponated(BigDecimal.fromString('1.0001'), BigInt.fromI32(tickIdx))
|
|
||||||
tick.price1 = safeDiv(ONE_BD, price0)
|
|
||||||
```
|
|
||||||
|
|
||||||
* tickIdx (tick index)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event)
|
|
||||||
|
|
||||||
// Inside createTick
|
|
||||||
// tickIdx = lowerTickIdx
|
|
||||||
tick.tickIdx = BigInt.fromI32(tickIdx)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Mint
|
|
||||||
* id (transaction hash + "#" + index in mints Transaction array)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let mint = new Mint(transaction.id.toString() + '#' + pool.txCount.toString())
|
|
||||||
```
|
|
||||||
|
|
||||||
* amount0 (amount of token 0 minted), amount1 (amount of token 1 minted)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
mint.amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
mint.amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
```
|
|
||||||
|
|
||||||
* amountUSD (derived amount based on available prices of tokens)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
mint.amountUSD = amount0
|
|
||||||
.times(token0.derivedETH.times(bundle.ethPriceUSD))
|
|
||||||
.plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD)))
|
|
||||||
```
|
|
||||||
|
|
||||||
* origin (txn origin)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
mint.origin = event.transaction.from
|
|
||||||
```
|
|
||||||
|
|
||||||
* owner (owner of position where liquidity minted to)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
mint.owner = event.params.owner
|
|
||||||
```
|
|
||||||
|
|
||||||
* pool (pool position is within)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let poolAddress = event.address.toHexString()
|
|
||||||
let pool = Pool.load(poolAddress)
|
|
||||||
mint.pool = pool.id
|
|
||||||
```
|
|
||||||
|
|
||||||
* sender (the address that minted the liquidity)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
mint.sender = event.params.sender
|
|
||||||
```
|
|
||||||
|
|
||||||
* timestamp (time of txn)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
mint.timestamp = transaction.timestamp
|
|
||||||
```
|
|
||||||
* loadTransaction (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/index.ts#L83)
|
|
||||||
- Uses Transaction entity
|
|
||||||
|
|
||||||
* transaction (which txn the mint was included in)
|
|
||||||
- Pool Mint event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
mint.transaction = transaction.id
|
|
||||||
```
|
|
||||||
|
|
||||||
- Burn
|
|
||||||
* id (transaction hash + "#" + index in mints Transaction array)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
let mint = new Burn(transaction.id + '#' + pool.txCount.toString())
|
|
||||||
```
|
|
||||||
|
|
||||||
* amount0 (amount of token 0 burned), amount1 (amount of token 1 burned)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
burn.amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
burn.amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
```
|
|
||||||
|
|
||||||
* amountUSD (derived amount based on available prices of tokens)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
burn.amountUSD = amount0
|
|
||||||
.times(token0.derivedETH.times(bundle.ethPriceUSD))
|
|
||||||
.plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD)))
|
|
||||||
```
|
|
||||||
|
|
||||||
* origin (txn origin)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
burn.origin = event.transaction.from
|
|
||||||
```
|
|
||||||
|
|
||||||
* owner (owner of position where liquidity was burned)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
burn.owner = event.params.owner
|
|
||||||
```
|
|
||||||
|
|
||||||
* pool (pool position is within)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
let poolAddress = event.address.toHexString()
|
|
||||||
let pool = Pool.load(poolAddress)
|
|
||||||
burn.pool = pool.id
|
|
||||||
```
|
|
||||||
|
|
||||||
* timestamp (need this to pull recent txns for specific token or pool)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
burn.timestamp = transaction.timestamp
|
|
||||||
```
|
|
||||||
|
|
||||||
* transaction (txn burn was included in)
|
|
||||||
- Pool Burn event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
burn.transaction = transaction.id
|
|
||||||
```
|
|
||||||
|
|
||||||
- Swap
|
|
||||||
* id (transaction hash + "#" + index in swaps Transaction array)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
let swap = new Swap(transaction.id + '#' + pool.txCount.toString())
|
|
||||||
```
|
|
||||||
|
|
||||||
* amount0 (allow indexing by tokens), amount1 (allow indexing by tokens)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
swap.amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
swap.amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
```
|
|
||||||
|
|
||||||
* amountUSD (derived info)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
swap.amountUSD = amountTotalUSDTracked
|
|
||||||
```
|
|
||||||
|
|
||||||
* origin (txn origin, the EOA that initiated the txn)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
swap.origin = event.transaction.from
|
|
||||||
```
|
|
||||||
|
|
||||||
* pool (pool swap occured within)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let poolAddress = event.address.toHexString()
|
|
||||||
let pool = Pool.load(poolAddress)
|
|
||||||
swap.pool = pool.id
|
|
||||||
```
|
|
||||||
|
|
||||||
* timestamp (timestamp of transaction)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
swap.timestamp = transaction.timestamp
|
|
||||||
```
|
|
||||||
|
|
||||||
* transaction (pointer to transaction)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
swap.transaction = transaction.id
|
|
||||||
```
|
|
||||||
|
|
||||||
- Transaction
|
|
||||||
* id (txn hash)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
NonfungiblePositionManager IncreaseLiquidity event, DecreaseLiquidity event, Collect event, Transfer event
|
|
||||||
```ts
|
|
||||||
let transaction = loadTransaction(event)
|
|
||||||
|
|
||||||
// Inside loadTransaction
|
|
||||||
let transaction = Transaction.load(event.transaction.hash.toHexString())
|
|
||||||
if (transaction === null) {
|
|
||||||
transaction = new Transaction(event.transaction.hash.toHexString())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* loadTransaction (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/index.ts#L83)
|
|
||||||
|
|
||||||
* timestamp (timestamp txn was confirmed)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
NonfungiblePositionManager IncreaseLiquidity event, DecreaseLiquidity event, Collect event, Transfer event
|
|
||||||
```ts
|
|
||||||
// Inside loadTransaction
|
|
||||||
let transaction = Transaction.load(event.transaction.hash.toHexString())
|
|
||||||
transaction.timestamp = event.block.timestamp
|
|
||||||
```
|
|
||||||
|
|
||||||
* burns, mints, swaps (derived values)
|
|
||||||
|
|
||||||
These fields are derived from reverse lookups.
|
|
||||||
https://thegraph.com/docs/define-a-subgraph#reverse-lookups
|
|
||||||
|
|
||||||
- UniswapDayData (Data accumulated and condensed into day stats for all of Uniswap)
|
|
||||||
* id (timestamp rounded to current day by dividing by 86400)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
updateUniswapDayData(event)
|
|
||||||
|
|
||||||
// Inside updateUniswapDayData
|
|
||||||
let timestamp = event.block.timestamp.toI32()
|
|
||||||
let dayID = timestamp / 86400
|
|
||||||
let uniswapDayData = UniswapDayData.load(dayID.toString())
|
|
||||||
if (uniswapDayData === null) {
|
|
||||||
uniswapDayData = new UniswapDayData(dayID.toString())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* updateUniswapDayData (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/intervalUpdates.ts#L23)
|
|
||||||
- Uses Factory entity `totalValueLockedUSD`, `txCount` fields
|
|
||||||
|
|
||||||
* date (timestamp rounded to current day by dividing by 86400)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateUniswapDayData
|
|
||||||
let timestamp = event.block.timestamp.toI32()
|
|
||||||
let dayID = timestamp / 86400
|
|
||||||
let dayStartTimestamp = dayID * 86400
|
|
||||||
let uniswapDayData = UniswapDayData.load(dayID.toString())
|
|
||||||
|
|
||||||
if (uniswapDayData === null) {
|
|
||||||
uniswapDayData = new UniswapDayData(dayID.toString())
|
|
||||||
uniswapDayData.date = dayStartTimestamp
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* tvlUSD (tvl in terms of USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let uniswap = Factory.load(FACTORY_ADDRESS)
|
|
||||||
let uniswapDayData = UniswapDayData.load(dayID.toString())
|
|
||||||
uniswapDayData.tvlUSD = uniswap.totalValueLockedUSD
|
|
||||||
```
|
|
||||||
|
|
||||||
* volumeUSD (total daily volume in Uniswap derived in terms of USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
let uniswapDayData = updateUniswapDayData(event)
|
|
||||||
uniswapDayData.volumeUSD = uniswapDayData.volumeUSD.plus(amountTotalUSDTracked)
|
|
||||||
```
|
|
||||||
|
|
||||||
- PoolDayData (Data accumulated and condensed into day stats for each pool)
|
|
||||||
* id (timestamp rounded to current day by dividing by 86400)
|
|
||||||
- Pool Initialize event, Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let poolDayData = updatePoolDayData(event)
|
|
||||||
|
|
||||||
// Inside updatePoolDayData
|
|
||||||
let timestamp = event.block.timestamp.toI32()
|
|
||||||
let dayID = timestamp / 86400
|
|
||||||
let dayPoolID = event.address
|
|
||||||
.toHexString()
|
|
||||||
.concat('-')
|
|
||||||
.concat(dayID.toString())
|
|
||||||
|
|
||||||
let poolDayData = PoolDayData.load(dayPoolID)
|
|
||||||
if (poolDayData === null) {
|
|
||||||
poolDayData = new PoolDayData(dayPoolID)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* updatePoolDayData (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/intervalUpdates.ts#L43)
|
|
||||||
- Uses Pool entity `token0Price`, `token1Price`, `liquidity`, `sqrtPrice`, `feeGrowthGlobal0X128`, `feeGrowthGlobal1X128`, `tick`, `totalValueLockedUSD` fields
|
|
||||||
|
|
||||||
* date (timestamp rounded to current day by dividing by 86400)
|
|
||||||
- Pool Initialize event, Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updatePoolDayData
|
|
||||||
let timestamp = event.block.timestamp.toI32()
|
|
||||||
let dayID = timestamp / 86400
|
|
||||||
let dayStartTimestamp = dayID * 86400
|
|
||||||
poolDayData.date = dayStartTimestamp
|
|
||||||
```
|
|
||||||
|
|
||||||
* tvlUSD (tvl derived in USD at end of period)
|
|
||||||
- Pool Initialize event, Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updatePoolDayData
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
poolDayData.tvlUSD = pool.totalValueLockedUSD
|
|
||||||
```
|
|
||||||
|
|
||||||
* volumeUSD (volume in USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
poolDayData.volumeUSD = poolDayData.volumeUSD.plus(amountTotalUSDTracked)
|
|
||||||
```
|
|
||||||
|
|
||||||
- TokenDayData
|
|
||||||
* id (token address concatendated with date)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token0DayData = updateTokenDayData(token0 as Token, event)
|
|
||||||
|
|
||||||
// Inside updateTokenDayData
|
|
||||||
// token = token0
|
|
||||||
let timestamp = event.block.timestamp.toI32()
|
|
||||||
let dayID = timestamp / 86400
|
|
||||||
let tokenDayID = token.id
|
|
||||||
.toString()
|
|
||||||
.concat('-')
|
|
||||||
.concat(dayID.toString())
|
|
||||||
|
|
||||||
let tokenDayData = TokenDayData.load(tokenDayID)
|
|
||||||
if (tokenDayData === null) {
|
|
||||||
tokenDayData = new TokenDayData(tokenDayID)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* updateTokenDayData (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/intervalUpdates.ts#L143)
|
|
||||||
- Uses Bundle entity `ethPriceUSD` field
|
|
||||||
|
|
||||||
* date (timestamp rounded to current day by dividing by 86400)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenDayData
|
|
||||||
let dayStartTimestamp = dayID * 86400
|
|
||||||
|
|
||||||
if (tokenDayData === null) {
|
|
||||||
tokenDayData = new TokenDayData(tokenDayID)
|
|
||||||
tokenDayData.date = dayStartTimestamp
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* totalValueLockedUSD (liquidity across all pools in derived USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenDayData
|
|
||||||
let tokenDayData = TokenDayData.load(tokenDayID)
|
|
||||||
tokenDayData.totalValueLockedUSD = token.totalValueLockedUSD
|
|
||||||
```
|
|
||||||
|
|
||||||
* volumeUSD (volume in derived USD)
|
|
||||||
- Pool Swap event
|
|
||||||
```ts
|
|
||||||
let pool = Pool.load(event.address.toHexString())
|
|
||||||
let token0 = Token.load(pool.token0)
|
|
||||||
let token1 = Token.load(pool.token1)
|
|
||||||
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
|
|
||||||
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)
|
|
||||||
|
|
||||||
let amount0Abs = amount0
|
|
||||||
if (amount0.lt(ZERO_BD)) {
|
|
||||||
amount0Abs = amount0.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
let amount1Abs = amount1
|
|
||||||
if (amount1.lt(ZERO_BD)) {
|
|
||||||
amount1Abs = amount1.times(BigDecimal.fromString('-1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div(
|
|
||||||
BigDecimal.fromString('2')
|
|
||||||
)
|
|
||||||
|
|
||||||
token0DayData.volumeUSD = token0DayData.volumeUSD.plus(amountTotalUSDTracked)
|
|
||||||
```
|
|
||||||
|
|
||||||
- TokenHourData
|
|
||||||
* id (token address concatendated with date)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
let token0HourData = updateTokenHourData(token0 as Token, event)
|
|
||||||
|
|
||||||
// Inside updateTokenHourData
|
|
||||||
// token = token0
|
|
||||||
let tokenHourID = token.id
|
|
||||||
.toString()
|
|
||||||
.concat('-')
|
|
||||||
.concat(hourIndex.toString())
|
|
||||||
let tokenHourData = TokenHourData.load(tokenHourID)
|
|
||||||
|
|
||||||
if (tokenHourData === null) {
|
|
||||||
tokenHourData = new TokenHourData(tokenHourID)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* updateTokenDayData (https://github.com/Uniswap/uniswap-v3-subgraph/blob/main/src/utils/intervalUpdates.ts#L186)
|
|
||||||
- Uses Bundle entity `ethPriceUSD` field
|
|
||||||
|
|
||||||
* close (close price USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenHourData
|
|
||||||
let bundle = Bundle.load('1')
|
|
||||||
let tokenPrice = token.derivedETH.times(bundle.ethPriceUSD)
|
|
||||||
tokenHourData.close = tokenPrice
|
|
||||||
```
|
|
||||||
|
|
||||||
* high (high price USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenHourData
|
|
||||||
let tokenHourData = TokenHourData.load(tokenHourID)
|
|
||||||
if (tokenHourData === null) {
|
|
||||||
tokenHourData = new TokenHourData(tokenHourID)
|
|
||||||
tokenHourData.high = tokenPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenPrice.gt(tokenHourData.high)) {
|
|
||||||
tokenHourData.high = tokenPrice
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* low (low price USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenHourData
|
|
||||||
let tokenHourData = TokenHourData.load(tokenHourID)
|
|
||||||
if (tokenHourData === null) {
|
|
||||||
tokenHourData = new TokenHourData(tokenHourID)
|
|
||||||
tokenHourData.low = tokenPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenPrice.lt(tokenHourData.low)) {
|
|
||||||
tokenHourData.low = tokenPrice
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* open (opening price USD)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenHourData
|
|
||||||
if (tokenHourData === null) {
|
|
||||||
tokenHourData = new TokenHourData(tokenHourID)
|
|
||||||
tokenHourData.open = tokenPrice
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* periodStartUnix (unix timestamp for start of hour)
|
|
||||||
- Pool Mint event, Burn event, Swap event
|
|
||||||
```ts
|
|
||||||
// Inside updateTokenHourData
|
|
||||||
if (tokenHourData === null) {
|
|
||||||
tokenHourData = new TokenHourData(tokenHourID)
|
|
||||||
tokenHourData.periodStartUnix = hourStartUnix
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
|||||||
# Contract Analysis
|
|
||||||
|
|
||||||
## View Methods in Uniswap V3 Core
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/NoDelegateCall.sol
|
|
||||||
- checkNotDelegateCall (private)
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/UniswapV3Pool.sol#L158
|
|
||||||
- _blockTimestamp (internal)
|
|
||||||
- balance0 (private)
|
|
||||||
- balance1 (private)
|
|
||||||
- snapshotCumulativesInside (external)
|
|
||||||
- observe (external)
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/Oracle.sol
|
|
||||||
- binarySearch (private)
|
|
||||||
- getSurroundingObservations (private)
|
|
||||||
- observeSingle (internal)
|
|
||||||
- observe (internal)
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/Position.sol
|
|
||||||
- get (internal)
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/Tick.sol
|
|
||||||
- getFeeGrowthInside (internal)
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/TickBitmap.sol
|
|
||||||
- nextInitializedTickWithinOneWord (internal)
|
|
||||||
|
|
||||||
## Mapping Event handlers in Uniswap subgraph
|
|
||||||
|
|
||||||
* handlePoolCreated (Factory contract - PoolCreated event)
|
|
||||||
- Data from event
|
|
||||||
- Entities
|
|
||||||
* Factory
|
|
||||||
* Bundle
|
|
||||||
* Pool
|
|
||||||
* Token
|
|
||||||
- Contract calls
|
|
||||||
* ERC20 (symbol, name, totalSupply, decimals)
|
|
||||||
* ERC20SymbolBytes (symbol)
|
|
||||||
* ERC20NameBytes (name)
|
|
||||||
- Create new Template contract (Pool)
|
|
||||||
|
|
||||||
* NonfungiblePositionManager contract
|
|
||||||
- Handlers (Similar code)
|
|
||||||
* handleIncreaseLiquidity (IncreaseLiquidity event)
|
|
||||||
* handleDecreaseLiquidity (DecreaseLiquidity event)
|
|
||||||
* handleCollect (Collect event)
|
|
||||||
* handleTransfer (Transfer event)
|
|
||||||
- Data from event
|
|
||||||
- Entities
|
|
||||||
* Position
|
|
||||||
* Transaction
|
|
||||||
* Token
|
|
||||||
- Contract calls
|
|
||||||
* NonfungiblePositionManager (positions)
|
|
||||||
* Factory (getPool)
|
|
||||||
|
|
||||||
* handleInitialize (Pool contract - Initialize event)
|
|
||||||
- Data from event
|
|
||||||
- Entities
|
|
||||||
* Pool
|
|
||||||
* Token
|
|
||||||
* Bundle
|
|
||||||
* PoolDayData
|
|
||||||
* PoolHourData
|
|
||||||
|
|
||||||
* handleSwap (Pool contract - Swap event)
|
|
||||||
- Data from event
|
|
||||||
- Entities
|
|
||||||
* Bundle
|
|
||||||
* Factory
|
|
||||||
* Pool
|
|
||||||
* Token
|
|
||||||
* Transaction
|
|
||||||
* Swap
|
|
||||||
* UniswapDayData
|
|
||||||
* PoolDayData
|
|
||||||
* PoolHourData
|
|
||||||
* TokenDayData
|
|
||||||
* TokenHourData
|
|
||||||
- Contract calls
|
|
||||||
* Pool (feeGrowthGlobal0X128, feeGrowthGlobal1X128)
|
|
||||||
|
|
||||||
* handleMint (Pool contract - Mint event)
|
|
||||||
- Data from event
|
|
||||||
- Entities
|
|
||||||
* Bundle
|
|
||||||
* Pool
|
|
||||||
* Factory
|
|
||||||
* Token
|
|
||||||
* Transaction
|
|
||||||
* Mint
|
|
||||||
* Tick
|
|
||||||
* UniswapDayData
|
|
||||||
* PoolDayData
|
|
||||||
* PoolHourData
|
|
||||||
* TokenDayData
|
|
||||||
* TokenHourData
|
|
||||||
|
|
||||||
* handleBurn (Pool contract - Burn event)
|
|
||||||
- Data from event
|
|
||||||
- Entities
|
|
||||||
* Bundle
|
|
||||||
* Pool
|
|
||||||
* Factory
|
|
||||||
* Token
|
|
||||||
* Burn
|
|
||||||
* Tick
|
|
||||||
* UniswapDayData
|
|
||||||
* PoolDayData
|
|
||||||
* PoolHourData
|
|
||||||
* TokenDayData
|
|
||||||
* TokenHourData
|
|
||||||
- Extra methods
|
|
||||||
* store.remove (remove Tick entity)
|
|
@ -1,19 +0,0 @@
|
|||||||
# Design Notes
|
|
||||||
|
|
||||||
## Watchers
|
|
||||||
|
|
||||||
* uniswap-watcher
|
|
||||||
* Provides events to downstream subscribers, access to core/periphery contract data,
|
|
||||||
* uniswap-info-watcher
|
|
||||||
* Subscribes to uniswap-watcher
|
|
||||||
* Performs computation/derivation of entity properties required by info frontend
|
|
||||||
* Filler (old to new block)
|
|
||||||
|
|
||||||
## Issues
|
|
||||||
|
|
||||||
* Filler should process block by block (old to new) starting from contract deployment block
|
|
||||||
* Otherwise, values of computed props will be incorrect
|
|
||||||
* "last_processed_block_number"
|
|
||||||
* Use audit/proof table to record changes to entities instead of aggregating in code (too slow)
|
|
||||||
* Handling reorgs
|
|
||||||
* ERC20 variants (storage layout)
|
|
@ -1,595 +0,0 @@
|
|||||||
# Frontend (Info App) Queries
|
|
||||||
|
|
||||||
- uniswap-v3 endpoint (https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-alt)
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/chartData.ts
|
|
||||||
```
|
|
||||||
query poolDayDatas($startTime: Int!, $skip: Int!, $address: Bytes!) {
|
|
||||||
poolDayDatas(
|
|
||||||
first: 1000
|
|
||||||
skip: $skip
|
|
||||||
where: { pool: $address, date_gt: $startTime }
|
|
||||||
orderBy: date
|
|
||||||
orderDirection: asc
|
|
||||||
) {
|
|
||||||
date
|
|
||||||
volumeUSD
|
|
||||||
tvlUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/poolData.ts
|
|
||||||
```
|
|
||||||
query pools {
|
|
||||||
pools(where: {id_in: $poolString}, block: {number: $block}, orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
feeTier
|
|
||||||
liquidity
|
|
||||||
sqrtPrice
|
|
||||||
tick
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
decimals
|
|
||||||
derivedETH
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
decimals
|
|
||||||
derivedETH
|
|
||||||
}
|
|
||||||
token0Price
|
|
||||||
token1Price
|
|
||||||
volumeUSD
|
|
||||||
txCount
|
|
||||||
totalValueLockedToken0
|
|
||||||
totalValueLockedToken1
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/tickData.ts
|
|
||||||
```
|
|
||||||
query surroundingTicks(
|
|
||||||
$poolAddress: String!
|
|
||||||
$tickIdxLowerBound: BigInt!
|
|
||||||
$tickIdxUpperBound: BigInt!
|
|
||||||
$skip: Int!
|
|
||||||
) {
|
|
||||||
ticks(
|
|
||||||
first: 1000
|
|
||||||
skip: $skip
|
|
||||||
where: { poolAddress: $poolAddress, tickIdx_lte: $tickIdxUpperBound, tickIdx_gte: $tickIdxLowerBound }
|
|
||||||
) {
|
|
||||||
tickIdx
|
|
||||||
liquidityGross
|
|
||||||
liquidityNet
|
|
||||||
price0
|
|
||||||
price1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query pool($poolAddress: String!) {
|
|
||||||
pool(id: $poolAddress) {
|
|
||||||
tick
|
|
||||||
token0 {
|
|
||||||
symbol
|
|
||||||
id
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
symbol
|
|
||||||
id
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
feeTier
|
|
||||||
sqrtPrice
|
|
||||||
liquidity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/topPools.ts
|
|
||||||
```
|
|
||||||
query topPools {
|
|
||||||
pools(first: 50, orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/transactions.ts
|
|
||||||
```
|
|
||||||
query transactions($address: Bytes!) {
|
|
||||||
mints(first: 100, orderBy: timestamp, orderDirection: desc, where: { pool: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
sender
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
swaps(first: 100, orderBy: timestamp, orderDirection: desc, where: { pool: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
burns(first: 100, orderBy: timestamp, orderDirection: desc, where: { pool: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/protocol/chart.ts
|
|
||||||
```
|
|
||||||
query uniswapDayDatas($startTime: Int!, $skip: Int!) {
|
|
||||||
uniswapDayDatas(first: 1000, skip: $skip, where: { date_gt: $startTime }, orderBy: date, orderDirection: asc) {
|
|
||||||
id
|
|
||||||
date
|
|
||||||
volumeUSD
|
|
||||||
tvlUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/protocol/overview.ts
|
|
||||||
```
|
|
||||||
query uniswapFactories {
|
|
||||||
factories(
|
|
||||||
block: { number: $block }
|
|
||||||
first: 1) {
|
|
||||||
txCount
|
|
||||||
totalVolumeUSD
|
|
||||||
totalFeesUSD
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/protocol/transactions.ts
|
|
||||||
```
|
|
||||||
query transactions {
|
|
||||||
transactions(first: 500, orderBy: timestamp, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
timestamp
|
|
||||||
mints {
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
sender
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
swaps {
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
burns {
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/search/index.ts
|
|
||||||
```
|
|
||||||
query tokens($value: String, $id: String) {
|
|
||||||
asSymbol: tokens(where: { symbol_contains: $value }, orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
asName: tokens(where: { name_contains: $value }, orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
asAddress: tokens(where: { id: $id }, orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query pools($tokens: [Bytes]!, $id: String) {
|
|
||||||
as0: pools(where: { token0_in: $tokens }) {
|
|
||||||
id
|
|
||||||
feeTier
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
as1: pools(where: { token1_in: $tokens }) {
|
|
||||||
id
|
|
||||||
feeTier
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
asAddress: pools(where: { id: $id }) {
|
|
||||||
id
|
|
||||||
feeTier
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/chartData.ts
|
|
||||||
```
|
|
||||||
query tokenDayDatas($startTime: Int!, $skip: Int!, $address: Bytes!) {
|
|
||||||
tokenDayDatas(
|
|
||||||
first: 1000
|
|
||||||
skip: $skip
|
|
||||||
where: { token: $address, date_gt: $startTime }
|
|
||||||
orderBy: date
|
|
||||||
orderDirection: asc
|
|
||||||
) {
|
|
||||||
date
|
|
||||||
volumeUSD
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/poolsForToken.ts
|
|
||||||
```
|
|
||||||
query topPools($address: Bytes!) {
|
|
||||||
asToken0: pools(first: 200, orderBy: totalValueLockedUSD, orderDirection: desc, where: { token0: $address }) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
asToken1: pools(first: 200, orderBy: totalValueLockedUSD, orderDirection: desc, where: { token1: $address }) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/priceData.ts
|
|
||||||
```
|
|
||||||
query blocks {
|
|
||||||
tBlockTimestamp:token(id:$tokenAddress, block: { number: $blockNumber }) {
|
|
||||||
derivedETH
|
|
||||||
},
|
|
||||||
bBlockTimestamp: bundle(id:"1", block: { number: $blockNumber }) {
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query tokenHourDatas($startTime: Int!, $skip: Int!, $address: Bytes!) {
|
|
||||||
tokenHourDatas(
|
|
||||||
first: 100
|
|
||||||
skip: $skip
|
|
||||||
where: { token: $address, periodStartUnix_gt: $startTime }
|
|
||||||
orderBy: periodStartUnix
|
|
||||||
orderDirection: asc
|
|
||||||
) {
|
|
||||||
periodStartUnix
|
|
||||||
high
|
|
||||||
low
|
|
||||||
open
|
|
||||||
close
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/tokenData.ts
|
|
||||||
```
|
|
||||||
query tokens {
|
|
||||||
tokens(where: {id_in: $tokenString}, block: {number: $block}), orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
derivedETH
|
|
||||||
volumeUSD
|
|
||||||
volume
|
|
||||||
txCount
|
|
||||||
totalValueLocked
|
|
||||||
feesUSD
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/topTokens.ts
|
|
||||||
```
|
|
||||||
query topPools {
|
|
||||||
tokens(first: 50, orderBy: totalValueLockedUSD, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/transactions.ts
|
|
||||||
```
|
|
||||||
query transactions($address: Bytes!) {
|
|
||||||
mintsAs0: mints(first: 500, orderBy: timestamp, orderDirection: desc, where: { token0: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
sender
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
mintsAs1: mints(first: 500, orderBy: timestamp, orderDirection: desc, where: { token0: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
sender
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
swapsAs0: swaps(first: 500, orderBy: timestamp, orderDirection: desc, where: { token0: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
swapsAs1: swaps(first: 500, orderBy: timestamp, orderDirection: desc, where: { token1: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
origin
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
burnsAs0: burns(first: 500, orderBy: timestamp, orderDirection: desc, where: { token0: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
burnsAs1: burns(first: 500, orderBy: timestamp, orderDirection: desc, where: { token1: $address }) {
|
|
||||||
timestamp
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner
|
|
||||||
amount0
|
|
||||||
amount1
|
|
||||||
amountUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/hooks/useEthPrices.ts
|
|
||||||
```
|
|
||||||
query prices($block24: Int!, $block48: Int!, $blockWeek: Int!) {
|
|
||||||
current: bundles(first: 1) {
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
oneDay: bundles(first: 1, block: { number: $block24 }) {
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
twoDay: bundles(first: 1, block: { number: $block48 }) {
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
oneWeek: bundles(first: 1, block: { number: $blockWeek }) {
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- ethereum-blocks endpoint (https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks)
|
|
||||||
|
|
||||||
https://github.com/Uniswap/uniswap-v3-info/blob/master/src/hooks/useBlocksFromTimestamps.ts
|
|
||||||
```
|
|
||||||
query blocks {
|
|
||||||
tTimestamp1:blocks(first: 1, orderBy: timestamp, orderDirection: desc, where: { timestamp_gt: $timestamp1, timestamp_lt: $timestamp1Plus600 }) {
|
|
||||||
number
|
|
||||||
}
|
|
||||||
|
|
||||||
tTimestamp2:blocks(first: 1, orderBy: timestamp, orderDirection: desc, where: { timestamp_gt: $timestamp2, timestamp_lt: $timestamp2Plus600 }) {
|
|
||||||
number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Checking subgraph health (https://thegraph.com/docs/deploy-a-subgraph#checking-subgraph-health)
|
|
||||||
|
|
||||||
https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/application/index.ts
|
|
||||||
```
|
|
||||||
query health {
|
|
||||||
indexingStatusForCurrentVersion(subgraphName: "uniswap/uniswap-v2") {
|
|
||||||
synced
|
|
||||||
health
|
|
||||||
chains {
|
|
||||||
chainHeadBlock {
|
|
||||||
number
|
|
||||||
}
|
|
||||||
latestBlock {
|
|
||||||
number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,64 +0,0 @@
|
|||||||
# Summary of Queries in Uniswap Info App
|
|
||||||
|
|
||||||
Actual queries are listed in [queries](./queries.md) file.
|
|
||||||
|
|
||||||
- uniswap-v3 endpoint (https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-alt)
|
|
||||||
* PoolDayData
|
|
||||||
- poolDayDatas (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/chartData.ts)
|
|
||||||
|
|
||||||
* Pool
|
|
||||||
- pools
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/poolData.ts
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/topPools.ts
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/search/index.ts
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/poolsForToken.ts
|
|
||||||
- pool
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/tickData.ts
|
|
||||||
|
|
||||||
* Tick
|
|
||||||
- tick (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/tickData.ts)
|
|
||||||
|
|
||||||
* Mint
|
|
||||||
- mints
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/pools/transactions.ts
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/transactions.ts
|
|
||||||
|
|
||||||
* UniswapDayData
|
|
||||||
- uniswapDayDatas (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/protocol/chart.ts)
|
|
||||||
|
|
||||||
* Factory
|
|
||||||
- factories (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/protocol/overview.ts)
|
|
||||||
|
|
||||||
* Transaction
|
|
||||||
- transactions (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/protocol/transactions.ts)
|
|
||||||
|
|
||||||
* Token
|
|
||||||
- tokens
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/search/index.ts
|
|
||||||
* (queried by block) https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/tokenData.ts
|
|
||||||
* https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/topTokens.ts
|
|
||||||
- token queried by block (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/priceData.ts)
|
|
||||||
|
|
||||||
* TokenDayData
|
|
||||||
- tokenDayDatas (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/chartData.ts)
|
|
||||||
|
|
||||||
* Bundle
|
|
||||||
- bundle queried by block (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/priceData.ts)
|
|
||||||
- bundles (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/hooks/useEthPrices.ts)
|
|
||||||
|
|
||||||
* TokenHourData
|
|
||||||
- tokenHourDatas (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/priceData.ts)
|
|
||||||
|
|
||||||
* Swap
|
|
||||||
- swaps (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/transactions.ts)
|
|
||||||
|
|
||||||
* Burn
|
|
||||||
- burns (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/tokens/transactions.ts)
|
|
||||||
|
|
||||||
- ethereum-blocks endpoint (https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks)
|
|
||||||
|
|
||||||
t${timestamp}:blocks (https://github.com/Uniswap/uniswap-v3-info/blob/master/src/hooks/useBlocksFromTimestamps.ts)
|
|
||||||
|
|
||||||
- Checking subgraph health (https://thegraph.com/docs/deploy-a-subgraph#checking-subgraph-health)
|
|
||||||
|
|
||||||
https://github.com/Uniswap/uniswap-v3-info/blob/master/src/data/application/index.ts#L5
|
|
@ -1,386 +0,0 @@
|
|||||||
# lint-disable fields-have-descriptions, arguments-have-descriptions, types-have-descriptions, enum-values-all-caps, enum-values-have-descriptions, input-object-values-have-descriptions, input-object-values-are-camel-cased, relay-page-info-spec
|
|
||||||
scalar BigDecimal
|
|
||||||
|
|
||||||
scalar BigInt
|
|
||||||
|
|
||||||
scalar Bytes
|
|
||||||
|
|
||||||
input Block_height {
|
|
||||||
hash: Bytes
|
|
||||||
number: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Pool {
|
|
||||||
feeTier: BigInt!
|
|
||||||
id: ID!
|
|
||||||
liquidity: BigInt!
|
|
||||||
sqrtPrice: BigInt!
|
|
||||||
tick: BigInt
|
|
||||||
token0: Token!
|
|
||||||
token0Price: BigDecimal!
|
|
||||||
token1: Token!
|
|
||||||
token1Price: BigDecimal!
|
|
||||||
totalValueLockedToken0: BigDecimal!
|
|
||||||
totalValueLockedToken1: BigDecimal!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
txCount: BigInt!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type PoolDayData {
|
|
||||||
date: Int!
|
|
||||||
id: ID!
|
|
||||||
tvlUSD: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tick {
|
|
||||||
id: ID!
|
|
||||||
liquidityGross: BigInt!
|
|
||||||
liquidityNet: BigInt!
|
|
||||||
price0: BigDecimal!
|
|
||||||
price1: BigDecimal!
|
|
||||||
tickIdx: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mint {
|
|
||||||
amount0: BigDecimal!
|
|
||||||
amount1: BigDecimal!
|
|
||||||
amountUSD: BigDecimal
|
|
||||||
id: ID!
|
|
||||||
origin: Bytes!
|
|
||||||
owner: Bytes!
|
|
||||||
pool: Pool!
|
|
||||||
sender: Bytes
|
|
||||||
timestamp: BigInt!
|
|
||||||
transaction: Transaction!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Swap {
|
|
||||||
amount0: BigDecimal!
|
|
||||||
amount1: BigDecimal!
|
|
||||||
amountUSD: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
origin: Bytes!
|
|
||||||
pool: Pool!
|
|
||||||
timestamp: BigInt!
|
|
||||||
transaction: Transaction!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Burn {
|
|
||||||
amount0: BigDecimal!
|
|
||||||
amount1: BigDecimal!
|
|
||||||
amountUSD: BigDecimal
|
|
||||||
id: ID!
|
|
||||||
origin: Bytes!
|
|
||||||
owner: Bytes
|
|
||||||
pool: Pool!
|
|
||||||
timestamp: BigInt!
|
|
||||||
transaction: Transaction!
|
|
||||||
}
|
|
||||||
|
|
||||||
type UniswapDayData {
|
|
||||||
date: Int!
|
|
||||||
id: ID!
|
|
||||||
tvlUSD: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Factory {
|
|
||||||
id: ID!
|
|
||||||
totalFeesUSD: BigDecimal!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
totalVolumeUSD: BigDecimal!
|
|
||||||
txCount: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Transaction {
|
|
||||||
burns(skip: Int = 0, first: Int = 100, orderBy: Burn_orderBy, orderDirection: OrderDirection, where: Burn_filter): [Burn]!
|
|
||||||
id: ID!
|
|
||||||
mints(skip: Int = 0, first: Int = 100, orderBy: Mint_orderBy, orderDirection: OrderDirection, where: Mint_filter): [Mint]!
|
|
||||||
swaps(skip: Int = 0, first: Int = 100, orderBy: Swap_orderBy, orderDirection: OrderDirection, where: Swap_filter): [Swap]!
|
|
||||||
timestamp: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Token {
|
|
||||||
decimals: BigInt!
|
|
||||||
derivedETH: BigDecimal!
|
|
||||||
feesUSD: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
name: String!
|
|
||||||
symbol: String!
|
|
||||||
totalValueLocked: BigDecimal!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
txCount: BigInt!
|
|
||||||
volume: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type TokenDayData {
|
|
||||||
date: Int!
|
|
||||||
id: ID!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bundle {
|
|
||||||
ethPriceUSD: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
}
|
|
||||||
|
|
||||||
type TokenHourData {
|
|
||||||
close: BigDecimal!
|
|
||||||
high: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
low: BigDecimal!
|
|
||||||
open: BigDecimal!
|
|
||||||
periodStartUnix: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderDirection {
|
|
||||||
asc
|
|
||||||
desc
|
|
||||||
}
|
|
||||||
|
|
||||||
input PoolDayData_filter {
|
|
||||||
date_gt: Int
|
|
||||||
pool: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PoolDayData_orderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
input Pool_filter {
|
|
||||||
id: ID
|
|
||||||
id_in: [ID!]
|
|
||||||
token0: String
|
|
||||||
token0_in: [String!]
|
|
||||||
token1: String
|
|
||||||
token1_in: [String!]
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Pool_orderBy {
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
input Tick_filter {
|
|
||||||
poolAddress: String
|
|
||||||
tickIdx_gte: BigInt
|
|
||||||
tickIdx_lte: BigInt
|
|
||||||
}
|
|
||||||
|
|
||||||
input Mint_filter {
|
|
||||||
pool: String
|
|
||||||
token0: String
|
|
||||||
token1: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Mint_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
input Swap_filter {
|
|
||||||
pool: String
|
|
||||||
token0: String
|
|
||||||
token1: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Swap_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
input Burn_filter {
|
|
||||||
pool: String
|
|
||||||
token0: String
|
|
||||||
token1: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Burn_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UniswapDayData_orderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
input UniswapDayData_filter {
|
|
||||||
date_gt: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Transaction_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
input Token_filter {
|
|
||||||
id: ID
|
|
||||||
id_in: [ID!]
|
|
||||||
name_contains: String
|
|
||||||
symbol_contains: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Token_orderBy {
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
input TokenDayData_filter {
|
|
||||||
date_gt: Int
|
|
||||||
token: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TokenDayData_orderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
input TokenHourData_filter {
|
|
||||||
periodStartUnix_gt: Int
|
|
||||||
token: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TokenHourData_orderBy {
|
|
||||||
periodStartUnix
|
|
||||||
}
|
|
||||||
|
|
||||||
type Query {
|
|
||||||
bundle(
|
|
||||||
id: ID!
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an `{ number:
|
|
||||||
Int }` containing the block number or a `{ hash: Bytes }` value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): Bundle
|
|
||||||
|
|
||||||
bundles(
|
|
||||||
first: Int = 100
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an `{ number:
|
|
||||||
Int }` containing the block number or a `{ hash: Bytes }` value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Bundle!]!
|
|
||||||
|
|
||||||
burns(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Burn_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Burn_filter
|
|
||||||
): [Burn!]!
|
|
||||||
|
|
||||||
factories(
|
|
||||||
first: Int = 100
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an `{ number:
|
|
||||||
Int }` containing the block number or a `{ hash: Bytes }` value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Factory!]!
|
|
||||||
|
|
||||||
mints(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Mint_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Mint_filter
|
|
||||||
): [Mint!]!
|
|
||||||
|
|
||||||
pool(
|
|
||||||
id: ID!
|
|
||||||
): Pool
|
|
||||||
|
|
||||||
poolDayDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: PoolDayData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: PoolDayData_filter
|
|
||||||
): [PoolDayData!]!
|
|
||||||
|
|
||||||
pools(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Pool_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Pool_filter
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an `{ number:
|
|
||||||
Int }` containing the block number or a `{ hash: Bytes }` value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Pool!]!
|
|
||||||
|
|
||||||
swaps(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Swap_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Swap_filter
|
|
||||||
): [Swap!]!
|
|
||||||
|
|
||||||
ticks(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
where: Tick_filter
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an `{ number:
|
|
||||||
Int }` containing the block number or a `{ hash: Bytes }` value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Tick!]!
|
|
||||||
|
|
||||||
token(
|
|
||||||
id: ID!
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an `{ number:
|
|
||||||
Int }` containing the block number or a `{ hash: Bytes }` value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): Token
|
|
||||||
|
|
||||||
tokenDayDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: TokenDayData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: TokenDayData_filter
|
|
||||||
): [TokenDayData!]!
|
|
||||||
|
|
||||||
tokenHourDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: TokenHourData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: TokenHourData_filter
|
|
||||||
): [TokenHourData!]!
|
|
||||||
|
|
||||||
tokens(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Token_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Token_filter
|
|
||||||
block: Block_height
|
|
||||||
): [Token!]!
|
|
||||||
|
|
||||||
transactions(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Transaction_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
): [Transaction!]!
|
|
||||||
|
|
||||||
uniswapDayDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: UniswapDayData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: UniswapDayData_filter
|
|
||||||
): [UniswapDayData!]!
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,66 +0,0 @@
|
|||||||
scalar BigInt
|
|
||||||
|
|
||||||
type Block {
|
|
||||||
hash: Bytes!
|
|
||||||
number: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
scalar Bytes
|
|
||||||
|
|
||||||
interface ChainIndexingStatus {
|
|
||||||
network: String!
|
|
||||||
chainHeadBlock: Block
|
|
||||||
earliestBlock: Block
|
|
||||||
latestBlock: Block
|
|
||||||
lastHealthyBlock: Block
|
|
||||||
}
|
|
||||||
|
|
||||||
type EthereumIndexingStatus implements ChainIndexingStatus {
|
|
||||||
network: String!
|
|
||||||
chainHeadBlock: Block
|
|
||||||
earliestBlock: Block
|
|
||||||
latestBlock: Block
|
|
||||||
lastHealthyBlock: Block
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Health {
|
|
||||||
"""Subgraph syncing normally"""
|
|
||||||
healthy
|
|
||||||
|
|
||||||
"""Subgraph syncing but with errors"""
|
|
||||||
unhealthy
|
|
||||||
|
|
||||||
"""Subgraph halted due to errors"""
|
|
||||||
failed
|
|
||||||
}
|
|
||||||
|
|
||||||
type Query {
|
|
||||||
indexingStatusForCurrentVersion(subgraphName: String!): SubgraphIndexingStatus
|
|
||||||
indexingStatusForPendingVersion(subgraphName: String!): SubgraphIndexingStatus
|
|
||||||
indexingStatusesForSubgraphName(subgraphName: String!): [SubgraphIndexingStatus!]!
|
|
||||||
indexingStatuses(subgraphs: [String!]): [SubgraphIndexingStatus!]!
|
|
||||||
proofOfIndexing(subgraph: String!, blockNumber: Int!, blockHash: Bytes!, indexer: Bytes): Bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
type SubgraphError {
|
|
||||||
message: String!
|
|
||||||
block: Block
|
|
||||||
handler: String
|
|
||||||
deterministic: Boolean!
|
|
||||||
}
|
|
||||||
|
|
||||||
type SubgraphIndexingStatus {
|
|
||||||
subgraph: String!
|
|
||||||
synced: Boolean!
|
|
||||||
health: Health!
|
|
||||||
|
|
||||||
"""If the subgraph has failed, this is the error caused it"""
|
|
||||||
fatalError: SubgraphError
|
|
||||||
|
|
||||||
"""Sorted from first to last, limited to first 1000"""
|
|
||||||
nonFatalErrors: [SubgraphError!]!
|
|
||||||
chains: [ChainIndexingStatus!]!
|
|
||||||
entityCount: BigInt!
|
|
||||||
node: String
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
[server]
|
|
||||||
host = "127.0.0.1"
|
|
||||||
port = 3004
|
|
||||||
# Use mode demo when running watcher locally.
|
|
||||||
# Mode demo whitelists all tokens so that entity values get updated.
|
|
||||||
mode = "demo"
|
|
||||||
|
|
||||||
[metrics]
|
|
||||||
host = "127.0.0.1"
|
|
||||||
port = 9000
|
|
||||||
|
|
||||||
[database]
|
|
||||||
type = "postgres"
|
|
||||||
host = "localhost"
|
|
||||||
port = 5432
|
|
||||||
database = "uni-info-watcher"
|
|
||||||
username = "postgres"
|
|
||||||
password = "postgres"
|
|
||||||
synchronize = true
|
|
||||||
logging = false
|
|
||||||
|
|
||||||
[upstream]
|
|
||||||
[upstream.ethServer]
|
|
||||||
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
|
|
||||||
rpcProviderEndpoint = "http://127.0.0.1:8081"
|
|
||||||
blockDelayInMilliSecs = 2000
|
|
||||||
|
|
||||||
[upstream.cache]
|
|
||||||
name = "requests"
|
|
||||||
enabled = false
|
|
||||||
deleteOnStart = false
|
|
||||||
|
|
||||||
[upstream.uniWatcher]
|
|
||||||
gqlEndpoint = "http://127.0.0.1:3003/graphql"
|
|
||||||
gqlSubscriptionEndpoint = "http://127.0.0.1:3003/graphql"
|
|
||||||
|
|
||||||
[upstream.tokenWatcher]
|
|
||||||
gqlEndpoint = "http://127.0.0.1:3001/graphql"
|
|
||||||
gqlSubscriptionEndpoint = "http://127.0.0.1:3001/graphql"
|
|
||||||
|
|
||||||
[jobQueue]
|
|
||||||
dbConnectionString = "postgres://postgres:postgres@localhost/uni-info-watcher-job-queue"
|
|
||||||
maxCompletionLagInSecs = 300
|
|
||||||
jobDelayInMilliSecs = 1000
|
|
||||||
eventsInBatch = 50
|
|
@ -1,41 +0,0 @@
|
|||||||
[server]
|
|
||||||
host = "127.0.0.1"
|
|
||||||
port = 3004
|
|
||||||
# Use mode demo when running watcher locally.
|
|
||||||
# Mode demo whitelists all tokens so that entity values get updated.
|
|
||||||
mode = "demo"
|
|
||||||
|
|
||||||
[database]
|
|
||||||
type = "postgres"
|
|
||||||
host = "localhost"
|
|
||||||
port = 5432
|
|
||||||
database = "uni-info-watcher"
|
|
||||||
username = "postgres"
|
|
||||||
password = "postgres"
|
|
||||||
synchronize = true
|
|
||||||
logging = false
|
|
||||||
|
|
||||||
[upstream]
|
|
||||||
[upstream.ethServer]
|
|
||||||
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
|
|
||||||
rpcProviderEndpoint = "http://127.0.0.1:8545"
|
|
||||||
blockDelayInMilliSecs = 2000
|
|
||||||
|
|
||||||
[upstream.cache]
|
|
||||||
name = "requests"
|
|
||||||
enabled = false
|
|
||||||
deleteOnStart = false
|
|
||||||
|
|
||||||
[upstream.uniWatcher]
|
|
||||||
gqlEndpoint = "http://127.0.0.1:3003/graphql"
|
|
||||||
gqlSubscriptionEndpoint = "http://127.0.0.1:3003/graphql"
|
|
||||||
|
|
||||||
[upstream.tokenWatcher]
|
|
||||||
gqlEndpoint = "http://127.0.0.1:3001/graphql"
|
|
||||||
gqlSubscriptionEndpoint = "http://127.0.0.1:3001/graphql"
|
|
||||||
|
|
||||||
[jobQueue]
|
|
||||||
dbConnectionString = "postgres://postgres:postgres@localhost/uni-info-watcher-job-queue"
|
|
||||||
maxCompletionLagInSecs = 300
|
|
||||||
jobDelayInMilliSecs = 1000
|
|
||||||
eventsInBatch = 50
|
|
@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@vulcanize/uni-info-watcher",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"license": "AGPL-3.0",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@apollo/client": "^3.3.19",
|
|
||||||
"@vulcanize/cache": "^0.1.0",
|
|
||||||
"@vulcanize/erc20-watcher": "^0.1.0",
|
|
||||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
|
||||||
"@vulcanize/uni-watcher": "^0.1.0",
|
|
||||||
"@vulcanize/util": "^0.1.0",
|
|
||||||
"apollo-server-express": "^2.25.0",
|
|
||||||
"apollo-type-bigint": "^0.1.3",
|
|
||||||
"debug": "^4.3.1",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"graphql": "^15.5.0",
|
|
||||||
"graphql-import-node": "^0.0.4",
|
|
||||||
"graphql-request": "^3.4.0",
|
|
||||||
"json-bigint": "^1.0.0",
|
|
||||||
"reflect-metadata": "^0.1.13",
|
|
||||||
"typeorm": "^0.2.32",
|
|
||||||
"yargs": "^17.0.1"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"lint": "eslint .",
|
|
||||||
"test": "mocha src/**/*.test.ts",
|
|
||||||
"test:gpev": "mocha src/get-prev-entity.test.ts",
|
|
||||||
"test:server": "mocha src/server.test.ts",
|
|
||||||
"build": "tsc",
|
|
||||||
"server": "DEBUG=vulcanize:* node --enable-source-maps dist/server.js",
|
|
||||||
"server:prof": "DEBUG=vulcanize:* node --require pprof --enable-source-maps dist/server.js",
|
|
||||||
"server:dev": "DEBUG=vulcanize:* nodemon --watch src src/server.ts",
|
|
||||||
"server:mock": "MOCK=1 nodemon src/server.ts",
|
|
||||||
"job-runner": "DEBUG=vulcanize:* node --enable-source-maps dist/job-runner.js",
|
|
||||||
"job-runner:prof": "DEBUG=vulcanize:* node --require pprof --enable-source-maps dist/job-runner.js",
|
|
||||||
"job-runner:dev": "DEBUG=vulcanize:* nodemon --watch src src/job-runner.ts",
|
|
||||||
"smoke-test": "mocha src/smoke.test.ts",
|
|
||||||
"fill": "DEBUG=vulcanize:* node --enable-source-maps dist/fill.js",
|
|
||||||
"fill:prof": "DEBUG=vulcanize:* node --require pprof --enable-source-maps dist/fill.js",
|
|
||||||
"fill:dev": "DEBUG=vulcanize:* ts-node src/fill.ts",
|
|
||||||
"generate:schema": "get-graphql-schema https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-alt > docs/analysis/schema/full-schema.graphql",
|
|
||||||
"generate:health-schema": "get-graphql-schema https://api.thegraph.com/index-node/graphql > docs/analysis/schema/health-schema.graphql",
|
|
||||||
"lint:schema": "graphql-schema-linter",
|
|
||||||
"reset": "DEBUG=vulcanize:* node --enable-source-maps dist/cli/reset.js",
|
|
||||||
"reset:dev": "DEBUG=vulcanize:* ts-node src/cli/reset.ts"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/chance": "^1.1.2",
|
|
||||||
"@types/express": "^4.17.11",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
|
||||||
"@typescript-eslint/parser": "^4.25.0",
|
|
||||||
"@uniswap/v3-core": "1.0.0",
|
|
||||||
"chai": "^4.3.4",
|
|
||||||
"chance": "^1.1.7",
|
|
||||||
"eslint": "^7.27.0",
|
|
||||||
"eslint-config-semistandard": "^15.0.1",
|
|
||||||
"eslint-config-standard": "^16.0.3",
|
|
||||||
"eslint-plugin-import": "^2.23.3",
|
|
||||||
"eslint-plugin-node": "^11.1.0",
|
|
||||||
"eslint-plugin-promise": "^5.1.0",
|
|
||||||
"eslint-plugin-standard": "^5.0.0",
|
|
||||||
"ethers": "^5.4.4",
|
|
||||||
"get-graphql-schema": "^2.1.2",
|
|
||||||
"graphql-schema-linter": "^2.0.1",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"mocha": "^8.4.0",
|
|
||||||
"nodemon": "^2.0.7",
|
|
||||||
"pprof": "^3.2.0",
|
|
||||||
"ts-node": "^10.0.0",
|
|
||||||
"typescript": "^4.3.2"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
import { getConfig, resetJobs } from '@vulcanize/util';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:reset-job-queue');
|
|
||||||
|
|
||||||
export const command = 'job-queue';
|
|
||||||
|
|
||||||
export const desc = 'Reset job queue';
|
|
||||||
|
|
||||||
export const builder = {};
|
|
||||||
|
|
||||||
export const handler = async (argv: any): Promise<void> => {
|
|
||||||
const config = await getConfig(argv.configFile);
|
|
||||||
await resetJobs(config);
|
|
||||||
|
|
||||||
log('Job queue reset successfully');
|
|
||||||
};
|
|
@ -1,102 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import debug from 'debug';
|
|
||||||
import { MoreThan } from 'typeorm';
|
|
||||||
import assert from 'assert';
|
|
||||||
|
|
||||||
import { getConfig, initClients, JobQueue, resetJobs } from '@vulcanize/util';
|
|
||||||
import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
|
||||||
import { Client as UniClient } from '@vulcanize/uni-watcher';
|
|
||||||
|
|
||||||
import { Database } from '../../database';
|
|
||||||
import { Indexer } from '../../indexer';
|
|
||||||
import { BlockProgress } from '../../entity/BlockProgress';
|
|
||||||
import { Factory } from '../../entity/Factory';
|
|
||||||
import { Bundle } from '../../entity/Bundle';
|
|
||||||
import { Pool } from '../../entity/Pool';
|
|
||||||
import { Mint } from '../../entity/Mint';
|
|
||||||
import { Burn } from '../../entity/Burn';
|
|
||||||
import { Swap } from '../../entity/Swap';
|
|
||||||
import { PositionSnapshot } from '../../entity/PositionSnapshot';
|
|
||||||
import { Position } from '../../entity/Position';
|
|
||||||
import { Token } from '../../entity/Token';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:reset-state');
|
|
||||||
|
|
||||||
export const command = 'state';
|
|
||||||
|
|
||||||
export const desc = 'Reset state to block number';
|
|
||||||
|
|
||||||
export const builder = {
|
|
||||||
blockNumber: {
|
|
||||||
type: 'number'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const handler = async (argv: any): Promise<void> => {
|
|
||||||
const config = await getConfig(argv.configFile);
|
|
||||||
await resetJobs(config);
|
|
||||||
const { jobQueue: jobQueueConfig } = config;
|
|
||||||
const { ethClient, ethProvider } = await initClients(config);
|
|
||||||
|
|
||||||
// Initialize database.
|
|
||||||
const db = new Database(config.database);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
const {
|
|
||||||
uniWatcher,
|
|
||||||
tokenWatcher
|
|
||||||
} = config.upstream;
|
|
||||||
|
|
||||||
const uniClient = new UniClient(uniWatcher);
|
|
||||||
const erc20Client = new ERC20Client(tokenWatcher);
|
|
||||||
|
|
||||||
assert(jobQueueConfig, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
await jobQueue.start();
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, uniClient, erc20Client, ethClient, ethProvider, jobQueue);
|
|
||||||
|
|
||||||
const syncStatus = await indexer.getSyncStatus();
|
|
||||||
assert(syncStatus, 'Missing syncStatus');
|
|
||||||
|
|
||||||
const blockProgresses = await indexer.getBlocksAtHeight(argv.blockNumber, false);
|
|
||||||
assert(blockProgresses.length, `No blocks at specified block number ${argv.blockNumber}`);
|
|
||||||
assert(!blockProgresses.some(block => !block.isComplete), `Incomplete block at block number ${argv.blockNumber} with unprocessed events`);
|
|
||||||
const [blockProgress] = blockProgresses;
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const removeEntitiesPromise = [BlockProgress, Factory, Bundle, Pool, Mint, Burn, Swap, PositionSnapshot, Position, Token].map(async entityClass => {
|
|
||||||
return db.removeEntities<any>(dbTx, entityClass, { blockNumber: MoreThan(argv.blockNumber) });
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(removeEntitiesPromise);
|
|
||||||
|
|
||||||
if (syncStatus.latestIndexedBlockNumber > blockProgress.blockNumber) {
|
|
||||||
await indexer.updateSyncStatusIndexedBlock(blockProgress.blockHash, blockProgress.blockNumber, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncStatus.latestCanonicalBlockNumber > blockProgress.blockNumber) {
|
|
||||||
await indexer.updateSyncStatusCanonicalBlock(blockProgress.blockHash, blockProgress.blockNumber, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
await indexer.updateSyncStatusChainHead(blockProgress.blockHash, blockProgress.blockNumber, true);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
log('Reset state successfully');
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
import { getResetYargs } from '@vulcanize/util';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:reset');
|
|
||||||
|
|
||||||
const main = async () => {
|
|
||||||
return getResetYargs()
|
|
||||||
.commandDir('reset-cmds', { extensions: ['ts', 'js'], exclude: /([a-zA-Z0-9\s_\\.\-:])+(.d.ts)$/ })
|
|
||||||
.demandCommand(1)
|
|
||||||
.help()
|
|
||||||
.argv;
|
|
||||||
};
|
|
||||||
|
|
||||||
main().then(() => {
|
|
||||||
process.exit();
|
|
||||||
}).catch(err => {
|
|
||||||
log(err);
|
|
||||||
});
|
|
@ -1,241 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client/core';
|
|
||||||
import { GraphQLClient, GraphQLConfig } from '@vulcanize/ipld-eth-client';
|
|
||||||
import { BlockHeight, OrderDirection } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import {
|
|
||||||
queryBundles,
|
|
||||||
queryBurns,
|
|
||||||
queryFactories,
|
|
||||||
queryMints,
|
|
||||||
queryPoolById,
|
|
||||||
queryPoolDayDatas,
|
|
||||||
queryPools,
|
|
||||||
queryPositions,
|
|
||||||
querySwaps,
|
|
||||||
queryTicks,
|
|
||||||
queryToken,
|
|
||||||
queryTokenDayDatas,
|
|
||||||
queryTokenHourDatas,
|
|
||||||
queryTransactions,
|
|
||||||
queryUniswapDayDatas
|
|
||||||
} from './queries';
|
|
||||||
|
|
||||||
export class Client {
|
|
||||||
_config: GraphQLConfig;
|
|
||||||
_client: GraphQLClient;
|
|
||||||
|
|
||||||
constructor (config: GraphQLConfig) {
|
|
||||||
this._config = config;
|
|
||||||
|
|
||||||
this._client = new GraphQLClient(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getToken (tokenId: string, block?: BlockHeight): Promise<any> {
|
|
||||||
const { token } = await this._client.query(
|
|
||||||
gql(queryToken),
|
|
||||||
{
|
|
||||||
block,
|
|
||||||
id: tokenId
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getFactories (first?: number, block?: BlockHeight): Promise<any> {
|
|
||||||
const { factories } = await this._client.query(
|
|
||||||
gql(queryFactories),
|
|
||||||
{
|
|
||||||
block,
|
|
||||||
first
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return factories;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBundles (first?: number, block?: BlockHeight): Promise<any> {
|
|
||||||
const { bundles } = await this._client.query(
|
|
||||||
gql(queryBundles),
|
|
||||||
{
|
|
||||||
block,
|
|
||||||
first
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return bundles;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPoolById (id: string): Promise<any> {
|
|
||||||
const { pool } = await this._client.query(
|
|
||||||
gql(queryPoolById),
|
|
||||||
{
|
|
||||||
id
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTicks (where?: any, skip?: number, first?: number, block?: BlockHeight): Promise<any> {
|
|
||||||
const { ticks } = await this._client.query(
|
|
||||||
gql(queryTicks),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
skip,
|
|
||||||
first,
|
|
||||||
block
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPools (where?: any, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { pools } = await this._client.query(
|
|
||||||
gql(queryPools),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return pools;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUniswapDayDatas (where?: any, skip?: number, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { uniswapDayDatas } = await this._client.query(
|
|
||||||
gql(queryUniswapDayDatas),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
skip,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return uniswapDayDatas;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPoolDayDatas (where?: any, skip?: number, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { poolDayDatas } = await this._client.query(
|
|
||||||
gql(queryPoolDayDatas),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
skip,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return poolDayDatas;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTokenDayDatas (where?: any, skip?: number, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { tokenDayDatas } = await this._client.query(
|
|
||||||
gql(queryTokenDayDatas),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
skip,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return tokenDayDatas;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTokenHourDatas (where?: any, skip?: number, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { tokenHourDatas } = await this._client.query(
|
|
||||||
gql(queryTokenHourDatas),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
skip,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return tokenHourDatas;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMints (where?: any, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { mints } = await this._client.query(
|
|
||||||
gql(queryMints),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return mints;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBurns (where?: any, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { burns } = await this._client.query(
|
|
||||||
gql(queryBurns),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return burns;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSwaps (where?: any, first?: number, orderBy?: string, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { swaps } = await this._client.query(
|
|
||||||
gql(querySwaps),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return swaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTransactions (first?: number, { orderBy, mintOrderBy, burnOrderBy, swapOrderBy }: {[key: string]: string} = {}, orderDirection?: OrderDirection): Promise<any> {
|
|
||||||
const { transactions } = await this._client.query(
|
|
||||||
gql(queryTransactions),
|
|
||||||
{
|
|
||||||
first,
|
|
||||||
orderBy,
|
|
||||||
orderDirection,
|
|
||||||
mintOrderBy,
|
|
||||||
burnOrderBy,
|
|
||||||
swapOrderBy
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return transactions;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPositions (where?: any, first?: number): Promise<any> {
|
|
||||||
const { positions } = await this._client.query(
|
|
||||||
gql(queryPositions),
|
|
||||||
{
|
|
||||||
where,
|
|
||||||
first
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return positions;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
# database
|
|
||||||
|
|
||||||
## Hierarchical Queries
|
|
||||||
|
|
||||||
For fetching previous entity that would be updated at a particular blockHash, we need to traverse the parent hashes. As the same entity might be present on a different branch chain with different values. These branches occur in the frothy region and so a recursive query is done to get the blockHash of the previous entity in this region.
|
|
||||||
|
|
||||||
Let the blockHash be `0xBlockHash` and the entity id be `entityId`, then the hierarchical query is
|
|
||||||
|
|
||||||
```pgsql
|
|
||||||
WITH RECURSIVE cte_query AS
|
|
||||||
(
|
|
||||||
SELECT
|
|
||||||
b.block_hash,
|
|
||||||
b.block_number,
|
|
||||||
b.parent_hash,
|
|
||||||
1 as depth,
|
|
||||||
e.id
|
|
||||||
FROM
|
|
||||||
block_progress b
|
|
||||||
LEFT JOIN
|
|
||||||
entityTable e ON e.block_hash = b.block_hash
|
|
||||||
WHERE
|
|
||||||
b.block_hash = '0xBlockHash'
|
|
||||||
UNION ALL
|
|
||||||
SELECT
|
|
||||||
b.block_hash,
|
|
||||||
b.block_number,
|
|
||||||
b.parent_hash,
|
|
||||||
c.depth + 1,
|
|
||||||
e.id
|
|
||||||
FROM
|
|
||||||
block_progress b
|
|
||||||
LEFT JOIN
|
|
||||||
${repo.metadata.tableName} e
|
|
||||||
ON e.block_hash = b.block_hash
|
|
||||||
AND e.id = 'entityId'
|
|
||||||
INNER JOIN
|
|
||||||
cte_query c ON c.parent_hash = b.block_hash
|
|
||||||
WHERE
|
|
||||||
c.id IS NULL AND c.depth < 16
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
block_hash, block_number, id
|
|
||||||
FROM
|
|
||||||
cte_query
|
|
||||||
ORDER BY block_number ASC
|
|
||||||
LIMIT 1;
|
|
||||||
```
|
|
||||||
|
|
||||||
The second WHERE clause checks that the loop continues only till MAX_REORG_DEPTH `16` which specifies the frothy region or stop when the entity is found.
|
|
||||||
|
|
||||||
The resulting blockHash is then used to fetch the previous entity.
|
|
||||||
|
|
||||||
For fetching multiple entities, we fetch all the blockHashes in the frothy region. So it fetches the entities from the correct branch in the frothy and then from the pruned region.
|
|
||||||
|
|
||||||
Hierarchical query for getting blockHashes in the frothy region
|
|
||||||
|
|
||||||
```pgsql
|
|
||||||
WITH RECURSIVE cte_query AS
|
|
||||||
(
|
|
||||||
SELECT
|
|
||||||
block_hash,
|
|
||||||
block_number,
|
|
||||||
parent_hash,
|
|
||||||
1 as depth
|
|
||||||
FROM
|
|
||||||
block_progress
|
|
||||||
WHERE
|
|
||||||
block_hash = '0xBlockHash'
|
|
||||||
UNION ALL
|
|
||||||
SELECT
|
|
||||||
b.block_hash,
|
|
||||||
b.block_number,
|
|
||||||
b.parent_hash,
|
|
||||||
c.depth + 1
|
|
||||||
FROM
|
|
||||||
block_progress b
|
|
||||||
INNER JOIN
|
|
||||||
cte_query c ON c.parent_hash = b.block_hash
|
|
||||||
WHERE
|
|
||||||
c.depth < 16
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
block_hash, block_number
|
|
||||||
FROM
|
|
||||||
cte_query;
|
|
||||||
```
|
|
@ -1,693 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import {
|
|
||||||
Connection,
|
|
||||||
ConnectionOptions,
|
|
||||||
DeepPartial,
|
|
||||||
FindConditions,
|
|
||||||
FindManyOptions,
|
|
||||||
FindOneOptions,
|
|
||||||
LessThanOrEqual,
|
|
||||||
QueryRunner
|
|
||||||
} from 'typeorm';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Database as BaseDatabase,
|
|
||||||
DatabaseInterface,
|
|
||||||
BlockHeight,
|
|
||||||
QueryOptions,
|
|
||||||
Where,
|
|
||||||
Relation
|
|
||||||
} from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Factory } from './entity/Factory';
|
|
||||||
import { Pool } from './entity/Pool';
|
|
||||||
import { Event } from './entity/Event';
|
|
||||||
import { Token } from './entity/Token';
|
|
||||||
import { Bundle } from './entity/Bundle';
|
|
||||||
import { PoolDayData } from './entity/PoolDayData';
|
|
||||||
import { PoolHourData } from './entity/PoolHourData';
|
|
||||||
import { Transaction } from './entity/Transaction';
|
|
||||||
import { Mint } from './entity/Mint';
|
|
||||||
import { UniswapDayData } from './entity/UniswapDayData';
|
|
||||||
import { Tick } from './entity/Tick';
|
|
||||||
import { TokenDayData } from './entity/TokenDayData';
|
|
||||||
import { TokenHourData } from './entity/TokenHourData';
|
|
||||||
import { Burn } from './entity/Burn';
|
|
||||||
import { Swap } from './entity/Swap';
|
|
||||||
import { Position } from './entity/Position';
|
|
||||||
import { PositionSnapshot } from './entity/PositionSnapshot';
|
|
||||||
import { BlockProgress } from './entity/BlockProgress';
|
|
||||||
import { Block } from './events';
|
|
||||||
import { SyncStatus } from './entity/SyncStatus';
|
|
||||||
import { TickDayData } from './entity/TickDayData';
|
|
||||||
|
|
||||||
export class Database implements DatabaseInterface {
|
|
||||||
_config: ConnectionOptions
|
|
||||||
_conn!: Connection
|
|
||||||
_baseDatabase: BaseDatabase
|
|
||||||
|
|
||||||
constructor (config: ConnectionOptions) {
|
|
||||||
assert(config);
|
|
||||||
|
|
||||||
this._config = {
|
|
||||||
...config,
|
|
||||||
entities: [path.join(__dirname, 'entity/*')]
|
|
||||||
};
|
|
||||||
|
|
||||||
this._baseDatabase = new BaseDatabase(this._config);
|
|
||||||
}
|
|
||||||
|
|
||||||
async init (): Promise<void> {
|
|
||||||
this._conn = await this._baseDatabase.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
async close (): Promise<void> {
|
|
||||||
return this._baseDatabase.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getFactory (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<Factory>): Promise<Factory | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Factory);
|
|
||||||
const whereOptions: FindConditions<Factory> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<Factory>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBundle (queryRunner: QueryRunner, { id, blockHash, blockNumber }: DeepPartial<Bundle>): Promise<Bundle | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Bundle);
|
|
||||||
const whereOptions: FindConditions<Bundle> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockNumber) {
|
|
||||||
whereOptions.blockNumber = LessThanOrEqual(blockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<Bundle>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getToken (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<Token>): Promise<Token | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Token);
|
|
||||||
const whereOptions: FindConditions<Token> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
relations: ['whitelistPools', 'whitelistPools.token0', 'whitelistPools.token1'],
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<Token>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTokenNoTx ({ id, blockHash }: DeepPartial<Token>): Promise<Token | undefined> {
|
|
||||||
const queryRunner = this._conn.createQueryRunner();
|
|
||||||
let res;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await queryRunner.connect();
|
|
||||||
res = await this.getToken(queryRunner, { id, blockHash });
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPool (queryRunner: QueryRunner, { id, blockHash, blockNumber }: DeepPartial<Pool>): Promise<Pool | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Pool);
|
|
||||||
const whereOptions: FindConditions<Pool> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockNumber) {
|
|
||||||
whereOptions.blockNumber = LessThanOrEqual(blockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
relations: ['token0', 'token1'],
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<Pool>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPoolNoTx ({ id, blockHash, blockNumber }: DeepPartial<Pool>): Promise<Pool | undefined> {
|
|
||||||
const queryRunner = this._conn.createQueryRunner();
|
|
||||||
let res;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await queryRunner.connect();
|
|
||||||
res = await this.getPool(queryRunner, { id, blockHash, blockNumber });
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPosition ({ id, blockHash }: DeepPartial<Position>): Promise<Position | undefined> {
|
|
||||||
const queryRunner = this._conn.createQueryRunner();
|
|
||||||
let entity;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await queryRunner.connect();
|
|
||||||
const repo = queryRunner.manager.getRepository(Position);
|
|
||||||
const whereOptions: FindConditions<Position> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
relations: ['pool', 'token0', 'token1', 'tickLower', 'tickUpper', 'transaction'],
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
entity = await repo.findOne(findOptions as FindOneOptions<Position>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTick (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<Tick>): Promise<Tick | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Tick);
|
|
||||||
const whereOptions: FindConditions<Tick> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
relations: ['pool'],
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<Tick>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTickNoTx ({ id, blockHash }: DeepPartial<Tick>): Promise<Tick | undefined> {
|
|
||||||
const queryRunner = this._conn.createQueryRunner();
|
|
||||||
let res;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await queryRunner.connect();
|
|
||||||
res = await this.getTick(queryRunner, { id, blockHash });
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPoolDayData (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<PoolDayData>): Promise<PoolDayData | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(PoolDayData);
|
|
||||||
const whereOptions: FindConditions<PoolDayData> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
},
|
|
||||||
relations: ['pool']
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<PoolDayData>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPoolHourData (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<PoolHourData>): Promise<PoolHourData | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(PoolHourData);
|
|
||||||
const whereOptions: FindConditions<PoolHourData> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<PoolHourData>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUniswapDayData (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<UniswapDayData>): Promise<UniswapDayData | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(UniswapDayData);
|
|
||||||
const whereOptions: FindConditions<UniswapDayData> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<UniswapDayData>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTokenDayData (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<TokenDayData>): Promise<TokenDayData | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(TokenDayData);
|
|
||||||
const whereOptions: FindConditions<TokenDayData> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<TokenDayData>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTokenHourData (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<TokenHourData>): Promise<TokenHourData | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(TokenHourData);
|
|
||||||
const whereOptions: FindConditions<TokenHourData> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<TokenHourData>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTickDayData (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<TickDayData>): Promise<TickDayData | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(TickDayData);
|
|
||||||
const whereOptions: FindConditions<TickDayData> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<TickDayData>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTransaction (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<Transaction>): Promise<Transaction | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Transaction);
|
|
||||||
const whereOptions: FindConditions<Transaction> = { id };
|
|
||||||
|
|
||||||
if (blockHash) {
|
|
||||||
whereOptions.blockHash = blockHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const findOptions = {
|
|
||||||
where: whereOptions,
|
|
||||||
order: {
|
|
||||||
blockNumber: 'DESC'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entity = await repo.findOne(findOptions as FindOneOptions<Transaction>);
|
|
||||||
|
|
||||||
if (!entity && findOptions.where.blockHash) {
|
|
||||||
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getModelEntities<Entity> (queryRunner: QueryRunner, entity: new () => Entity, block: BlockHeight, where: Where = {}, queryOptions: QueryOptions = {}, relations: Relation[] = []): Promise<Entity[]> {
|
|
||||||
return this._baseDatabase.getModelEntities(queryRunner, entity, block, where, queryOptions, relations);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getModelEntitiesNoTx<Entity> (entity: new () => Entity, block: BlockHeight, where: Where = {}, queryOptions: QueryOptions = {}, relations: Relation[] = []): Promise<Entity[]> {
|
|
||||||
const queryRunner = this._conn.createQueryRunner();
|
|
||||||
let res;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await queryRunner.connect();
|
|
||||||
res = await this.getModelEntities(queryRunner, entity, block, where, queryOptions, relations);
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveFactory (queryRunner: QueryRunner, factory: Factory, block: Block): Promise<Factory> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Factory);
|
|
||||||
factory.blockNumber = block.number;
|
|
||||||
factory.blockHash = block.hash;
|
|
||||||
return repo.save(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveBundle (queryRunner: QueryRunner, bundle: Bundle, block: Block): Promise<Bundle> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Bundle);
|
|
||||||
bundle.blockNumber = block.number;
|
|
||||||
bundle.blockHash = block.hash;
|
|
||||||
return repo.save(bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
async savePool (queryRunner: QueryRunner, pool: Pool, block: Block): Promise<Pool> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Pool);
|
|
||||||
pool.blockNumber = block.number;
|
|
||||||
pool.blockHash = block.hash;
|
|
||||||
return repo.save(pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
async savePoolDayData (queryRunner: QueryRunner, poolDayData: PoolDayData, block: Block): Promise<PoolDayData> {
|
|
||||||
const repo = queryRunner.manager.getRepository(PoolDayData);
|
|
||||||
poolDayData.blockNumber = block.number;
|
|
||||||
poolDayData.blockHash = block.hash;
|
|
||||||
return repo.save(poolDayData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async savePoolHourData (queryRunner: QueryRunner, poolHourData: PoolHourData, block: Block): Promise<PoolHourData> {
|
|
||||||
const repo = queryRunner.manager.getRepository(PoolHourData);
|
|
||||||
poolHourData.blockNumber = block.number;
|
|
||||||
poolHourData.blockHash = block.hash;
|
|
||||||
return repo.save(poolHourData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveToken (queryRunner: QueryRunner, token: Token, block: Block): Promise<Token> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Token);
|
|
||||||
token.blockNumber = block.number;
|
|
||||||
token.blockHash = block.hash;
|
|
||||||
return repo.save(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveTransaction (queryRunner: QueryRunner, transaction: Transaction, block: Block): Promise<Transaction> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Transaction);
|
|
||||||
transaction.blockNumber = block.number;
|
|
||||||
transaction.blockHash = block.hash;
|
|
||||||
return repo.save(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveUniswapDayData (queryRunner: QueryRunner, uniswapDayData: UniswapDayData, block: Block): Promise<UniswapDayData> {
|
|
||||||
const repo = queryRunner.manager.getRepository(UniswapDayData);
|
|
||||||
uniswapDayData.blockNumber = block.number;
|
|
||||||
uniswapDayData.blockHash = block.hash;
|
|
||||||
return repo.save(uniswapDayData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveTokenDayData (queryRunner: QueryRunner, tokenDayData: TokenDayData, block: Block): Promise<TokenDayData> {
|
|
||||||
const repo = queryRunner.manager.getRepository(TokenDayData);
|
|
||||||
tokenDayData.blockNumber = block.number;
|
|
||||||
tokenDayData.blockHash = block.hash;
|
|
||||||
return repo.save(tokenDayData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveTokenHourData (queryRunner: QueryRunner, tokenHourData: TokenHourData, block: Block): Promise<TokenHourData> {
|
|
||||||
const repo = queryRunner.manager.getRepository(TokenHourData);
|
|
||||||
tokenHourData.blockNumber = block.number;
|
|
||||||
tokenHourData.blockHash = block.hash;
|
|
||||||
return repo.save(tokenHourData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveTick (queryRunner: QueryRunner, tick: Tick, block: Block): Promise<Tick> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Tick);
|
|
||||||
tick.blockNumber = block.number;
|
|
||||||
tick.blockHash = block.hash;
|
|
||||||
return repo.save(tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveTickDayData (queryRunner: QueryRunner, tickDayData: TickDayData, block: Block): Promise<TickDayData> {
|
|
||||||
const repo = queryRunner.manager.getRepository(TickDayData);
|
|
||||||
tickDayData.blockNumber = block.number;
|
|
||||||
tickDayData.blockHash = block.hash;
|
|
||||||
return repo.save(tickDayData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async savePosition (queryRunner: QueryRunner, position: Position, block: Block): Promise<Position> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Position);
|
|
||||||
position.blockNumber = block.number;
|
|
||||||
position.blockHash = block.hash;
|
|
||||||
return repo.save(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
async savePositionSnapshot (queryRunner: QueryRunner, positionSnapshot: PositionSnapshot, block: Block): Promise<PositionSnapshot> {
|
|
||||||
const repo = queryRunner.manager.getRepository(PositionSnapshot);
|
|
||||||
positionSnapshot.blockNumber = block.number;
|
|
||||||
positionSnapshot.blockHash = block.hash;
|
|
||||||
return repo.save(positionSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveMint (queryRunner: QueryRunner, mint: Mint, block: Block): Promise<Mint> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Mint);
|
|
||||||
mint.blockNumber = block.number;
|
|
||||||
mint.blockHash = block.hash;
|
|
||||||
return repo.save(mint);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveBurn (queryRunner: QueryRunner, burn: Burn, block: Block): Promise<Burn> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Burn);
|
|
||||||
burn.blockNumber = block.number;
|
|
||||||
burn.blockHash = block.hash;
|
|
||||||
return repo.save(burn);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveSwap (queryRunner: QueryRunner, swap: Swap, block: Block): Promise<Swap> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Swap);
|
|
||||||
swap.blockNumber = block.number;
|
|
||||||
swap.blockHash = block.hash;
|
|
||||||
return repo.save(swap);
|
|
||||||
}
|
|
||||||
|
|
||||||
async createTransactionRunner (): Promise<QueryRunner> {
|
|
||||||
return this._baseDatabase.createTransactionRunner();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.getProcessedBlockCountForRange(repo, fromBlockNumber, toBlockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise<Array<Event>> {
|
|
||||||
const repo = this._conn.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.getEventsInRange(repo, fromBlockNumber, toBlockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveEventEntity (queryRunner: QueryRunner, entity: Event): Promise<Event> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Event);
|
|
||||||
return this._baseDatabase.saveEventEntity(repo, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise<Event[]> {
|
|
||||||
const repo = this._conn.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.getBlockEvents(repo, blockHash, where, queryOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveEvents (queryRunner: QueryRunner, block: DeepPartial<BlockProgress>, events: DeepPartial<Event>[]): Promise<BlockProgress> {
|
|
||||||
const blockRepo = queryRunner.manager.getRepository(BlockProgress);
|
|
||||||
const eventRepo = queryRunner.manager.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.saveEvents(blockRepo, eventRepo, block, events);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateSyncStatusIndexedBlock(repo, blockHash, blockNumber, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSyncStatusCanonicalBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateSyncStatusCanonicalBlock(repo, blockHash, blockNumber, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSyncStatusChainHead (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSyncStatus (queryRunner: QueryRunner): Promise<SyncStatus | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.getSyncStatus(repo);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEvent (id: string): Promise<Event | undefined> {
|
|
||||||
const repo = this._conn.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.getEvent(repo, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlocksAtHeight (height: number, isPruned: boolean): Promise<BlockProgress[]> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.getBlocksAtHeight(repo, height, isPruned);
|
|
||||||
}
|
|
||||||
|
|
||||||
async markBlocksAsPruned (queryRunner: QueryRunner, blocks: BlockProgress[]): Promise<void> {
|
|
||||||
const repo = queryRunner.manager.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.markBlocksAsPruned(repo, blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockProgress (blockHash: string): Promise<BlockProgress | undefined> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
return this._baseDatabase.getBlockProgress(repo, blockHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockProgressEntities (where: FindConditions<BlockProgress>, options: FindManyOptions<BlockProgress>): Promise<BlockProgress[]> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.getBlockProgressEntities(repo, where, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateBlockProgress (queryRunner: QueryRunner, block: BlockProgress, lastProcessedEventIndex: number): Promise<BlockProgress> {
|
|
||||||
const repo = queryRunner.manager.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateBlockProgress(repo, block, lastProcessedEventIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEntities<Entity> (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindConditions<Entity>): Promise<Entity[]> {
|
|
||||||
return this._baseDatabase.getEntities(queryRunner, entity, findConditions);
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeEntities<Entity> (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindManyOptions<Entity> | FindConditions<Entity>): Promise<void> {
|
|
||||||
return this._baseDatabase.removeEntities(queryRunner, entity, findConditions);
|
|
||||||
}
|
|
||||||
|
|
||||||
async isEntityEmpty<Entity> (entity: new () => Entity): Promise<boolean> {
|
|
||||||
return this._baseDatabase.isEntityEmpty(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAncestorAtDepth (blockHash: string, depth: number): Promise<string> {
|
|
||||||
return this._baseDatabase.getAncestorAtDepth(blockHash, depth);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn } from 'typeorm';
|
|
||||||
|
|
||||||
import { BlockProgressInterface } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
@Index(['blockHash'], { unique: true })
|
|
||||||
@Index(['blockNumber'])
|
|
||||||
@Index(['parentHash'])
|
|
||||||
export class BlockProgress implements BlockProgressInterface {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
@Column('varchar')
|
|
||||||
cid!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
blockHash!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66, nullable: true })
|
|
||||||
parentHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockTimestamp!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
numEvents!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
numProcessedEvents!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
lastProcessedEventIndex!: number;
|
|
||||||
|
|
||||||
@Column('boolean')
|
|
||||||
isComplete!: boolean
|
|
||||||
|
|
||||||
@Column('boolean', { default: false })
|
|
||||||
isPruned!: boolean
|
|
||||||
|
|
||||||
@CreateDateColumn()
|
|
||||||
createdAt!: Date;
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Bundle {
|
|
||||||
@PrimaryColumn('varchar', { length: 1 })
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
ethPriceUSD!: GraphDecimal
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { bigintTransformer, graphDecimalTransformer, GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Transaction } from './Transaction';
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
import { Token } from './Token';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Burn {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => Transaction, transaction => transaction.burns, { onDelete: 'CASCADE' })
|
|
||||||
transaction!: Transaction
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
timestamp!: bigint;
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token0!: Token
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token1!: Token
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
owner!: string
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
origin!: string
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
amount!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amount0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amount1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amountUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
tickLower!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
tickUpper!: bigint
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, ManyToOne } from 'typeorm';
|
|
||||||
import { BlockProgress } from './BlockProgress';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
// Index to query all events for a contract efficiently.
|
|
||||||
@Index(['contract'])
|
|
||||||
export class Event {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => BlockProgress, { onDelete: 'CASCADE' })
|
|
||||||
block!: BlockProgress;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
txHash!: string;
|
|
||||||
|
|
||||||
// Index of the log in the block.
|
|
||||||
@Column('integer')
|
|
||||||
index!: number;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
contract!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 256 })
|
|
||||||
eventName!: string;
|
|
||||||
|
|
||||||
@Column('text')
|
|
||||||
eventInfo!: string;
|
|
||||||
|
|
||||||
@Column('text')
|
|
||||||
extraInfo!: string;
|
|
||||||
|
|
||||||
@Column('text')
|
|
||||||
proof!: string;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';
|
|
||||||
|
|
||||||
// Stores a row if events for a (block, token) combination have already been fetched.
|
|
||||||
//
|
|
||||||
// Required as a particular block may not have events from a particular contract,
|
|
||||||
// and we need to differentiate between that case and the case where data hasn't
|
|
||||||
// yet been synced from upstream.
|
|
||||||
//
|
|
||||||
@Entity()
|
|
||||||
@Index(['blockHash', 'token'], { unique: true })
|
|
||||||
export class EventSyncProgress {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
blockHash!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
token!: string;
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Factory {
|
|
||||||
@PrimaryColumn('varchar', { length: 42 })
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
poolCount!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedETH!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
txCount!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedUSD!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalVolumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalVolumeETH!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalFeesUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalFeesETH!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
untrackedVolumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
// TODO: Add remaining fields when they are used.
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Transaction } from './Transaction';
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
import { Token } from './Token';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Mint {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => Transaction, transaction => transaction.mints, { onDelete: 'CASCADE' })
|
|
||||||
transaction!: Transaction
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
timestamp!: bigint;
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token0!: Token
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token1!: Token
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
owner!: string
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
sender!: string
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
origin!: string
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
amount!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amount0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amount1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amountUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
tickLower!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
tickUpper!: bigint
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Token } from './Token';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Pool {
|
|
||||||
@PrimaryColumn('varchar', { length: 42 })
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token0!: Token;
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token1!: Token;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
token0Price!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
token1Price!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
feeTier!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
sqrtPrice!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { nullable: true, transformer: bigintTransformer })
|
|
||||||
tick!: bigint | null
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
liquidity!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
feeGrowthGlobal0X128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
feeGrowthGlobal1X128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedETH!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
txCount!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
untrackedVolumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
feesUSD!: GraphDecimal
|
|
||||||
|
|
||||||
// TODO: Add remaining fields when they are used.
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class PoolDayData {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
date!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
high!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
low!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
open!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
close!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
sqrtPrice!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { nullable: true, transformer: bigintTransformer })
|
|
||||||
tick!: bigint | null
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
liquidity!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
feeGrowthGlobal0X128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
feeGrowthGlobal1X128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
token0Price!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
token1Price!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
tvlUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
txCount!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
feesUSD!: GraphDecimal
|
|
||||||
|
|
||||||
// TODO: Add remaining fields when they are used.
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class PoolHourData {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
periodStartUnix!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
high!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
low!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
open!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
close!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
sqrtPrice!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { nullable: true, transformer: bigintTransformer })
|
|
||||||
tick!: bigint | null
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
liquidity!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
feeGrowthGlobal0X128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
feeGrowthGlobal1X128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
token0Price!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
token1Price!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
tvlUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
txCount!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
feesUSD!: GraphDecimal
|
|
||||||
|
|
||||||
// TODO: Add remaining fields when they are used.
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
import { Token } from './Token';
|
|
||||||
import { Tick } from './Tick';
|
|
||||||
import { Transaction } from './Transaction';
|
|
||||||
import { ADDRESS_ZERO } from '../utils/constants';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Position {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
feeGrowthInside0LastX128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
feeGrowthInside1LastX128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
liquidity!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
depositedToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
depositedToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42, default: ADDRESS_ZERO })
|
|
||||||
owner!: string
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
withdrawnToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
withdrawnToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
collectedFeesToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
collectedFeesToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool
|
|
||||||
|
|
||||||
@ManyToOne(() => Token)
|
|
||||||
token0!: Token
|
|
||||||
|
|
||||||
@ManyToOne(() => Token)
|
|
||||||
token1!: Token
|
|
||||||
|
|
||||||
@ManyToOne(() => Tick)
|
|
||||||
tickLower!: Tick
|
|
||||||
|
|
||||||
@ManyToOne(() => Tick)
|
|
||||||
tickUpper!: Tick
|
|
||||||
|
|
||||||
@ManyToOne(() => Transaction)
|
|
||||||
transaction!: Transaction
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
import { Transaction } from './Transaction';
|
|
||||||
import { ADDRESS_ZERO } from '../utils/constants';
|
|
||||||
import { Position } from './Position';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class PositionSnapshot {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
timestamp!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
feeGrowthInside0LastX128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
feeGrowthInside1LastX128!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
liquidity!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
depositedToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
depositedToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42, default: ADDRESS_ZERO })
|
|
||||||
owner!: string
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
withdrawnToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
withdrawnToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
collectedFeesToken0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
collectedFeesToken1!: GraphDecimal
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool
|
|
||||||
|
|
||||||
@ManyToOne(() => Position, { onDelete: 'CASCADE' })
|
|
||||||
position!: Position
|
|
||||||
|
|
||||||
@ManyToOne(() => Transaction, { onDelete: 'CASCADE' })
|
|
||||||
transaction!: Transaction
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Transaction } from './Transaction';
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
import { Token } from './Token';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Swap {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => Transaction, transaction => transaction.swaps, { onDelete: 'CASCADE' })
|
|
||||||
transaction!: Transaction
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
timestamp!: bigint;
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token0!: Token
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token1!: Token
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
sender!: string
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
origin!: string
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
recipient!: string
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amount0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amount1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
amountUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
tick!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
sqrtPriceX96!: bigint
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
||||||
|
|
||||||
import { SyncStatusInterface } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class SyncStatus implements SyncStatusInterface {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
// Latest block hash and number from the chain itself.
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
chainHeadBlockHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
chainHeadBlockNumber!: number;
|
|
||||||
|
|
||||||
// Most recent block hash that's been indexed.
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
latestIndexedBlockHash!: string;
|
|
||||||
|
|
||||||
// Most recent block number that's been indexed.
|
|
||||||
@Column('integer')
|
|
||||||
latestIndexedBlockNumber!: number;
|
|
||||||
|
|
||||||
// Most recent block hash and number that we can consider as part
|
|
||||||
// of the canonical/finalized chain. Reorgs older than this block
|
|
||||||
// cannot be processed and processing will halt.
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
latestCanonicalBlockHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
latestCanonicalBlockNumber!: number;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
initialIndexedBlockHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
initialIndexedBlockNumber!: number;
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Tick {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
tickIdx!: bigint;
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
poolAddress!: string
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
price0!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
price1!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: bigintTransformer })
|
|
||||||
liquidityGross!: bigint
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: bigintTransformer })
|
|
||||||
liquidityNet!: bigint
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
import { Tick } from './Tick';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class TickDayData {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
date!: number
|
|
||||||
|
|
||||||
@ManyToOne(() => Pool, { onDelete: 'CASCADE' })
|
|
||||||
pool!: Pool;
|
|
||||||
|
|
||||||
@ManyToOne(() => Tick, { onDelete: 'CASCADE' })
|
|
||||||
tick!: Tick
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
liquidityGross!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
liquidityNet!: bigint;
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToMany, JoinTable } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from './Pool';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Token {
|
|
||||||
@PrimaryColumn('varchar', { length: 42 })
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('varchar')
|
|
||||||
symbol!: string;
|
|
||||||
|
|
||||||
@Column('varchar')
|
|
||||||
name!: string;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
totalSupply!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
decimals!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
derivedETH!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: BigInt(0), transformer: bigintTransformer })
|
|
||||||
txCount!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLocked!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedUSD!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volume!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
untrackedVolumeUSD!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
feesUSD!: GraphDecimal;
|
|
||||||
|
|
||||||
@ManyToMany(() => Pool)
|
|
||||||
@JoinTable()
|
|
||||||
whitelistPools!: Pool[];
|
|
||||||
|
|
||||||
// TODO: Add remaining fields when they are used.
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Token } from './Token';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class TokenDayData {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
date!: number
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token!: Token
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
high!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
low!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
open!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
close!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
priceUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
totalValueLocked!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volume!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
untrackedVolumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
feesUSD!: GraphDecimal
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Token } from './Token';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class TokenHourData {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
periodStartUnix!: number
|
|
||||||
|
|
||||||
@ManyToOne(() => Token, { onDelete: 'CASCADE' })
|
|
||||||
token!: Token
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
high!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
low!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
open!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
close!: GraphDecimal;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
priceUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
totalValueLocked!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
totalValueLockedUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volume!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
untrackedVolumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
feesUSD!: GraphDecimal
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column, OneToMany } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Mint } from './Mint';
|
|
||||||
import { Burn } from './Burn';
|
|
||||||
import { Swap } from './Swap';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Transaction {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
ethPriceUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
timestamp!: bigint;
|
|
||||||
|
|
||||||
@OneToMany(() => Mint, mint => mint.transaction)
|
|
||||||
mints!: Mint[];
|
|
||||||
|
|
||||||
@OneToMany(() => Burn, burn => burn.transaction)
|
|
||||||
burns!: Burn[];
|
|
||||||
|
|
||||||
@OneToMany(() => Swap, swap => swap.transaction)
|
|
||||||
swaps!: Swap[];
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
|
||||||
import { graphDecimalTransformer, GraphDecimal, bigintTransformer } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class UniswapDayData {
|
|
||||||
@PrimaryColumn('varchar')
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
// https://typeorm.io/#/entities/primary-columns
|
|
||||||
@PrimaryColumn('varchar', { length: 66 })
|
|
||||||
blockHash!: string
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
date!: number
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer })
|
|
||||||
tvlUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { default: 0, transformer: graphDecimalTransformer })
|
|
||||||
volumeUSD!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: bigintTransformer })
|
|
||||||
txCount!: bigint;
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer, default: 0 })
|
|
||||||
volumeETH!: GraphDecimal
|
|
||||||
|
|
||||||
@Column('numeric', { transformer: graphDecimalTransformer, default: 0 })
|
|
||||||
feesUSD!: GraphDecimal
|
|
||||||
}
|
|
@ -1,178 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import debug from 'debug';
|
|
||||||
import { PubSub } from 'apollo-server-express';
|
|
||||||
|
|
||||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
|
||||||
import { EventWatcher as BaseEventWatcher, EventWatcherInterface, JobQueue, QUEUE_BLOCK_PROCESSING, QUEUE_EVENT_PROCESSING, UpstreamConfig } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:events');
|
|
||||||
|
|
||||||
export interface PoolCreatedEvent {
|
|
||||||
__typename: 'PoolCreatedEvent';
|
|
||||||
token0: string;
|
|
||||||
token1: string;
|
|
||||||
fee: string;
|
|
||||||
tickSpacing: string;
|
|
||||||
pool: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InitializeEvent {
|
|
||||||
__typename: 'InitializeEvent';
|
|
||||||
sqrtPriceX96: string;
|
|
||||||
tick: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MintEvent {
|
|
||||||
__typename: 'MintEvent';
|
|
||||||
sender: string;
|
|
||||||
owner: string;
|
|
||||||
tickLower: string;
|
|
||||||
tickUpper: string;
|
|
||||||
amount: string;
|
|
||||||
amount0: string;
|
|
||||||
amount1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BurnEvent {
|
|
||||||
__typename: 'BurnEvent';
|
|
||||||
owner: string;
|
|
||||||
tickLower: string;
|
|
||||||
tickUpper: string;
|
|
||||||
amount: string;
|
|
||||||
amount0: string;
|
|
||||||
amount1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SwapEvent {
|
|
||||||
__typename: 'SwapEvent';
|
|
||||||
sender: string;
|
|
||||||
recipient: string;
|
|
||||||
amount0: string;
|
|
||||||
amount1: string;
|
|
||||||
sqrtPriceX96: string;
|
|
||||||
liquidity: string;
|
|
||||||
tick: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IncreaseLiquidityEvent {
|
|
||||||
__typename: 'IncreaseLiquidityEvent';
|
|
||||||
tokenId: string;
|
|
||||||
liquidity: string;
|
|
||||||
amount0: string;
|
|
||||||
amount1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DecreaseLiquidityEvent {
|
|
||||||
__typename: 'DecreaseLiquidityEvent';
|
|
||||||
tokenId: string;
|
|
||||||
liquidity: string;
|
|
||||||
amount0: string;
|
|
||||||
amount1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CollectEvent {
|
|
||||||
__typename: 'CollectEvent';
|
|
||||||
tokenId: string;
|
|
||||||
recipient: string;
|
|
||||||
amount0: string;
|
|
||||||
amount1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TransferEvent {
|
|
||||||
__typename: 'TransferEvent';
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
tokenId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Block {
|
|
||||||
cid: string;
|
|
||||||
number: number;
|
|
||||||
hash: string;
|
|
||||||
timestamp: number;
|
|
||||||
parentHash: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Transaction {
|
|
||||||
hash: string;
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
index: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResultEvent {
|
|
||||||
block: Block;
|
|
||||||
tx: Transaction;
|
|
||||||
contract: string;
|
|
||||||
eventIndex: number;
|
|
||||||
event: PoolCreatedEvent | InitializeEvent | MintEvent | BurnEvent | SwapEvent | IncreaseLiquidityEvent | DecreaseLiquidityEvent | CollectEvent | TransferEvent;
|
|
||||||
proof: {
|
|
||||||
data: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EventWatcher implements EventWatcherInterface {
|
|
||||||
_ethClient: EthClient
|
|
||||||
_indexer: Indexer
|
|
||||||
_subscription?: ZenObservable.Subscription
|
|
||||||
_pubsub: PubSub
|
|
||||||
_jobQueue: JobQueue
|
|
||||||
_baseEventWatcher: BaseEventWatcher
|
|
||||||
|
|
||||||
constructor (upstreamConfig: UpstreamConfig, ethClient: EthClient, indexer: Indexer, pubsub: PubSub, jobQueue: JobQueue) {
|
|
||||||
this._ethClient = ethClient;
|
|
||||||
this._indexer = indexer;
|
|
||||||
this._pubsub = pubsub;
|
|
||||||
this._jobQueue = jobQueue;
|
|
||||||
this._baseEventWatcher = new BaseEventWatcher(upstreamConfig, this._ethClient, this._indexer, this._pubsub, this._jobQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockProgressEventIterator (): AsyncIterator<any> {
|
|
||||||
return this._baseEventWatcher.getBlockProgressEventIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
async start (): Promise<void> {
|
|
||||||
assert(!this._subscription, 'subscription already started');
|
|
||||||
log('Started watching upstream events...');
|
|
||||||
|
|
||||||
await this.initBlockProcessingOnCompleteHandler();
|
|
||||||
await this.initEventProcessingOnCompleteHandler();
|
|
||||||
this._baseEventWatcher.startBlockProcessing();
|
|
||||||
}
|
|
||||||
|
|
||||||
async stop (): Promise<void> {
|
|
||||||
this._baseEventWatcher.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
async initBlockProcessingOnCompleteHandler (): Promise<void> {
|
|
||||||
await this._jobQueue.onComplete(QUEUE_BLOCK_PROCESSING, async (job) => {
|
|
||||||
const { id, data: { failed } } = job;
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
log(`Job ${id} for queue ${QUEUE_BLOCK_PROCESSING} failed`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._baseEventWatcher.blockProcessingCompleteHandler(job);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async initEventProcessingOnCompleteHandler (): Promise<void> {
|
|
||||||
await this._jobQueue.onComplete(QUEUE_EVENT_PROCESSING, async (job) => {
|
|
||||||
const { id, data: { failed } } = job;
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
log(`Job ${id} for queue ${QUEUE_EVENT_PROCESSING} failed`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._baseEventWatcher.eventProcessingCompleteHandler(job);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import yargs from 'yargs';
|
|
||||||
import { hideBin } from 'yargs/helpers';
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
import { getConfig, Config, fillBlocks, JobQueue, DEFAULT_CONFIG_PATH, initClients } from '@vulcanize/util';
|
|
||||||
import { Client as UniClient } from '@vulcanize/uni-watcher';
|
|
||||||
import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
|
||||||
|
|
||||||
import { Database } from './database';
|
|
||||||
import { PubSub } from 'apollo-server-express';
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { EventWatcher } from './events';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:server');
|
|
||||||
|
|
||||||
export const main = async (): Promise<any> => {
|
|
||||||
const argv = await yargs(hideBin(process.argv)).parserConfiguration({
|
|
||||||
'parse-numbers': false
|
|
||||||
}).options({
|
|
||||||
configFile: {
|
|
||||||
alias: 'f',
|
|
||||||
type: 'string',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'configuration file path (toml)',
|
|
||||||
default: DEFAULT_CONFIG_PATH
|
|
||||||
},
|
|
||||||
startBlock: {
|
|
||||||
type: 'number',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'Block number to start processing at'
|
|
||||||
},
|
|
||||||
endBlock: {
|
|
||||||
type: 'number',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'Block number to stop processing at'
|
|
||||||
},
|
|
||||||
prefetch: {
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
describe: 'Block and events prefetch mode'
|
|
||||||
},
|
|
||||||
batchBlocks: {
|
|
||||||
type: 'number',
|
|
||||||
default: 10,
|
|
||||||
describe: 'Number of blocks prefetched in batch'
|
|
||||||
}
|
|
||||||
}).argv;
|
|
||||||
|
|
||||||
const config: Config = await getConfig(argv.configFile);
|
|
||||||
const { ethClient, ethProvider } = await initClients(config);
|
|
||||||
|
|
||||||
const db = new Database(config.database);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
const { uniWatcher, tokenWatcher, ethServer: { blockDelayInMilliSecs } } = config.upstream;
|
|
||||||
|
|
||||||
const uniClient = new UniClient(uniWatcher);
|
|
||||||
const erc20Client = new ERC20Client(tokenWatcher);
|
|
||||||
|
|
||||||
// Note: In-memory pubsub works fine for now, as each watcher is a single process anyway.
|
|
||||||
// Later: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
|
|
||||||
const pubsub = new PubSub();
|
|
||||||
|
|
||||||
const jobQueueConfig = config.jobQueue;
|
|
||||||
assert(jobQueueConfig, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
await jobQueue.start();
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, uniClient, erc20Client, ethClient, ethProvider, jobQueue);
|
|
||||||
|
|
||||||
const eventWatcher = new EventWatcher(config.upstream, ethClient, indexer, pubsub, jobQueue);
|
|
||||||
|
|
||||||
await fillBlocks(jobQueue, indexer, eventWatcher, blockDelayInMilliSecs, argv);
|
|
||||||
};
|
|
||||||
|
|
||||||
main().catch(err => {
|
|
||||||
log(err);
|
|
||||||
}).finally(() => {
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
log(`Exiting process ${process.pid} with code 0`);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
@ -1,622 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { expect, assert } from 'chai';
|
|
||||||
import 'mocha';
|
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import {
|
|
||||||
getConfig
|
|
||||||
} from '@vulcanize/util';
|
|
||||||
import { removeEntities } from '@vulcanize/util/test';
|
|
||||||
|
|
||||||
import { Database } from './database';
|
|
||||||
import { createTestBlockTree, insertDummyToken } from '../test/utils';
|
|
||||||
import { Block } from './events';
|
|
||||||
import { BlockProgress } from './entity/BlockProgress';
|
|
||||||
import { SyncStatus } from './entity/SyncStatus';
|
|
||||||
import { Token } from './entity/Token';
|
|
||||||
|
|
||||||
const CONFIG_FILE = './environments/test.toml';
|
|
||||||
|
|
||||||
describe('getPrevEntityVersion', () => {
|
|
||||||
let db: Database;
|
|
||||||
let blocks: Block[][];
|
|
||||||
let tail: Block;
|
|
||||||
let head: Block;
|
|
||||||
let isDbEmptyBeforeTest: boolean;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
// Get config.
|
|
||||||
const config = await getConfig(CONFIG_FILE);
|
|
||||||
|
|
||||||
const { database: dbConfig } = config;
|
|
||||||
assert(dbConfig, 'Missing dbConfig.');
|
|
||||||
|
|
||||||
// Initialize database.
|
|
||||||
db = new Database(dbConfig);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
// Check if database is empty.
|
|
||||||
const isBlockProgressEmpty = await db.isEntityEmpty(BlockProgress);
|
|
||||||
const isTokenEmpty = await db.isEntityEmpty(Token);
|
|
||||||
const isSyncStatusEmpty = await db.isEntityEmpty(SyncStatus);
|
|
||||||
isDbEmptyBeforeTest = isBlockProgressEmpty && isTokenEmpty && isSyncStatusEmpty;
|
|
||||||
|
|
||||||
assert(isDbEmptyBeforeTest, 'Abort: Database not empty.');
|
|
||||||
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
blocks = await createTestBlockTree(db);
|
|
||||||
tail = blocks[0][0];
|
|
||||||
head = blocks[3][10];
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async () => {
|
|
||||||
if (isDbEmptyBeforeTest) {
|
|
||||||
await removeEntities(db, BlockProgress);
|
|
||||||
await removeEntities(db, SyncStatus);
|
|
||||||
}
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await removeEntities(db, Token);
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|------Token (token44)
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// 8 Blocks 3 Blocks
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 7 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |------Token (token00)
|
|
||||||
// +---+ (Target)
|
|
||||||
//
|
|
||||||
it('should fetch Token in pruned region', async () => {
|
|
||||||
// Insert a Token entity at the tail.
|
|
||||||
const token00 = await insertDummyToken(db, tail);
|
|
||||||
|
|
||||||
const token44 = _.cloneDeep(token00);
|
|
||||||
token44.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][4], token44);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: token00.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(token00.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(token00.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(token00.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(token00.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|------Token (token44)
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// 8 Blocks 3 Blocks
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 5 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 3 |------Token (token02)
|
|
||||||
// +---+ (Target)
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 2 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |------Token (token00)
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should fetch updated Token in pruned region', async () => {
|
|
||||||
// Insert a Token entity at the tail and update in pruned region.
|
|
||||||
const token00 = await insertDummyToken(db, tail);
|
|
||||||
|
|
||||||
const token02 = _.cloneDeep(token00);
|
|
||||||
token02.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[0][2], token02);
|
|
||||||
|
|
||||||
const token44 = _.cloneDeep(token00);
|
|
||||||
token44.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][4], token44);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: token00.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(token02.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(token02.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(token02.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(token02.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|------Token (token44)
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// Token (token30)-------\ | /
|
|
||||||
// (Target) -\ 8 Blocks 3 Blocks
|
|
||||||
// -\ | /
|
|
||||||
// -\ | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 7 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |------Token (token00)
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should fetch the Token in frothy region', async () => {
|
|
||||||
// Insert a Token entity at tail and in the frothy region.
|
|
||||||
const token00 = await insertDummyToken(db, tail);
|
|
||||||
|
|
||||||
const token30 = _.cloneDeep(token00);
|
|
||||||
token30.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[3][0], token30);
|
|
||||||
|
|
||||||
const token44 = _.cloneDeep(token00);
|
|
||||||
token44.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][4], token44);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: token00.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(token30.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(token30.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(token30.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(token30.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// Token (token30)-------\ | /
|
|
||||||
// (Target) -\ 8 Blocks 3 Blocks
|
|
||||||
// -\ | /
|
|
||||||
// -\ | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// Token------| 11| | 11| | 11|------Token (token40)
|
|
||||||
// (token11) +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |------Token (token08)
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 7 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should fetch the Token in frothy region (same block number)', async () => {
|
|
||||||
// Insert a Token entity in the frothy region at same block numbers.
|
|
||||||
const token08 = await insertDummyToken(db, blocks[0][8]);
|
|
||||||
|
|
||||||
const token11 = _.cloneDeep(token08);
|
|
||||||
token11.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[1][1], token11);
|
|
||||||
|
|
||||||
const token30 = _.cloneDeep(token08);
|
|
||||||
token30.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[3][0], token30);
|
|
||||||
|
|
||||||
const token40 = _.cloneDeep(token08);
|
|
||||||
token40.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][0], token40);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: token08.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(token30.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(token30.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(token30.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(token30.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|------Token (token44)
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// 8 Blocks 3 Blocks
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 7 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should not fetch the Token from a side branch in frothy region', async () => {
|
|
||||||
// Insert a Token entity in the frothy region in a side branch.
|
|
||||||
const token44 = await insertDummyToken(db, blocks[4][4]);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: token44.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.be.undefined;
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|------TokenA (tokenA44)
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// 8 Blocks 3 Blocks
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 6 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 2 |------TokenB
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |------TokenA (tokenA00)
|
|
||||||
// +---+ (Target)
|
|
||||||
//
|
|
||||||
it('should fetch Token in pruned region (multiple tokens)', async () => {
|
|
||||||
// Insert multiple Token entities in the pruned region.
|
|
||||||
const tokenA00 = await insertDummyToken(db, tail);
|
|
||||||
|
|
||||||
await insertDummyToken(db, blocks[0][1]);
|
|
||||||
|
|
||||||
const tokenA44 = _.cloneDeep(tokenA00);
|
|
||||||
tokenA44.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][4], tokenA44);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: tokenA00.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(tokenA00.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(tokenA00.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(tokenA00.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(tokenA00.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// TokenB (tokenB39)------| 20| | 15|------TokenA (tokenA44)
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// TokenA (tokenA30)-------\ | /
|
|
||||||
// (Target) -\ 8 Blocks 3 Blocks
|
|
||||||
// -\ | /
|
|
||||||
// -\ | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 6 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 2 |------TokenB (tokenB01)
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |------TokenA (tokenA00)
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should fetch the Token in frothy region (multiple tokens)', async () => {
|
|
||||||
// Insert multiple Token entities in the pruned region and in the frothy region.
|
|
||||||
const tokenA00 = await insertDummyToken(db, tail);
|
|
||||||
|
|
||||||
const tokenB01 = await insertDummyToken(db, blocks[0][1]);
|
|
||||||
|
|
||||||
const tokenA30 = _.cloneDeep(tokenA00);
|
|
||||||
tokenA30.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[3][0], tokenA30);
|
|
||||||
|
|
||||||
const tokenA44 = _.cloneDeep(tokenA00);
|
|
||||||
tokenA44.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][4], tokenA44);
|
|
||||||
|
|
||||||
const tokenB39 = _.cloneDeep(tokenB01);
|
|
||||||
tokenB39.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[3][9], tokenB39);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: tokenA00.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(tokenA30.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(tokenA30.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(tokenA30.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(tokenA30.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// 7 Blocks 2 Blocks
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// TokenB (tokenB31) +---+ +---+
|
|
||||||
// TokenA (tokenA31)------| 12| | 12|------TokenA (tokenA41)
|
|
||||||
// (Target) +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |------TokenA (tokenA08)
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 8 |------TokenB (tokenB07)
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 6 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should fetch the Token in frothy region (same block number) (multiple tokens)', async () => {
|
|
||||||
// Insert multiple Token entities in the frothy region at same block numbers.
|
|
||||||
const tokenB07 = await insertDummyToken(db, blocks[0][7]);
|
|
||||||
|
|
||||||
const tokenA08 = await insertDummyToken(db, blocks[0][8]);
|
|
||||||
|
|
||||||
const tokenA31 = _.cloneDeep(tokenA08);
|
|
||||||
tokenA31.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[3][1], tokenA31);
|
|
||||||
|
|
||||||
const tokenB31 = _.cloneDeep(tokenB07);
|
|
||||||
tokenB31.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[3][1], tokenB31);
|
|
||||||
|
|
||||||
const tokenA41 = _.cloneDeep(tokenA08);
|
|
||||||
tokenA41.txCount++;
|
|
||||||
await insertDummyToken(db, blocks[4][1], tokenA41);
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
try {
|
|
||||||
const searchedToken = await db.getToken(dbTx, { id: tokenA08.id, blockHash: head.hash });
|
|
||||||
expect(searchedToken).to.not.be.empty;
|
|
||||||
expect(searchedToken?.id).to.be.equal(tokenA31.id);
|
|
||||||
expect(searchedToken?.txCount).to.be.equal(tokenA31.txCount);
|
|
||||||
expect(searchedToken?.blockNumber).to.be.equal(tokenA31.blockNumber);
|
|
||||||
expect(searchedToken?.blockHash).to.be.equal(tokenA31.blockHash);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
File diff suppressed because it is too large
Load Diff
@ -1,120 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import yargs from 'yargs';
|
|
||||||
import { hideBin } from 'yargs/helpers';
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
|
||||||
import { Client as UniClient } from '@vulcanize/uni-watcher';
|
|
||||||
|
|
||||||
import {
|
|
||||||
getConfig,
|
|
||||||
Config,
|
|
||||||
JobQueue,
|
|
||||||
QUEUE_BLOCK_PROCESSING,
|
|
||||||
QUEUE_EVENT_PROCESSING,
|
|
||||||
JobRunner as BaseJobRunner,
|
|
||||||
JobQueueConfig,
|
|
||||||
DEFAULT_CONFIG_PATH,
|
|
||||||
initClients,
|
|
||||||
startMetricsServer
|
|
||||||
} from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { Database } from './database';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:job-runner');
|
|
||||||
|
|
||||||
export class JobRunner {
|
|
||||||
_indexer: Indexer
|
|
||||||
_jobQueue: JobQueue
|
|
||||||
_baseJobRunner: BaseJobRunner
|
|
||||||
_jobQueueConfig: JobQueueConfig
|
|
||||||
|
|
||||||
constructor (jobQueueConfig: JobQueueConfig, indexer: Indexer, jobQueue: JobQueue) {
|
|
||||||
this._jobQueueConfig = jobQueueConfig;
|
|
||||||
this._indexer = indexer;
|
|
||||||
this._jobQueue = jobQueue;
|
|
||||||
this._baseJobRunner = new BaseJobRunner(this._jobQueueConfig, this._indexer, this._jobQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
async start (): Promise<void> {
|
|
||||||
await this.subscribeBlockProcessingQueue();
|
|
||||||
await this.subscribeEventProcessingQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
async subscribeBlockProcessingQueue (): Promise<void> {
|
|
||||||
await this._jobQueue.subscribe(QUEUE_BLOCK_PROCESSING, async (job) => {
|
|
||||||
await this._baseJobRunner.processBlock(job);
|
|
||||||
|
|
||||||
await this._jobQueue.markComplete(job);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async subscribeEventProcessingQueue (): Promise<void> {
|
|
||||||
await this._jobQueue.subscribe(QUEUE_EVENT_PROCESSING, async (job) => {
|
|
||||||
await this._baseJobRunner.processEvent(job);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const main = async (): Promise<any> => {
|
|
||||||
const argv = await yargs(hideBin(process.argv))
|
|
||||||
.option('f', {
|
|
||||||
alias: 'config-file',
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'configuration file path (toml)',
|
|
||||||
type: 'string',
|
|
||||||
default: DEFAULT_CONFIG_PATH
|
|
||||||
})
|
|
||||||
.argv;
|
|
||||||
|
|
||||||
const config: Config = await getConfig(argv.f);
|
|
||||||
const { ethClient, ethProvider } = await initClients(config);
|
|
||||||
|
|
||||||
const db = new Database(config.database);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
const {
|
|
||||||
uniWatcher,
|
|
||||||
tokenWatcher
|
|
||||||
} = config.upstream;
|
|
||||||
|
|
||||||
const uniClient = new UniClient(uniWatcher);
|
|
||||||
const erc20Client = new ERC20Client(tokenWatcher);
|
|
||||||
|
|
||||||
const jobQueueConfig = config.jobQueue;
|
|
||||||
assert(jobQueueConfig, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
await jobQueue.start();
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, uniClient, erc20Client, ethClient, ethProvider, jobQueue);
|
|
||||||
|
|
||||||
const jobRunner = new JobRunner(jobQueueConfig, indexer, jobQueue);
|
|
||||||
await jobRunner.start();
|
|
||||||
|
|
||||||
startMetricsServer(config, indexer);
|
|
||||||
};
|
|
||||||
|
|
||||||
main().then(() => {
|
|
||||||
log('Starting job runner...');
|
|
||||||
}).catch(err => {
|
|
||||||
log(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('uncaughtException', err => {
|
|
||||||
log('uncaughtException', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
log(`Exiting process ${process.pid} with code 0`);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
@ -1,256 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Chance from 'chance';
|
|
||||||
import { ethers } from 'ethers';
|
|
||||||
|
|
||||||
export const NO_OF_BLOCKS = 3;
|
|
||||||
|
|
||||||
export interface Entity {
|
|
||||||
blockNumber: number
|
|
||||||
id: string
|
|
||||||
[field: string]: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Data {
|
|
||||||
static _instance: Data;
|
|
||||||
|
|
||||||
_entities: {[key: string]: Array<Entity>} = {
|
|
||||||
bundles: [],
|
|
||||||
burns: [],
|
|
||||||
transactions: [],
|
|
||||||
pools: [],
|
|
||||||
tokens: [],
|
|
||||||
factories: [],
|
|
||||||
mints: [],
|
|
||||||
swaps: [],
|
|
||||||
poolDayDatas: [],
|
|
||||||
tokenDayDatas: [],
|
|
||||||
uniswapDayDatas: [],
|
|
||||||
ticks: [],
|
|
||||||
tokenHourDatas: []
|
|
||||||
}
|
|
||||||
|
|
||||||
_chance: Chance.Chance
|
|
||||||
|
|
||||||
constructor () {
|
|
||||||
this._chance = new Chance();
|
|
||||||
this._generateData();
|
|
||||||
}
|
|
||||||
|
|
||||||
static getInstance (): Data {
|
|
||||||
if (!this._instance) {
|
|
||||||
this._instance = new Data();
|
|
||||||
}
|
|
||||||
return this._instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
get entities (): {[key: string]: Array<Entity>} {
|
|
||||||
return this._entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateData (): void {
|
|
||||||
const factoryAddress = this._getRandomAddress();
|
|
||||||
|
|
||||||
// Generate data for each block.
|
|
||||||
Array.from(Array(NO_OF_BLOCKS))
|
|
||||||
.forEach((_, blockNumber) => {
|
|
||||||
// Generate data for Factory.
|
|
||||||
this._entities.factories.push({
|
|
||||||
blockNumber,
|
|
||||||
id: factoryAddress,
|
|
||||||
totalFeesUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
totalValueLockedUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
totalVolumeUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
txCount: this._chance.integer({ min: 1 })
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate Bundle.
|
|
||||||
this._entities.bundles.push({
|
|
||||||
blockNumber,
|
|
||||||
id: '1',
|
|
||||||
ethPriceUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate Pools.
|
|
||||||
Array.from(Array(3))
|
|
||||||
.forEach(() => {
|
|
||||||
const token0 = {
|
|
||||||
blockNumber: blockNumber,
|
|
||||||
id: this._getRandomAddress(),
|
|
||||||
symbol: this._chance.string({ length: 3, casing: 'upper', alpha: false }),
|
|
||||||
name: this._chance.word({ syllables: 1 }),
|
|
||||||
volume: this._chance.integer({ min: 1 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
feesUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
txCount: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLocked: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLockedUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
derivedETH: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
};
|
|
||||||
|
|
||||||
const token1 = {
|
|
||||||
blockNumber: blockNumber,
|
|
||||||
id: this._getRandomAddress(),
|
|
||||||
symbol: this._chance.string({ length: 3, casing: 'upper', alpha: false }),
|
|
||||||
name: this._chance.word({ syllables: 1 }),
|
|
||||||
volume: this._chance.integer({ min: 1 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
feesUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
txCount: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLocked: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLockedUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
derivedETH: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
};
|
|
||||||
|
|
||||||
const pool = {
|
|
||||||
blockNumber: blockNumber,
|
|
||||||
id: this._getRandomAddress(),
|
|
||||||
token0: token0.id,
|
|
||||||
token1: token1.id,
|
|
||||||
feeTier: this._chance.integer({ min: 1 }),
|
|
||||||
liquidity: this._chance.integer({ min: 1 }),
|
|
||||||
sqrtPrice: this._chance.integer({ min: 1 }),
|
|
||||||
token0Price: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
token1Price: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
tick: this._chance.integer({ min: 1 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
txCount: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLockedToken0: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLockedToken1: this._chance.integer({ min: 1 }),
|
|
||||||
totalValueLockedUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
};
|
|
||||||
|
|
||||||
const timestamp = this._chance.timestamp();
|
|
||||||
|
|
||||||
this._entities.poolDayDatas.push({
|
|
||||||
blockNumber,
|
|
||||||
date: timestamp,
|
|
||||||
id: String(timestamp),
|
|
||||||
tvlUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
});
|
|
||||||
|
|
||||||
this._entities.tokenDayDatas.push(
|
|
||||||
{
|
|
||||||
blockNumber,
|
|
||||||
date: timestamp,
|
|
||||||
id: `${token0.id}-${timestamp}`,
|
|
||||||
totalValueLockedUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blockNumber,
|
|
||||||
date: timestamp,
|
|
||||||
id: `${token1.id}-${timestamp}`,
|
|
||||||
totalValueLockedUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this._entities.uniswapDayDatas.push({
|
|
||||||
blockNumber,
|
|
||||||
date: timestamp,
|
|
||||||
id: String(timestamp),
|
|
||||||
tvlUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
volumeUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
});
|
|
||||||
|
|
||||||
this._entities.ticks.push({
|
|
||||||
blockNumber,
|
|
||||||
id: `${pool.id}#${this._chance.integer({ min: 1 })}`,
|
|
||||||
liquidityGross: this._chance.integer({ min: 1 }),
|
|
||||||
liquidityNet: this._chance.integer({ min: 1 }),
|
|
||||||
price0: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
price1: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
tickIdx: this._chance.integer({ min: 1 })
|
|
||||||
});
|
|
||||||
|
|
||||||
this._entities.tokenHourDatas.push(
|
|
||||||
{
|
|
||||||
blockNumber,
|
|
||||||
close: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
high: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
id: `${token0.id}-${timestamp}`,
|
|
||||||
low: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
open: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
periodStartUnix: timestamp
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blockNumber,
|
|
||||||
close: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
high: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
id: `${token1.id}-${timestamp}`,
|
|
||||||
low: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
open: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
periodStartUnix: timestamp
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this._entities.tokens.push(token0, token1);
|
|
||||||
this._entities.pools.push(pool);
|
|
||||||
|
|
||||||
// Generate Transactions.
|
|
||||||
Array.from(Array(3))
|
|
||||||
.forEach((_, transactionIndex) => {
|
|
||||||
const transactionHash = ethers.utils.hexlify(ethers.utils.randomBytes(32));
|
|
||||||
|
|
||||||
const transaction = {
|
|
||||||
blockNumber,
|
|
||||||
id: transactionHash,
|
|
||||||
timestamp: this._chance.timestamp()
|
|
||||||
};
|
|
||||||
|
|
||||||
this._entities.transactions.push(transaction);
|
|
||||||
|
|
||||||
// Generate Burns
|
|
||||||
this._entities.burns.push({
|
|
||||||
id: `${transaction.id}#${transactionIndex}`,
|
|
||||||
blockNumber,
|
|
||||||
transaction: transaction.id,
|
|
||||||
pool: pool.id,
|
|
||||||
timestamp: this._chance.timestamp(),
|
|
||||||
owner: this._getRandomAddress(),
|
|
||||||
origin: this._getRandomAddress(),
|
|
||||||
amount0: this._chance.integer({ min: 1 }),
|
|
||||||
amount1: this._chance.integer({ min: 1 }),
|
|
||||||
amountUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate Mints
|
|
||||||
this._entities.mints.push({
|
|
||||||
id: `${transaction.id}#${transactionIndex}`,
|
|
||||||
blockNumber,
|
|
||||||
transaction: transaction.id,
|
|
||||||
pool: pool.id,
|
|
||||||
timestamp: this._chance.timestamp(),
|
|
||||||
owner: this._getRandomAddress(),
|
|
||||||
origin: this._getRandomAddress(),
|
|
||||||
amount0: this._chance.integer({ min: 1 }),
|
|
||||||
amount1: this._chance.integer({ min: 1 }),
|
|
||||||
amountUSD: this._chance.floating({ min: 1, fixed: 2 }),
|
|
||||||
sender: this._getRandomAddress()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate Swaps
|
|
||||||
this._entities.swaps.push({
|
|
||||||
id: `${transaction.id}#${transactionIndex}`,
|
|
||||||
blockNumber,
|
|
||||||
transaction: transaction.id,
|
|
||||||
pool: pool.id,
|
|
||||||
timestamp: this._chance.timestamp(),
|
|
||||||
origin: this._getRandomAddress(),
|
|
||||||
amount0: this._chance.integer({ min: 1 }),
|
|
||||||
amount1: this._chance.integer({ min: 1 }),
|
|
||||||
amountUSD: this._chance.floating({ min: 1, fixed: 2 })
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_getRandomAddress (): string {
|
|
||||||
return ethers.utils.hexlify(ethers.utils.randomBytes(20));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,462 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
|
||||||
import debug from 'debug';
|
|
||||||
import BigInt from 'apollo-type-bigint';
|
|
||||||
|
|
||||||
import { BlockHeight, OrderDirection } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Data, Entity, NO_OF_BLOCKS } from './data';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:test');
|
|
||||||
|
|
||||||
enum BurnOrderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BurnFilter {
|
|
||||||
pool: string;
|
|
||||||
token0: string;
|
|
||||||
token1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MintOrderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MintFilter {
|
|
||||||
pool: string;
|
|
||||||
token0: string;
|
|
||||||
token1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PoolOrderBy {
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PoolFilter {
|
|
||||||
id: string;
|
|
||||||
id_in: [string];
|
|
||||||
token0: string;
|
|
||||||
token0_in: [string];
|
|
||||||
token1: string;
|
|
||||||
token1_in: [string];
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TokenOrderBy {
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TokenFilter {
|
|
||||||
id: string;
|
|
||||||
id_in: [string];
|
|
||||||
name_contains: string;
|
|
||||||
symbol_contains: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TransactionOrderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SwapFilter {
|
|
||||||
pool: string;
|
|
||||||
token0: string;
|
|
||||||
token1: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SwapOrderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DayDataOrderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DayDataFilter {
|
|
||||||
date_gt: number;
|
|
||||||
pool: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TickFilter {
|
|
||||||
poolAddress: string;
|
|
||||||
tickIdx_gte: number;
|
|
||||||
tickIdx_lte: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TokenHourDataOrderBy {
|
|
||||||
periodStartUnix
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TokenHourDataFilter {
|
|
||||||
periodStartUnix_gt: number;
|
|
||||||
token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createResolvers = async (): Promise<any> => {
|
|
||||||
const latestBlockNumber = NO_OF_BLOCKS - 1;
|
|
||||||
const data = Data.getInstance();
|
|
||||||
const { bundles, burns, pools, transactions, factories, mints, tokens, swaps, poolDayDatas, tokenDayDatas, uniswapDayDatas, ticks, tokenHourDatas } = data.entities;
|
|
||||||
|
|
||||||
return {
|
|
||||||
BigInt: new BigInt('bigInt'),
|
|
||||||
|
|
||||||
Query: {
|
|
||||||
bundle: (_: any, { id: bundleId, block }: { id: string, block: BlockHeight }) => {
|
|
||||||
log('bundle', bundleId, block);
|
|
||||||
const res = bundles.find((bundle: Entity) => bundle.blockNumber === block.number && bundle.id === bundleId);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
const { ethPriceUSD, id } = res;
|
|
||||||
return { ethPriceUSD, id };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
bundles: (_: any, { first, block }: { first: number, block: BlockHeight }) => {
|
|
||||||
log('bundles', first, block);
|
|
||||||
|
|
||||||
const res = bundles.filter((bundle: Entity) => bundle.blockNumber === block.number)
|
|
||||||
.slice(0, first)
|
|
||||||
.map(({ ethPriceUSD, id }) => ({ ethPriceUSD, id }));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
burns: (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: BurnOrderBy, orderDirection: OrderDirection, where: BurnFilter }) => {
|
|
||||||
log('burns', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = burns.filter((burn: Entity) => {
|
|
||||||
if (burn.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([field, value]) => burn[field] === value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(0, first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
})
|
|
||||||
.map(burn => {
|
|
||||||
return {
|
|
||||||
...burn,
|
|
||||||
pool: pools.find(pool => pool.id === burn.pool),
|
|
||||||
transaction: transactions.find(transaction => transaction.id === burn.transaction)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
factories: (_: any, { first, block }: { first: number, block: BlockHeight }) => {
|
|
||||||
log('factories', first, block);
|
|
||||||
|
|
||||||
const res = factories.filter((factory: Entity) => factory.blockNumber === block.number)
|
|
||||||
.slice(0, first);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
mints: (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: MintOrderBy, orderDirection: OrderDirection, where: MintFilter }) => {
|
|
||||||
log('mints', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = mints.filter((mint: Entity) => {
|
|
||||||
if (mint.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([field, value]) => mint[field] === value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(0, first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
})
|
|
||||||
.map(mint => {
|
|
||||||
return {
|
|
||||||
...mint,
|
|
||||||
pool: pools.find(pool => pool.id === mint.pool),
|
|
||||||
transaction: transactions.find(transaction => transaction.id === mint.transaction)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
pool: (_: any, { id: poolId }: { id: string }) => {
|
|
||||||
log('pool', poolId);
|
|
||||||
const res = pools.find((pool: Entity) => pool.id === poolId);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
return {
|
|
||||||
...res,
|
|
||||||
token0: tokens.find(token => token.id === res.token0),
|
|
||||||
token1: tokens.find(token => token.id === res.token1)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
pools: (_: any, { first, orderBy, orderDirection, where, block }: { first: number, orderBy: PoolOrderBy, orderDirection: OrderDirection, where: PoolFilter, block: BlockHeight }) => {
|
|
||||||
log('pools', first, orderBy, orderDirection, where, block);
|
|
||||||
|
|
||||||
const res = pools.filter((pool: Entity) => {
|
|
||||||
if (pool.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_in')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return value.some((el: any) => el === pool[field]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pool[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(0, first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
})
|
|
||||||
.map(pool => {
|
|
||||||
return {
|
|
||||||
...pool,
|
|
||||||
token0: tokens.find(token => token.id === pool.token0),
|
|
||||||
token1: tokens.find(token => token.id === pool.token1)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
token: (_: any, { id: tokenId, block }: { id: string, block: BlockHeight }) => {
|
|
||||||
log('token', tokenId, block);
|
|
||||||
const res = tokens.find((token: Entity) => token.blockNumber === block.number && token.id === tokenId);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
tokens: (_: any, { orderBy, orderDirection, where }: { orderBy: TokenOrderBy, orderDirection: OrderDirection, where: TokenFilter }) => {
|
|
||||||
log('tokens', orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = tokens.filter((token: Entity) => {
|
|
||||||
if (token.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_in')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return value.some((el: any) => el === token[field]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return token[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
transactions: (_: any, { first, orderBy, orderDirection }: { first: number, orderBy: TransactionOrderBy, orderDirection: OrderDirection }) => {
|
|
||||||
log('transactions', first, orderBy, orderDirection);
|
|
||||||
|
|
||||||
const res = transactions.filter((transaction: Entity) => transaction.blockNumber === latestBlockNumber)
|
|
||||||
.slice(0, first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
})
|
|
||||||
.map(transaction => {
|
|
||||||
return {
|
|
||||||
...transaction,
|
|
||||||
burns: burns.filter(burn => burn.transaction === transaction.id),
|
|
||||||
mints: mints.filter(mint => mint.transaction === transaction.id),
|
|
||||||
swaps: swaps.filter(swap => swap.transaction === transaction.id)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
swaps: (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: SwapOrderBy, orderDirection: OrderDirection, where: SwapFilter }) => {
|
|
||||||
log('swaps', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = swaps.filter((swap: Entity) => {
|
|
||||||
if (swap.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([field, value]) => swap[field] === value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(0, first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
})
|
|
||||||
.map(swap => {
|
|
||||||
return {
|
|
||||||
...swap,
|
|
||||||
pool: pools.find(pool => pool.id === swap.pool),
|
|
||||||
transaction: transactions.find(transaction => transaction.id === swap.transaction)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
poolDayDatas: (_: any, { skip, first, orderBy, orderDirection, where }: { skip: number, first: number, orderBy: DayDataOrderBy, orderDirection: OrderDirection, where: DayDataFilter }) => {
|
|
||||||
log('poolDayDatas', skip, first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = poolDayDatas.filter((poolDayData: Entity) => {
|
|
||||||
if (poolDayData.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_gt')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return poolDayData[field] > value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return poolDayData[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(skip, skip + first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
tokenDayDatas: (_: any, { skip, first, orderBy, orderDirection, where }: { skip: number, first: number, orderBy: DayDataOrderBy, orderDirection: OrderDirection, where: DayDataFilter }) => {
|
|
||||||
log('tokenDayDatas', skip, first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = tokenDayDatas.filter((tokenDayData: Entity) => {
|
|
||||||
if (tokenDayData.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_gt')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return tokenDayData[field] > value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenDayData[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(skip, skip + first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
uniswapDayDatas: (_: any, { skip, first, orderBy, orderDirection, where }: { skip: number, first: number, orderBy: DayDataOrderBy, orderDirection: OrderDirection, where: DayDataFilter }) => {
|
|
||||||
log('uniswapDayDatas', skip, first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = uniswapDayDatas.filter((uniswapDayData: Entity) => {
|
|
||||||
if (uniswapDayData.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_gt')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return uniswapDayData[field] > value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uniswapDayData[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(skip, skip + first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
ticks: (_: any, { skip, first, where, block }: { skip: number, first: number, where: TickFilter, block: BlockHeight }) => {
|
|
||||||
log('ticks', skip, first, where, block);
|
|
||||||
|
|
||||||
const res = ticks.filter((tick: Entity) => {
|
|
||||||
if (tick.blockNumber === block.number) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_gte')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return tick[field] >= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter.endsWith('_lte')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return tick[field] <= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tick[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(skip, skip + first);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
tokenHourDatas: (_: any, { skip, first, orderBy, orderDirection, where }: { skip: number, first: number, orderBy: TokenHourDataOrderBy, orderDirection: OrderDirection, where: TokenHourDataFilter }) => {
|
|
||||||
log('tokenHourDatas', skip, first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
const res = tokenHourDatas.filter((tokenHourData: Entity) => {
|
|
||||||
if (tokenHourData.blockNumber === latestBlockNumber) {
|
|
||||||
return Object.entries(where || {})
|
|
||||||
.every(([filter, value]) => {
|
|
||||||
if (filter.endsWith('_gt')) {
|
|
||||||
const field = filter.substring(0, filter.length - 3);
|
|
||||||
|
|
||||||
return tokenHourData[field] > value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenHourData[filter] === value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).slice(skip, skip + first)
|
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
a = a[orderBy];
|
|
||||||
b = b[orderBy];
|
|
||||||
return orderDirection === OrderDirection.asc ? (a - b) : (b - a);
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,29 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import 'mocha';
|
|
||||||
import { expect } from 'chai';
|
|
||||||
import { GraphQLClient } from 'graphql-request';
|
|
||||||
|
|
||||||
import { queryBundles } from '../queries';
|
|
||||||
import { Data } from './data';
|
|
||||||
|
|
||||||
describe('server', () => {
|
|
||||||
const client = new GraphQLClient('http://localhost:3004/graphql');
|
|
||||||
const data = Data.getInstance();
|
|
||||||
|
|
||||||
it('query bundle', async () => {
|
|
||||||
const { bundles } = data.entities;
|
|
||||||
expect(bundles.length).to.be.greaterThan(0);
|
|
||||||
|
|
||||||
for (let i = 0; i < bundles.length; i++) {
|
|
||||||
const { id, blockNumber, ethPriceUSD } = bundles[i];
|
|
||||||
|
|
||||||
// Bundle query.
|
|
||||||
const [bundle] = await client.request(queryBundles, { first: 1, block: { number: blockNumber } });
|
|
||||||
expect(bundle.id).to.equal(id);
|
|
||||||
expect(bundle.ethPriceUSD).to.equal(ethPriceUSD);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,283 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { gql } from 'graphql-request';
|
|
||||||
|
|
||||||
const resultPool = `
|
|
||||||
{
|
|
||||||
id,
|
|
||||||
feeTier,
|
|
||||||
liquidity,
|
|
||||||
sqrtPrice,
|
|
||||||
tick,
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
token0Price,
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
token1Price,
|
|
||||||
totalValueLockedToken0,
|
|
||||||
totalValueLockedToken1,
|
|
||||||
totalValueLockedUSD,
|
|
||||||
txCount,
|
|
||||||
volumeUSD,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const queryToken = gql`
|
|
||||||
query queryToken($id: ID!, $block: Block_height) {
|
|
||||||
token(id: $id, block: $block) {
|
|
||||||
derivedETH
|
|
||||||
feesUSD
|
|
||||||
id
|
|
||||||
name
|
|
||||||
symbol
|
|
||||||
totalValueLocked
|
|
||||||
totalValueLockedUSD
|
|
||||||
txCount
|
|
||||||
volume
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
export const queryFactories = gql`
|
|
||||||
query queryFactories($block: Block_height, $first: Int) {
|
|
||||||
factories(first: $first, block: $block) {
|
|
||||||
id
|
|
||||||
totalFeesUSD
|
|
||||||
totalValueLockedUSD
|
|
||||||
totalVolumeUSD
|
|
||||||
txCount
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
export const queryBundles = gql`
|
|
||||||
query queryBundles($block: Block_height, $first: Int) {
|
|
||||||
bundles(first: $first, block: $block) {
|
|
||||||
id
|
|
||||||
ethPriceUSD
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting Pool by id.
|
|
||||||
export const queryPoolById = gql`
|
|
||||||
query queryPoolById($id: ID!) {
|
|
||||||
pool(id: $id)
|
|
||||||
${resultPool}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
export const queryTicks = gql`
|
|
||||||
query queryTicks($skip: Int, $first: Int, $where: Tick_filter, $block: Block_height) {
|
|
||||||
ticks(skip: $skip, first: $first, where: $where, block: $block) {
|
|
||||||
id
|
|
||||||
liquidityGross
|
|
||||||
liquidityNet
|
|
||||||
price0
|
|
||||||
price1
|
|
||||||
tickIdx
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting Pool(s).
|
|
||||||
export const queryPools = gql`
|
|
||||||
query queryPools($where: Pool_filter, $first: Int, $orderBy: Pool_orderBy, $orderDirection: OrderDirection) {
|
|
||||||
pools(where: $where, first: $first, orderBy: $orderBy, orderDirection: $orderDirection)
|
|
||||||
${resultPool}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting UniswapDayData(s).
|
|
||||||
export const queryUniswapDayDatas = gql`
|
|
||||||
query queryUniswapDayDatas($first: Int, $skip: Int, $orderBy: UniswapDayData_orderBy, $orderDirection: OrderDirection, $where: UniswapDayData_filter) {
|
|
||||||
uniswapDayDatas(first: $first, skip: $skip, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) {
|
|
||||||
id,
|
|
||||||
date,
|
|
||||||
tvlUSD,
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting PoolDayData(s).
|
|
||||||
export const queryPoolDayDatas = gql`
|
|
||||||
query queryPoolDayDatas($first: Int, $skip: Int, $orderBy: PoolDayData_orderBy, $orderDirection: OrderDirection, $where: PoolDayData_filter) {
|
|
||||||
poolDayDatas(first: $first, skip: $skip, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) {
|
|
||||||
id,
|
|
||||||
date,
|
|
||||||
tvlUSD,
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting TokenDayDatas(s).
|
|
||||||
export const queryTokenDayDatas = gql`
|
|
||||||
query queryTokenDayData($first: Int, $skip: Int, $orderBy: TokenDayData_orderBy, $orderDirection: OrderDirection, $where: TokenDayData_filter) {
|
|
||||||
tokenDayDatas(first: $first, skip: $skip, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) {
|
|
||||||
id,
|
|
||||||
date,
|
|
||||||
totalValueLockedUSD,
|
|
||||||
volumeUSD
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting TokenDayDatas(s).
|
|
||||||
export const queryTokenHourDatas = gql`
|
|
||||||
query queryTokenHourData($first: Int, $skip: Int, $orderBy: TokenHourData_orderBy, $orderDirection: OrderDirection, $where: TokenHourData_filter) {
|
|
||||||
tokenHourDatas(first: $first, skip: $skip, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) {
|
|
||||||
id,
|
|
||||||
low,
|
|
||||||
high,
|
|
||||||
open,
|
|
||||||
close,
|
|
||||||
periodStartUnix
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting mint(s).
|
|
||||||
export const queryMints = gql`
|
|
||||||
query queryMints(
|
|
||||||
$first: Int,
|
|
||||||
$orderBy: Mint_orderBy,
|
|
||||||
$orderDirection: OrderDirection,
|
|
||||||
$where: Mint_filter) {
|
|
||||||
mints(
|
|
||||||
first: $first,
|
|
||||||
orderBy: $orderBy,
|
|
||||||
orderDirection: $orderDirection,
|
|
||||||
where: $where) {
|
|
||||||
amount0,
|
|
||||||
amount1,
|
|
||||||
amountUSD,
|
|
||||||
id,
|
|
||||||
origin,
|
|
||||||
owner,
|
|
||||||
sender,
|
|
||||||
timestamp,
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting burns(s).
|
|
||||||
export const queryBurns = gql`
|
|
||||||
query queryBurns(
|
|
||||||
$first: Int,
|
|
||||||
$orderBy: Burn_orderBy,
|
|
||||||
$orderDirection: OrderDirection,
|
|
||||||
$where: Burn_filter) {
|
|
||||||
burns(
|
|
||||||
first: $first,
|
|
||||||
orderBy: $orderBy,
|
|
||||||
orderDirection: $orderDirection,
|
|
||||||
where: $where) {
|
|
||||||
amount0,
|
|
||||||
amount1,
|
|
||||||
amountUSD,
|
|
||||||
id,
|
|
||||||
origin,
|
|
||||||
owner,
|
|
||||||
timestamp,
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting swap(s) .
|
|
||||||
export const querySwaps = gql`
|
|
||||||
query querySwaps(
|
|
||||||
$first: Int,
|
|
||||||
$orderBy: Swap_orderBy,
|
|
||||||
$orderDirection: OrderDirection,
|
|
||||||
$where: Swap_filter) {
|
|
||||||
swaps(
|
|
||||||
first: $first,
|
|
||||||
orderBy: $orderBy,
|
|
||||||
orderDirection: $orderDirection,
|
|
||||||
where: $where) {
|
|
||||||
amount0,
|
|
||||||
amount1,
|
|
||||||
amountUSD,
|
|
||||||
id,
|
|
||||||
origin,
|
|
||||||
timestamp,
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting transactions(s).
|
|
||||||
export const queryTransactions = gql`
|
|
||||||
query queryTransactions(
|
|
||||||
$first: Int,
|
|
||||||
$orderBy: Transaction_orderBy,
|
|
||||||
$mintOrderBy: Mint_orderBy,
|
|
||||||
$burnOrderBy: Burn_orderBy,
|
|
||||||
$swapOrderBy: Swap_orderBy,
|
|
||||||
$orderDirection: OrderDirection) {
|
|
||||||
transactions(
|
|
||||||
first: $first,
|
|
||||||
orderBy: $orderBy,
|
|
||||||
orderDirection: $orderDirection) {
|
|
||||||
id,
|
|
||||||
mints( first: $first, orderBy: $mintOrderBy, orderDirection: $orderDirection) {
|
|
||||||
id,
|
|
||||||
timestamp
|
|
||||||
},
|
|
||||||
burns( first: $first, orderBy: $burnOrderBy, orderDirection: $orderDirection) {
|
|
||||||
id,
|
|
||||||
timestamp
|
|
||||||
},
|
|
||||||
swaps( first: $first, orderBy: $swapOrderBy, orderDirection: $orderDirection) {
|
|
||||||
id,
|
|
||||||
timestamp
|
|
||||||
},
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Getting positions.
|
|
||||||
export const queryPositions = gql`
|
|
||||||
query queryPositions($first: Int, $where: Position_filter) {
|
|
||||||
positions(first: $first, where: $where) {
|
|
||||||
id,
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
token0 {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
token1 {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
tickLower {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
tickUpper {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
transaction {
|
|
||||||
id
|
|
||||||
},
|
|
||||||
liquidity,
|
|
||||||
depositedToken0,
|
|
||||||
depositedToken1,
|
|
||||||
collectedFeesToken0,
|
|
||||||
collectedFeesToken1,
|
|
||||||
owner,
|
|
||||||
feeGrowthInside0LastX128,
|
|
||||||
feeGrowthInside1LastX128
|
|
||||||
}
|
|
||||||
}`;
|
|
@ -1,251 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import BigInt from 'apollo-type-bigint';
|
|
||||||
import debug from 'debug';
|
|
||||||
import { GraphQLScalarType } from 'graphql';
|
|
||||||
|
|
||||||
import { BlockHeight, GraphDecimal, OrderDirection } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { Burn } from './entity/Burn';
|
|
||||||
import { Bundle } from './entity/Bundle';
|
|
||||||
import { Factory } from './entity/Factory';
|
|
||||||
import { Mint } from './entity/Mint';
|
|
||||||
import { PoolDayData } from './entity/PoolDayData';
|
|
||||||
import { Pool } from './entity/Pool';
|
|
||||||
import { Swap } from './entity/Swap';
|
|
||||||
import { Tick } from './entity/Tick';
|
|
||||||
import { Token } from './entity/Token';
|
|
||||||
import { TokenDayData } from './entity/TokenDayData';
|
|
||||||
import { TokenHourData } from './entity/TokenHourData';
|
|
||||||
import { Transaction } from './entity/Transaction';
|
|
||||||
import { UniswapDayData } from './entity/UniswapDayData';
|
|
||||||
import { Position } from './entity/Position';
|
|
||||||
import { EventWatcher } from './events';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:resolver');
|
|
||||||
|
|
||||||
export { BlockHeight };
|
|
||||||
|
|
||||||
export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatcher): Promise<any> => {
|
|
||||||
assert(indexer);
|
|
||||||
|
|
||||||
return {
|
|
||||||
BigInt: new BigInt('bigInt'),
|
|
||||||
|
|
||||||
BigDecimal: new GraphQLScalarType({
|
|
||||||
name: 'BigDecimal',
|
|
||||||
description: 'BigDecimal custom scalar type',
|
|
||||||
parseValue (value) {
|
|
||||||
// value from the client
|
|
||||||
return new GraphDecimal(value);
|
|
||||||
},
|
|
||||||
serialize (value: GraphDecimal) {
|
|
||||||
// value sent to the client
|
|
||||||
return value.toFixed();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
ChainIndexingStatus: {
|
|
||||||
__resolveType: () => {
|
|
||||||
return 'EthereumIndexingStatus';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Subscription: {
|
|
||||||
onBlockProgressEvent: {
|
|
||||||
subscribe: () => eventWatcher.getBlockProgressEventIterator()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Query: {
|
|
||||||
bundle: async (_: any, { id, block = {} }: { id: string, block: BlockHeight }) => {
|
|
||||||
log('bundle', id, block);
|
|
||||||
|
|
||||||
return indexer.getBundle(id, block);
|
|
||||||
},
|
|
||||||
|
|
||||||
bundles: async (_: any, { block = {}, first }: { first: number, block: BlockHeight }) => {
|
|
||||||
log('bundles', block, first);
|
|
||||||
|
|
||||||
return indexer.getEntities(Bundle, block, {}, { limit: first });
|
|
||||||
},
|
|
||||||
|
|
||||||
burns: async (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('burns', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(Burn, {}, where, { limit: first, orderBy, orderDirection }, ['burn.pool', 'burn.transaction', 'pool.token0', 'pool.token1']);
|
|
||||||
},
|
|
||||||
|
|
||||||
factories: async (_: any, { block = {}, first }: { first: number, block: BlockHeight }) => {
|
|
||||||
log('factories', block, first);
|
|
||||||
|
|
||||||
return indexer.getEntities(Factory, block, {}, { limit: first });
|
|
||||||
},
|
|
||||||
|
|
||||||
mints: async (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('mints', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(Mint, {}, where, { limit: first, orderBy, orderDirection }, ['mint.pool', 'mint.transaction', 'pool.token0', 'pool.token1']);
|
|
||||||
},
|
|
||||||
|
|
||||||
pool: async (_: any, { id, block = {} }: { id: string, block: BlockHeight }) => {
|
|
||||||
log('pool', id, block);
|
|
||||||
|
|
||||||
return indexer.getPool(id, block);
|
|
||||||
},
|
|
||||||
|
|
||||||
poolDayDatas: async (_: any, { first, skip, orderBy, orderDirection, where }: { first: number, skip: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('poolDayDatas', first, skip, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(PoolDayData, {}, where, { limit: first, skip, orderBy, orderDirection });
|
|
||||||
},
|
|
||||||
|
|
||||||
pools: async (_: any, { block = {}, first, orderBy, orderDirection, where = {} }: { block: BlockHeight, first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('pools', block, first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(Pool, block, where, { limit: first, orderBy, orderDirection }, ['pool.token0', 'pool.token1']);
|
|
||||||
},
|
|
||||||
|
|
||||||
swaps: async (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('swaps', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(Swap, {}, where, { limit: first, orderBy, orderDirection }, ['swap.pool', 'swap.transaction', 'pool.token0', 'pool.token1']);
|
|
||||||
},
|
|
||||||
|
|
||||||
ticks: async (_: any, { block = {}, first, skip, where = {} }: { block: BlockHeight, first: number, skip: number, where: { [key: string]: any } }) => {
|
|
||||||
log('ticks', block, first, skip, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(Tick, block, where, { limit: first, skip });
|
|
||||||
},
|
|
||||||
|
|
||||||
token: async (_: any, { id, block = {} }: { id: string, block: BlockHeight }) => {
|
|
||||||
log('token', id, block);
|
|
||||||
|
|
||||||
return indexer.getToken(id, block);
|
|
||||||
},
|
|
||||||
|
|
||||||
tokens: async (_: any, { block = {}, first, orderBy, orderDirection, where }: { block: BlockHeight, first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('tokens', orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(Token, block, where, { limit: first, orderBy, orderDirection }, ['token.whitelistPools']);
|
|
||||||
},
|
|
||||||
|
|
||||||
tokenDayDatas: async (_: any, { first, skip, orderBy, orderDirection, where }: { first: number, skip: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('tokenDayDatas', first, skip, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(TokenDayData, {}, where, { limit: first, skip, orderBy, orderDirection });
|
|
||||||
},
|
|
||||||
|
|
||||||
tokenHourDatas: async (_: any, { first, skip, orderBy, orderDirection, where }: { first: number, skip: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('tokenHourDatas', first, skip, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(TokenHourData, {}, where, { limit: first, skip, orderBy, orderDirection });
|
|
||||||
},
|
|
||||||
|
|
||||||
transactions: async (_: any, { first, orderBy, orderDirection }: { first: number, orderBy: string, orderDirection: OrderDirection}) => {
|
|
||||||
log('transactions', first, orderBy, orderDirection);
|
|
||||||
|
|
||||||
return indexer.getEntities(
|
|
||||||
Transaction,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{ limit: first, orderBy, orderDirection },
|
|
||||||
[
|
|
||||||
'transaction.mints',
|
|
||||||
'transaction.burns',
|
|
||||||
'transaction.swaps',
|
|
||||||
{
|
|
||||||
property: 'mints.transaction',
|
|
||||||
alias: 'mintsTransaction'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'burns.transaction',
|
|
||||||
alias: 'burnsTransaction'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'swaps.transaction',
|
|
||||||
alias: 'swapsTransaction'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'mints.pool',
|
|
||||||
alias: 'mintsPool'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'burns.pool',
|
|
||||||
alias: 'burnsPool'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'swaps.pool',
|
|
||||||
alias: 'swapsPool'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'mintsPool.token0',
|
|
||||||
alias: 'mintsPoolToken0'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'mintsPool.token1',
|
|
||||||
alias: 'mintsPoolToken1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'burnsPool.token0',
|
|
||||||
alias: 'burnsPoolToken0'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'burnsPool.token1',
|
|
||||||
alias: 'burnsPoolToken1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'swapsPool.token0',
|
|
||||||
alias: 'swapsPoolToken0'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
property: 'swapsPool.token1',
|
|
||||||
alias: 'swapsPoolToken1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
uniswapDayDatas: async (_: any, { first, skip, orderBy, orderDirection, where }: { first: number, skip: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('uniswapDayDatas', first, skip, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(UniswapDayData, {}, where, { limit: first, skip, orderBy, orderDirection });
|
|
||||||
},
|
|
||||||
|
|
||||||
positions: async (_: any, { first, where }: { first: number, where: { [key: string]: any } }) => {
|
|
||||||
log('positions', first, where);
|
|
||||||
|
|
||||||
return indexer.getEntities(
|
|
||||||
Position,
|
|
||||||
{},
|
|
||||||
where,
|
|
||||||
{ limit: first },
|
|
||||||
[
|
|
||||||
'position.pool',
|
|
||||||
'position.token0',
|
|
||||||
'position.token1',
|
|
||||||
'position.tickLower',
|
|
||||||
'position.tickUpper',
|
|
||||||
'position.transaction'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
blocks: async (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
|
|
||||||
log('blocks', first, orderBy, orderDirection, where);
|
|
||||||
|
|
||||||
return indexer.getBlockEntities(where, { limit: first, orderBy, orderDirection });
|
|
||||||
},
|
|
||||||
|
|
||||||
indexingStatusForCurrentVersion: async (_: any, { subgraphName }: { subgraphName: string }) => {
|
|
||||||
log('health', subgraphName);
|
|
||||||
|
|
||||||
return indexer.getIndexingStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,490 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client/core';
|
|
||||||
|
|
||||||
export default gql`
|
|
||||||
scalar BigDecimal
|
|
||||||
|
|
||||||
scalar BigInt
|
|
||||||
|
|
||||||
scalar Bytes
|
|
||||||
|
|
||||||
input Block_height {
|
|
||||||
hash: Bytes
|
|
||||||
number: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Pool {
|
|
||||||
feeTier: BigInt!
|
|
||||||
id: ID!
|
|
||||||
liquidity: BigInt!
|
|
||||||
sqrtPrice: BigInt!
|
|
||||||
tick: BigInt
|
|
||||||
token0: Token!
|
|
||||||
token0Price: BigDecimal!
|
|
||||||
token1: Token!
|
|
||||||
token1Price: BigDecimal!
|
|
||||||
totalValueLockedToken0: BigDecimal!
|
|
||||||
totalValueLockedToken1: BigDecimal!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
txCount: BigInt!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type PoolDayData {
|
|
||||||
date: Int!
|
|
||||||
id: ID!
|
|
||||||
tvlUSD: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tick {
|
|
||||||
id: ID!
|
|
||||||
liquidityGross: BigInt!
|
|
||||||
liquidityNet: BigInt!
|
|
||||||
price0: BigDecimal!
|
|
||||||
price1: BigDecimal!
|
|
||||||
tickIdx: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mint {
|
|
||||||
amount0: BigDecimal!
|
|
||||||
amount1: BigDecimal!
|
|
||||||
amountUSD: BigDecimal
|
|
||||||
id: ID!
|
|
||||||
origin: Bytes!
|
|
||||||
owner: Bytes!
|
|
||||||
pool: Pool!
|
|
||||||
sender: Bytes
|
|
||||||
timestamp: BigInt!
|
|
||||||
transaction: Transaction!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Swap {
|
|
||||||
amount0: BigDecimal!
|
|
||||||
amount1: BigDecimal!
|
|
||||||
amountUSD: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
origin: Bytes!
|
|
||||||
pool: Pool!
|
|
||||||
timestamp: BigInt!
|
|
||||||
transaction: Transaction!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Burn {
|
|
||||||
amount0: BigDecimal!
|
|
||||||
amount1: BigDecimal!
|
|
||||||
amountUSD: BigDecimal
|
|
||||||
id: ID!
|
|
||||||
origin: Bytes!
|
|
||||||
owner: Bytes
|
|
||||||
pool: Pool!
|
|
||||||
timestamp: BigInt!
|
|
||||||
transaction: Transaction!
|
|
||||||
}
|
|
||||||
|
|
||||||
type UniswapDayData {
|
|
||||||
date: Int!
|
|
||||||
id: ID!
|
|
||||||
tvlUSD: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Factory {
|
|
||||||
id: ID!
|
|
||||||
totalFeesUSD: BigDecimal!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
totalVolumeUSD: BigDecimal!
|
|
||||||
txCount: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Transaction {
|
|
||||||
burns(skip: Int = 0, first: Int = 100, orderBy: Burn_orderBy, orderDirection: OrderDirection, where: Burn_filter): [Burn]!
|
|
||||||
id: ID!
|
|
||||||
mints(skip: Int = 0, first: Int = 100, orderBy: Mint_orderBy, orderDirection: OrderDirection, where: Mint_filter): [Mint]!
|
|
||||||
swaps(skip: Int = 0, first: Int = 100, orderBy: Swap_orderBy, orderDirection: OrderDirection, where: Swap_filter): [Swap]!
|
|
||||||
timestamp: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Token {
|
|
||||||
decimals: BigInt!
|
|
||||||
derivedETH: BigDecimal!
|
|
||||||
feesUSD: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
name: String!
|
|
||||||
symbol: String!
|
|
||||||
totalValueLocked: BigDecimal!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
txCount: BigInt!
|
|
||||||
volume: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
whitelistPools: [Pool]
|
|
||||||
}
|
|
||||||
|
|
||||||
type TokenDayData {
|
|
||||||
date: Int!
|
|
||||||
id: ID!
|
|
||||||
totalValueLockedUSD: BigDecimal!
|
|
||||||
volumeUSD: BigDecimal!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bundle {
|
|
||||||
ethPriceUSD: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
}
|
|
||||||
|
|
||||||
type TokenHourData {
|
|
||||||
close: BigDecimal!
|
|
||||||
high: BigDecimal!
|
|
||||||
id: ID!
|
|
||||||
low: BigDecimal!
|
|
||||||
open: BigDecimal!
|
|
||||||
periodStartUnix: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Position {
|
|
||||||
id: ID!
|
|
||||||
pool: Pool!
|
|
||||||
token0: Token!
|
|
||||||
token1: Token!
|
|
||||||
tickLower: Tick!
|
|
||||||
tickUpper: Tick!
|
|
||||||
transaction: Transaction!
|
|
||||||
liquidity: BigInt!
|
|
||||||
depositedToken0: BigDecimal!
|
|
||||||
depositedToken1: BigDecimal!
|
|
||||||
collectedFeesToken0: BigDecimal!
|
|
||||||
collectedFeesToken1: BigDecimal!
|
|
||||||
owner: Bytes!
|
|
||||||
feeGrowthInside0LastX128: BigInt!
|
|
||||||
feeGrowthInside1LastX128: BigInt!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Block {
|
|
||||||
number: Int!
|
|
||||||
hash: Bytes!
|
|
||||||
timestamp: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type BlockProgressEvent {
|
|
||||||
blockNumber: Int!
|
|
||||||
blockHash: String!
|
|
||||||
numEvents: Int!
|
|
||||||
numProcessedEvents: Int!
|
|
||||||
isComplete: Boolean!
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderDirection {
|
|
||||||
asc
|
|
||||||
desc
|
|
||||||
}
|
|
||||||
|
|
||||||
input PoolDayData_filter {
|
|
||||||
date_gt: Int
|
|
||||||
pool: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PoolDayData_orderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
input Pool_filter {
|
|
||||||
id: ID
|
|
||||||
id_in: [ID!]
|
|
||||||
token0: String
|
|
||||||
token0_in: [String!]
|
|
||||||
token1: String
|
|
||||||
token1_in: [String!]
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Pool_orderBy {
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
input Tick_filter {
|
|
||||||
poolAddress: String
|
|
||||||
tickIdx_gte: BigInt
|
|
||||||
tickIdx_lte: BigInt
|
|
||||||
}
|
|
||||||
|
|
||||||
input Mint_filter {
|
|
||||||
pool: String
|
|
||||||
token0: String
|
|
||||||
token1: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Mint_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
input Swap_filter {
|
|
||||||
pool: String
|
|
||||||
token0: String
|
|
||||||
token1: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Swap_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
input Burn_filter {
|
|
||||||
pool: String
|
|
||||||
token0: String
|
|
||||||
token1: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Burn_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UniswapDayData_orderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
input UniswapDayData_filter {
|
|
||||||
date_gt: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Transaction_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
input Token_filter {
|
|
||||||
id: ID
|
|
||||||
id_in: [ID!]
|
|
||||||
name_contains: String
|
|
||||||
symbol_contains: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Token_orderBy {
|
|
||||||
totalValueLockedUSD
|
|
||||||
}
|
|
||||||
|
|
||||||
input TokenDayData_filter {
|
|
||||||
date_gt: Int
|
|
||||||
token: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TokenDayData_orderBy {
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
input TokenHourData_filter {
|
|
||||||
periodStartUnix_gt: Int
|
|
||||||
token: String
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TokenHourData_orderBy {
|
|
||||||
periodStartUnix
|
|
||||||
}
|
|
||||||
|
|
||||||
input Position_filter {
|
|
||||||
id: ID
|
|
||||||
}
|
|
||||||
|
|
||||||
input Block_filter {
|
|
||||||
timestamp_gt: Int
|
|
||||||
timestamp_lt: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Block_orderBy {
|
|
||||||
timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ChainIndexingStatus {
|
|
||||||
chainHeadBlock: Block
|
|
||||||
latestBlock: Block
|
|
||||||
}
|
|
||||||
|
|
||||||
type EthereumIndexingStatus implements ChainIndexingStatus {
|
|
||||||
chainHeadBlock: Block
|
|
||||||
latestBlock: Block
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Health {
|
|
||||||
"""Syncing normally"""
|
|
||||||
healthy
|
|
||||||
|
|
||||||
"""Syncing but with errors"""
|
|
||||||
unhealthy
|
|
||||||
|
|
||||||
"""Halted due to errors"""
|
|
||||||
failed
|
|
||||||
}
|
|
||||||
|
|
||||||
type SubgraphIndexingStatus {
|
|
||||||
synced: Boolean!
|
|
||||||
health: Health!
|
|
||||||
chains: [ChainIndexingStatus!]!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Query {
|
|
||||||
bundle(
|
|
||||||
id: ID!
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an '{ number:
|
|
||||||
Int }' containing the block number or a '{ hash: Bytes }' value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): Bundle
|
|
||||||
|
|
||||||
bundles(
|
|
||||||
first: Int = 100
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an '{ number:
|
|
||||||
Int }' containing the block number or a '{ hash: Bytes }' value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Bundle!]!
|
|
||||||
|
|
||||||
burns(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Burn_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Burn_filter
|
|
||||||
): [Burn!]!
|
|
||||||
|
|
||||||
factories(
|
|
||||||
first: Int = 100
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an '{ number:
|
|
||||||
Int }' containing the block number or a '{ hash: Bytes }' value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Factory!]!
|
|
||||||
|
|
||||||
mints(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Mint_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Mint_filter
|
|
||||||
): [Mint!]!
|
|
||||||
|
|
||||||
pool(
|
|
||||||
id: ID!
|
|
||||||
): Pool
|
|
||||||
|
|
||||||
poolDayDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: PoolDayData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: PoolDayData_filter
|
|
||||||
): [PoolDayData!]!
|
|
||||||
|
|
||||||
pools(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Pool_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Pool_filter
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an '{ number:
|
|
||||||
Int }' containing the block number or a '{ hash: Bytes }' value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Pool!]!
|
|
||||||
|
|
||||||
swaps(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Swap_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Swap_filter
|
|
||||||
): [Swap!]!
|
|
||||||
|
|
||||||
ticks(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
where: Tick_filter
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an '{ number:
|
|
||||||
Int }' containing the block number or a '{ hash: Bytes }' value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): [Tick!]!
|
|
||||||
|
|
||||||
token(
|
|
||||||
id: ID!
|
|
||||||
|
|
||||||
"""
|
|
||||||
The block at which the query should be executed. Can either be an '{ number:
|
|
||||||
Int }' containing the block number or a '{ hash: Bytes }' value containing a
|
|
||||||
block hash. Defaults to the latest block when omitted.
|
|
||||||
"""
|
|
||||||
block: Block_height
|
|
||||||
): Token
|
|
||||||
|
|
||||||
tokenDayDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: TokenDayData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: TokenDayData_filter
|
|
||||||
): [TokenDayData!]!
|
|
||||||
|
|
||||||
tokenHourDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: TokenHourData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: TokenHourData_filter
|
|
||||||
): [TokenHourData!]!
|
|
||||||
|
|
||||||
tokens(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Token_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Token_filter
|
|
||||||
block: Block_height
|
|
||||||
): [Token!]!
|
|
||||||
|
|
||||||
transactions(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Transaction_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
): [Transaction!]!
|
|
||||||
|
|
||||||
uniswapDayDatas(
|
|
||||||
skip: Int = 0
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: UniswapDayData_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: UniswapDayData_filter
|
|
||||||
): [UniswapDayData!]!
|
|
||||||
|
|
||||||
positions(
|
|
||||||
first: Int = 100
|
|
||||||
where: Position_filter
|
|
||||||
): [Position!]!
|
|
||||||
|
|
||||||
blocks(
|
|
||||||
first: Int = 100
|
|
||||||
orderBy: Block_orderBy
|
|
||||||
orderDirection: OrderDirection
|
|
||||||
where: Block_filter
|
|
||||||
): [Block!]!
|
|
||||||
|
|
||||||
indexingStatusForCurrentVersion(
|
|
||||||
subgraphName: String
|
|
||||||
): SubgraphIndexingStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Subscriptions
|
|
||||||
#
|
|
||||||
type Subscription {
|
|
||||||
# Watch for block progress events from filler process.
|
|
||||||
onBlockProgressEvent: BlockProgressEvent!
|
|
||||||
}
|
|
||||||
`;
|
|
@ -1,103 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import express, { Application } from 'express';
|
|
||||||
import { ApolloServer, PubSub } from 'apollo-server-express';
|
|
||||||
import yargs from 'yargs';
|
|
||||||
import { hideBin } from 'yargs/helpers';
|
|
||||||
import debug from 'debug';
|
|
||||||
import 'graphql-import-node';
|
|
||||||
import { createServer } from 'http';
|
|
||||||
|
|
||||||
import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
|
||||||
import { Client as UniClient } from '@vulcanize/uni-watcher';
|
|
||||||
import { DEFAULT_CONFIG_PATH, getConfig, Config, getCustomProvider, JobQueue, initClients } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import typeDefs from './schema';
|
|
||||||
|
|
||||||
import { createResolvers as createMockResolvers } from './mock/resolvers';
|
|
||||||
import { createResolvers } from './resolvers';
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { Database } from './database';
|
|
||||||
import { EventWatcher } from './events';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:server');
|
|
||||||
|
|
||||||
export const main = async (): Promise<any> => {
|
|
||||||
const argv = await yargs(hideBin(process.argv))
|
|
||||||
.option('f', {
|
|
||||||
alias: 'config-file',
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'configuration file path (toml)',
|
|
||||||
type: 'string',
|
|
||||||
default: DEFAULT_CONFIG_PATH
|
|
||||||
})
|
|
||||||
.argv;
|
|
||||||
|
|
||||||
const config: Config = await getConfig(argv.f);
|
|
||||||
const { ethClient } = await initClients(config);
|
|
||||||
|
|
||||||
const { host, port } = config.server;
|
|
||||||
|
|
||||||
const db = new Database(config.database);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
const { uniWatcher, tokenWatcher, ethServer: { rpcProviderEndpoint } } = config.upstream;
|
|
||||||
|
|
||||||
const uniClient = new UniClient(uniWatcher);
|
|
||||||
const erc20Client = new ERC20Client(tokenWatcher);
|
|
||||||
const ethProvider = getCustomProvider(rpcProviderEndpoint);
|
|
||||||
|
|
||||||
const jobQueueConfig = config.jobQueue;
|
|
||||||
assert(jobQueueConfig, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
await jobQueue.start();
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, uniClient, erc20Client, ethClient, ethProvider, jobQueue);
|
|
||||||
|
|
||||||
const pubSub = new PubSub();
|
|
||||||
const eventWatcher = new EventWatcher(config.upstream, ethClient, indexer, pubSub, jobQueue);
|
|
||||||
await eventWatcher.start();
|
|
||||||
|
|
||||||
const resolvers = process.env.MOCK ? await createMockResolvers() : await createResolvers(indexer, eventWatcher);
|
|
||||||
|
|
||||||
const app: Application = express();
|
|
||||||
const server = new ApolloServer({
|
|
||||||
typeDefs,
|
|
||||||
resolvers
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
server.applyMiddleware({ app });
|
|
||||||
|
|
||||||
const httpServer = createServer(app);
|
|
||||||
server.installSubscriptionHandlers(httpServer);
|
|
||||||
|
|
||||||
httpServer.listen(port, host, () => {
|
|
||||||
log(`Server is listening on host ${host} port ${port}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
return { app, server };
|
|
||||||
};
|
|
||||||
|
|
||||||
main().then(() => {
|
|
||||||
log('Starting server...');
|
|
||||||
}).catch(err => {
|
|
||||||
log(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('uncaughtException', err => {
|
|
||||||
log('uncaughtException', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
log(`Exiting process ${process.pid} with code 0`);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
// https://medium.com/@steveruiz/using-a-javascript-library-without-type-declarations-in-a-typescript-project-3643490015f3
|
|
||||||
declare module 'canonical-json'
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "common",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"license": "AGPL-3.0",
|
|
||||||
"typings": "main.d.ts"
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { utils } from 'ethers';
|
|
||||||
|
|
||||||
export const ADDRESS_ZERO = utils.getAddress('0x0000000000000000000000000000000000000000');
|
|
@ -1,76 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { BigNumber, utils } from 'ethers';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
import { GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Transaction as TransactionEntity } from '../entity/Transaction';
|
|
||||||
import { Database } from '../database';
|
|
||||||
import { Block, Transaction } from '../events';
|
|
||||||
|
|
||||||
export const exponentToBigDecimal = (decimals: bigint): GraphDecimal => {
|
|
||||||
let bd = new GraphDecimal(1);
|
|
||||||
|
|
||||||
for (let i = 0; BigNumber.from(decimals).gte(i); i++) {
|
|
||||||
bd = bd.times(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bd;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const convertTokenToDecimal = (tokenAmount: bigint, exchangeDecimals: bigint): GraphDecimal => {
|
|
||||||
if (exchangeDecimals === BigInt(0)) {
|
|
||||||
return new GraphDecimal(tokenAmount.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new GraphDecimal(tokenAmount.toString())).div(exponentToBigDecimal(exchangeDecimals));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const loadTransaction = async (db: Database, dbTx: QueryRunner, event: { block: Block, tx: Transaction }): Promise<TransactionEntity> => {
|
|
||||||
const { tx, block } = event;
|
|
||||||
// Get the txHash in lowercase.
|
|
||||||
const txHash = utils.hexlify(tx.hash);
|
|
||||||
let transaction = await db.getTransaction(dbTx, { id: txHash, blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!transaction) {
|
|
||||||
transaction = new TransactionEntity();
|
|
||||||
transaction.id = txHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.blockNumber = block.number;
|
|
||||||
transaction.timestamp = BigInt(block.timestamp);
|
|
||||||
|
|
||||||
return db.saveTransaction(dbTx, transaction, block);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return 0 if denominator is 0 in division.
|
|
||||||
export const safeDiv = (amount0: GraphDecimal, amount1: GraphDecimal): GraphDecimal => {
|
|
||||||
if (amount1.isZero()) {
|
|
||||||
return new GraphDecimal(0);
|
|
||||||
} else {
|
|
||||||
return amount0.div(amount1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const bigDecimalExponated = (value: GraphDecimal, power: bigint): GraphDecimal => {
|
|
||||||
if (power === BigInt(0)) {
|
|
||||||
return new GraphDecimal(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const negativePower = power > BigInt(0);
|
|
||||||
let result = (new GraphDecimal(0)).plus(value);
|
|
||||||
const powerAbs = BigNumber.from(power).abs();
|
|
||||||
|
|
||||||
for (let i = BigNumber.from(1); i.lt(powerAbs); i = i.add(1)) {
|
|
||||||
result = result.times(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (negativePower) {
|
|
||||||
result = safeDiv(new GraphDecimal(1), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
@ -1,259 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import { BigNumber, utils } from 'ethers';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
import { Database } from '../database';
|
|
||||||
import { Factory } from '../entity/Factory';
|
|
||||||
import { PoolDayData } from '../entity/PoolDayData';
|
|
||||||
import { PoolHourData } from '../entity/PoolHourData';
|
|
||||||
import { Tick } from '../entity/Tick';
|
|
||||||
import { TickDayData } from '../entity/TickDayData';
|
|
||||||
import { Token } from '../entity/Token';
|
|
||||||
import { TokenDayData } from '../entity/TokenDayData';
|
|
||||||
import { TokenHourData } from '../entity/TokenHourData';
|
|
||||||
import { UniswapDayData } from '../entity/UniswapDayData';
|
|
||||||
import { Block } from '../events';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tracks global aggregate data over daily windows.
|
|
||||||
* @param db
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
export const updateUniswapDayData = async (db: Database, dbTx: QueryRunner, event: { contractAddress: string, block: Block }): Promise<UniswapDayData> => {
|
|
||||||
const { block } = event;
|
|
||||||
|
|
||||||
// TODO: In subgraph factory is fetched by hardcoded factory address.
|
|
||||||
// Currently fetching first factory in database as only one exists.
|
|
||||||
const [factory] = await db.getModelEntities(dbTx, Factory, { hash: block.hash }, {}, { limit: 1 });
|
|
||||||
|
|
||||||
const dayID = Math.floor(block.timestamp / 86400); // Rounded.
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
|
|
||||||
let uniswapDayData = await db.getUniswapDayData(dbTx, { id: dayID.toString(), blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!uniswapDayData) {
|
|
||||||
uniswapDayData = new UniswapDayData();
|
|
||||||
uniswapDayData.id = dayID.toString();
|
|
||||||
uniswapDayData.date = dayStartTimestamp;
|
|
||||||
uniswapDayData.tvlUSD = factory.totalValueLockedUSD;
|
|
||||||
uniswapDayData.txCount = factory.txCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
uniswapDayData.tvlUSD = factory.totalValueLockedUSD;
|
|
||||||
uniswapDayData.txCount = factory.txCount;
|
|
||||||
return db.saveUniswapDayData(dbTx, uniswapDayData, block);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePoolDayData = async (db: Database, dbTx: QueryRunner, event: { contractAddress: string, block: Block }): Promise<PoolDayData> => {
|
|
||||||
const { contractAddress, block } = event;
|
|
||||||
const dayID = Math.floor(block.timestamp / 86400);
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
|
|
||||||
const dayPoolID = utils.hexlify(contractAddress)
|
|
||||||
.concat('-')
|
|
||||||
.concat(dayID.toString());
|
|
||||||
|
|
||||||
const pool = await db.getPool(dbTx, { id: utils.hexlify(contractAddress), blockHash: block.hash });
|
|
||||||
assert(pool);
|
|
||||||
|
|
||||||
let poolDayData = await db.getPoolDayData(dbTx, { id: dayPoolID, blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!poolDayData) {
|
|
||||||
poolDayData = new PoolDayData();
|
|
||||||
poolDayData.id = dayPoolID;
|
|
||||||
poolDayData.date = dayStartTimestamp;
|
|
||||||
poolDayData.pool = pool;
|
|
||||||
poolDayData.open = pool.token0Price;
|
|
||||||
poolDayData.high = pool.token0Price;
|
|
||||||
poolDayData.low = pool.token0Price;
|
|
||||||
poolDayData.close = pool.token0Price;
|
|
||||||
poolDayData = await db.savePoolDayData(dbTx, poolDayData, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Number(pool.token0Price) > Number(poolDayData.high)) {
|
|
||||||
poolDayData.high = pool.token0Price;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Number(pool.token0Price) < Number(poolDayData.low)) {
|
|
||||||
poolDayData.low = pool.token0Price;
|
|
||||||
}
|
|
||||||
|
|
||||||
poolDayData.liquidity = pool.liquidity;
|
|
||||||
poolDayData.sqrtPrice = pool.sqrtPrice;
|
|
||||||
poolDayData.feeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128;
|
|
||||||
poolDayData.feeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128;
|
|
||||||
poolDayData.token0Price = pool.token0Price;
|
|
||||||
poolDayData.token1Price = pool.token1Price;
|
|
||||||
poolDayData.tick = pool.tick;
|
|
||||||
poolDayData.tvlUSD = pool.totalValueLockedUSD;
|
|
||||||
poolDayData.txCount = BigInt(BigNumber.from(poolDayData.txCount).add(1).toHexString());
|
|
||||||
poolDayData = await db.savePoolDayData(dbTx, poolDayData, block);
|
|
||||||
|
|
||||||
return poolDayData;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePoolHourData = async (db: Database, dbTx: QueryRunner, event: { contractAddress: string, block: Block }): Promise<PoolHourData> => {
|
|
||||||
const { contractAddress, block } = event;
|
|
||||||
const hourIndex = Math.floor(block.timestamp / 3600); // Get unique hour within unix history.
|
|
||||||
const hourStartUnix = hourIndex * 3600; // Want the rounded effect.
|
|
||||||
|
|
||||||
const hourPoolID = utils.hexlify(contractAddress)
|
|
||||||
.concat('-')
|
|
||||||
.concat(hourIndex.toString());
|
|
||||||
|
|
||||||
const pool = await db.getPool(dbTx, { id: utils.hexlify(contractAddress), blockHash: block.hash });
|
|
||||||
assert(pool);
|
|
||||||
|
|
||||||
let poolHourData = await db.getPoolHourData(dbTx, { id: hourPoolID, blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!poolHourData) {
|
|
||||||
poolHourData = new PoolHourData();
|
|
||||||
poolHourData.id = hourPoolID;
|
|
||||||
poolHourData.periodStartUnix = hourStartUnix;
|
|
||||||
poolHourData.pool = pool;
|
|
||||||
poolHourData.open = pool.token0Price;
|
|
||||||
poolHourData.high = pool.token0Price;
|
|
||||||
poolHourData.low = pool.token0Price;
|
|
||||||
poolHourData.close = pool.token0Price;
|
|
||||||
poolHourData = await db.savePoolHourData(dbTx, poolHourData, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Number(pool.token0Price) > Number(poolHourData.high)) {
|
|
||||||
poolHourData.high = pool.token0Price;
|
|
||||||
}
|
|
||||||
if (Number(pool.token0Price) < Number(poolHourData.low)) {
|
|
||||||
poolHourData.low = pool.token0Price;
|
|
||||||
}
|
|
||||||
|
|
||||||
poolHourData.liquidity = pool.liquidity;
|
|
||||||
poolHourData.sqrtPrice = pool.sqrtPrice;
|
|
||||||
poolHourData.token0Price = pool.token0Price;
|
|
||||||
poolHourData.token1Price = pool.token1Price;
|
|
||||||
poolHourData.feeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128;
|
|
||||||
poolHourData.feeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128;
|
|
||||||
poolHourData.close = pool.token0Price;
|
|
||||||
poolHourData.tick = pool.tick;
|
|
||||||
poolHourData.tvlUSD = pool.totalValueLockedUSD;
|
|
||||||
poolHourData.txCount = BigInt(BigNumber.from(poolHourData.txCount).add(1).toHexString());
|
|
||||||
poolHourData = await db.savePoolHourData(dbTx, poolHourData, block);
|
|
||||||
|
|
||||||
return poolHourData;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateTokenDayData = async (db: Database, dbTx: QueryRunner, token: Token, event: { block: Block }): Promise<TokenDayData> => {
|
|
||||||
const { block } = event;
|
|
||||||
const bundle = await db.getBundle(dbTx, { id: '1', blockHash: block.hash });
|
|
||||||
assert(bundle);
|
|
||||||
const dayID = Math.floor(block.timestamp / 86400);
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
|
|
||||||
const tokenDayID = token.id
|
|
||||||
.concat('-')
|
|
||||||
.concat(dayID.toString());
|
|
||||||
|
|
||||||
const tokenPrice = token.derivedETH.times(bundle.ethPriceUSD);
|
|
||||||
|
|
||||||
let tokenDayData = await db.getTokenDayData(dbTx, { id: tokenDayID, blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!tokenDayData) {
|
|
||||||
tokenDayData = new TokenDayData();
|
|
||||||
tokenDayData.id = tokenDayID;
|
|
||||||
tokenDayData.date = dayStartTimestamp;
|
|
||||||
tokenDayData.token = token;
|
|
||||||
tokenDayData.open = tokenPrice;
|
|
||||||
tokenDayData.high = tokenPrice;
|
|
||||||
tokenDayData.low = tokenPrice;
|
|
||||||
tokenDayData.close = tokenPrice;
|
|
||||||
tokenDayData.priceUSD = token.derivedETH.times(bundle.ethPriceUSD);
|
|
||||||
tokenDayData.totalValueLocked = token.totalValueLocked;
|
|
||||||
tokenDayData.totalValueLockedUSD = token.totalValueLockedUSD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenPrice.gt(tokenDayData.high)) {
|
|
||||||
tokenDayData.high = tokenPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenPrice.lt(tokenDayData.low)) {
|
|
||||||
tokenDayData.low = tokenPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenDayData.close = tokenPrice;
|
|
||||||
tokenDayData.priceUSD = token.derivedETH.times(bundle.ethPriceUSD);
|
|
||||||
tokenDayData.totalValueLocked = token.totalValueLocked;
|
|
||||||
tokenDayData.totalValueLockedUSD = token.totalValueLockedUSD;
|
|
||||||
return db.saveTokenDayData(dbTx, tokenDayData, block);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateTokenHourData = async (db: Database, dbTx: QueryRunner, token: Token, event: { block: Block }): Promise<TokenHourData> => {
|
|
||||||
const { block } = event;
|
|
||||||
const bundle = await db.getBundle(dbTx, { id: '1', blockHash: block.hash });
|
|
||||||
assert(bundle);
|
|
||||||
const hourIndex = Math.floor(block.timestamp / 3600); // Get unique hour within unix history.
|
|
||||||
const hourStartUnix = hourIndex * 3600; // Want the rounded effect.
|
|
||||||
|
|
||||||
const tokenHourID = token.id
|
|
||||||
.concat('-')
|
|
||||||
.concat(hourIndex.toString());
|
|
||||||
|
|
||||||
const tokenPrice = token.derivedETH.times(bundle.ethPriceUSD);
|
|
||||||
|
|
||||||
let tokenHourData = await db.getTokenHourData(dbTx, { id: tokenHourID, blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!tokenHourData) {
|
|
||||||
tokenHourData = new TokenHourData();
|
|
||||||
tokenHourData.id = tokenHourID;
|
|
||||||
tokenHourData.periodStartUnix = hourStartUnix;
|
|
||||||
tokenHourData.token = token;
|
|
||||||
tokenHourData.open = tokenPrice;
|
|
||||||
tokenHourData.high = tokenPrice;
|
|
||||||
tokenHourData.low = tokenPrice;
|
|
||||||
tokenHourData.close = tokenPrice;
|
|
||||||
tokenHourData.priceUSD = tokenPrice;
|
|
||||||
tokenHourData.totalValueLocked = token.totalValueLocked;
|
|
||||||
tokenHourData.totalValueLockedUSD = token.totalValueLockedUSD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenPrice.gt(tokenHourData.high)) {
|
|
||||||
tokenHourData.high = tokenPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenPrice.lt(tokenHourData.low)) {
|
|
||||||
tokenHourData.low = tokenPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenHourData.close = tokenPrice;
|
|
||||||
tokenHourData.priceUSD = tokenPrice;
|
|
||||||
tokenHourData.totalValueLocked = token.totalValueLocked;
|
|
||||||
tokenHourData.totalValueLockedUSD = token.totalValueLockedUSD;
|
|
||||||
return db.saveTokenHourData(dbTx, tokenHourData, block);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateTickDayData = async (db: Database, dbTx: QueryRunner, tick: Tick, event: { block: Block }): Promise<TickDayData> => {
|
|
||||||
const { block } = event;
|
|
||||||
const timestamp = block.timestamp;
|
|
||||||
const dayID = Math.floor(timestamp / 86400);
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
|
|
||||||
const tickDayDataID = tick.id
|
|
||||||
.concat('-')
|
|
||||||
.concat(dayID.toString());
|
|
||||||
|
|
||||||
let tickDayData = await db.getTickDayData(dbTx, { id: tickDayDataID, blockHash: block.hash });
|
|
||||||
|
|
||||||
if (!tickDayData) {
|
|
||||||
tickDayData = new TickDayData();
|
|
||||||
tickDayData.id = tickDayDataID;
|
|
||||||
tickDayData.date = dayStartTimestamp;
|
|
||||||
tickDayData.pool = tick.pool;
|
|
||||||
tickDayData.tick = tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
tickDayData.liquidityGross = tick.liquidityGross;
|
|
||||||
tickDayData.liquidityNet = tick.liquidityNet;
|
|
||||||
|
|
||||||
return db.saveTickDayData(dbTx, tickDayData, block);
|
|
||||||
};
|
|
@ -1,190 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import { BigNumber } from 'ethers';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
import { GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { exponentToBigDecimal, safeDiv } from '.';
|
|
||||||
import { Database } from '../database';
|
|
||||||
import { Token } from '../entity/Token';
|
|
||||||
import { Block } from '../events';
|
|
||||||
|
|
||||||
// TODO: Move constants to config.
|
|
||||||
const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
|
||||||
|
|
||||||
const USDC_WETH_03_POOL = '0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8';
|
|
||||||
|
|
||||||
// Token where amounts should contribute to tracked volume and liquidity.
|
|
||||||
// Usually tokens that many tokens are paired with.
|
|
||||||
// TODO: Load whitelisted tokens from config.
|
|
||||||
export const WHITELIST_TOKENS: string[] = [
|
|
||||||
WETH_ADDRESS, // WETH
|
|
||||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
|
||||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
|
||||||
'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
|
|
||||||
'0x0000000000085d4780b73119b644ae5ecd22b376', // TUSD
|
|
||||||
'0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', // WBTC
|
|
||||||
'0x5d3a536e4d6dbd6114cc1ead35777bab948e3643', // cDAI
|
|
||||||
'0x39aa39c021dfbae8fac545936693ac917d5e7563', // cUSDC
|
|
||||||
'0x86fadb80d8d2cff3c3680819e4da99c10232ba0f', // EBASE
|
|
||||||
'0x57ab1ec28d129707052df4df418d58a2d46d5f51', // sUSD
|
|
||||||
'0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', // MKR
|
|
||||||
'0xc00e94cb662c3520282e6f5717214004a7f26888', // COMP
|
|
||||||
'0x514910771af9ca656af840dff83e8264ecf986ca', // LINK
|
|
||||||
'0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f', // SNX
|
|
||||||
'0x0bc529c00c6401aef6d220be8c6ea1667f6ad93e', // YFI
|
|
||||||
'0x111111111117dc0aa78b770fa6a738034120c302', // 1INCH
|
|
||||||
'0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8', // yCurv
|
|
||||||
'0x956f47f50a910163d8bf957cf5846d573e7f87ca', // FEI
|
|
||||||
'0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', // MATIC
|
|
||||||
'0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9' // AAVE
|
|
||||||
];
|
|
||||||
|
|
||||||
const STABLE_COINS: string[] = [
|
|
||||||
'0x6b175474e89094c44da98b954eedeac495271d0f',
|
|
||||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
||||||
'0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
||||||
'0x0000000000085d4780b73119b644ae5ecd22b376',
|
|
||||||
'0x956f47f50a910163d8bf957cf5846d573e7f87ca',
|
|
||||||
'0x4dd28568d05f09b02220b09c2cb307bfd837cb95'
|
|
||||||
];
|
|
||||||
|
|
||||||
const MINIMUM_ETH_LOCKED = new GraphDecimal(52);
|
|
||||||
const Q192 = 2 ** 192;
|
|
||||||
|
|
||||||
// Constants used in demo.
|
|
||||||
const ETH_PRICE_IN_USD = '3200.00';
|
|
||||||
|
|
||||||
export const sqrtPriceX96ToTokenPrices = (sqrtPriceX96: bigint, token0: Token, token1: Token): GraphDecimal[] => {
|
|
||||||
const num = new GraphDecimal((sqrtPriceX96 * sqrtPriceX96).toString());
|
|
||||||
const denom = new GraphDecimal(Q192.toString());
|
|
||||||
|
|
||||||
const price1 = num
|
|
||||||
.div(denom)
|
|
||||||
.times(exponentToBigDecimal(token0.decimals))
|
|
||||||
.div(exponentToBigDecimal(token1.decimals));
|
|
||||||
|
|
||||||
const price0 = safeDiv(new GraphDecimal('1'), price1);
|
|
||||||
|
|
||||||
return [price0, price1];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getEthPriceInUSD = async (db: Database, dbTx: QueryRunner, block: Block, isDemo: boolean): Promise<GraphDecimal> => {
|
|
||||||
if (isDemo) {
|
|
||||||
// For demo purpose in local development.
|
|
||||||
const ethPriceInUSD = new GraphDecimal(ETH_PRICE_IN_USD);
|
|
||||||
return ethPriceInUSD;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch eth prices for each stablecoin.
|
|
||||||
const usdcPool = await db.getPool(dbTx, { id: USDC_WETH_03_POOL, blockHash: block.hash }); // DAI is token0.
|
|
||||||
|
|
||||||
if (usdcPool) {
|
|
||||||
return usdcPool.token0Price;
|
|
||||||
} else {
|
|
||||||
return new GraphDecimal(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search through graph to find derived Eth per token.
|
|
||||||
* @todo update to be derived ETH (add stablecoin estimates)
|
|
||||||
**/
|
|
||||||
export const findEthPerToken = async (db: Database, dbTx: QueryRunner, token: Token, isDemo: boolean): Promise<GraphDecimal> => {
|
|
||||||
if (token.id === WETH_ADDRESS || isDemo) {
|
|
||||||
return new GraphDecimal(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const whiteList = token.whitelistPools;
|
|
||||||
// For now just take USD from pool with greatest TVL.
|
|
||||||
// Need to update this to actually detect best rate based on liquidity distribution.
|
|
||||||
let largestLiquidityETH = new GraphDecimal(0);
|
|
||||||
let priceSoFar = new GraphDecimal(0);
|
|
||||||
const bundle = await db.getBundle(dbTx, { id: '1' });
|
|
||||||
assert(bundle);
|
|
||||||
|
|
||||||
// hardcoded fix for incorrect rates
|
|
||||||
// if whitelist includes token - get the safe price
|
|
||||||
if (STABLE_COINS.includes(token.id)) {
|
|
||||||
priceSoFar = safeDiv(new GraphDecimal(1), bundle.ethPriceUSD);
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < whiteList.length; ++i) {
|
|
||||||
const poolAddress = whiteList[i].id;
|
|
||||||
const pool = await db.getPool(dbTx, { id: poolAddress });
|
|
||||||
assert(pool);
|
|
||||||
|
|
||||||
if (BigNumber.from(pool.liquidity).gt(0)) {
|
|
||||||
if (pool.token0.id === token.id) {
|
|
||||||
// whitelist token is token1
|
|
||||||
const token1 = pool.token1;
|
|
||||||
|
|
||||||
// get the derived ETH in pool
|
|
||||||
const ethLocked = pool.totalValueLockedToken1.times(token1.derivedETH);
|
|
||||||
|
|
||||||
if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) {
|
|
||||||
largestLiquidityETH = ethLocked;
|
|
||||||
// token1 per our token * Eth per token1
|
|
||||||
priceSoFar = pool.token1Price.times(token1.derivedETH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pool.token1.id === token.id) {
|
|
||||||
const token0 = pool.token0;
|
|
||||||
// Get the derived ETH in pool.
|
|
||||||
const ethLocked = pool.totalValueLockedToken0.times(token0.derivedETH);
|
|
||||||
|
|
||||||
if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) {
|
|
||||||
largestLiquidityETH = ethLocked;
|
|
||||||
// token0 per our token * ETH per token0
|
|
||||||
priceSoFar = pool.token0Price.times(token0.derivedETH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return priceSoFar; // If nothing was found return 0.
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts tokens and amounts, return tracked amount based on token whitelist.
|
|
||||||
* If one token on whitelist, return amount in that token converted to USD * 2.
|
|
||||||
* If both are, return sum of two amounts.
|
|
||||||
* If neither is, return 0.
|
|
||||||
*/
|
|
||||||
export const getTrackedAmountUSD = async (
|
|
||||||
db: Database,
|
|
||||||
dbTx: QueryRunner,
|
|
||||||
tokenAmount0: GraphDecimal,
|
|
||||||
token0: Token,
|
|
||||||
tokenAmount1: GraphDecimal,
|
|
||||||
token1: Token,
|
|
||||||
isDemo: boolean
|
|
||||||
): Promise<GraphDecimal> => {
|
|
||||||
const bundle = await db.getBundle(dbTx, { id: '1' });
|
|
||||||
assert(bundle);
|
|
||||||
const price0USD = token0.derivedETH.times(bundle.ethPriceUSD);
|
|
||||||
const price1USD = token1.derivedETH.times(bundle.ethPriceUSD);
|
|
||||||
|
|
||||||
// Both are whitelist tokens, return sum of both amounts.
|
|
||||||
// Use demo mode
|
|
||||||
if ((WHITELIST_TOKENS.includes(token0.id) && WHITELIST_TOKENS.includes(token1.id)) || isDemo) {
|
|
||||||
return tokenAmount0.times(price0USD).plus(tokenAmount1.times(price1USD));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take double value of the whitelisted token amount.
|
|
||||||
if (WHITELIST_TOKENS.includes(token0.id) && !WHITELIST_TOKENS.includes(token1.id)) {
|
|
||||||
return tokenAmount0.times(price0USD).times(new GraphDecimal('2'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take double value of the whitelisted token amount.
|
|
||||||
if (!WHITELIST_TOKENS.includes(token0.id) && WHITELIST_TOKENS.includes(token1.id)) {
|
|
||||||
return tokenAmount1.times(price1USD).times(new GraphDecimal('2'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Neither token is on white list, tracked amount is 0.
|
|
||||||
return new GraphDecimal(0);
|
|
||||||
};
|
|
@ -1,46 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
import { GraphDecimal } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Pool } from '../entity/Pool';
|
|
||||||
import { Database } from '../database';
|
|
||||||
import { bigDecimalExponated, safeDiv } from '.';
|
|
||||||
import { Tick } from '../entity/Tick';
|
|
||||||
import { Block } from '../events';
|
|
||||||
|
|
||||||
export const createTick = async (db: Database, dbTx: QueryRunner, tickId: string, tickIdx: bigint, pool: Pool, block: Block): Promise<Tick> => {
|
|
||||||
const tick = new Tick();
|
|
||||||
tick.id = tickId;
|
|
||||||
tick.tickIdx = tickIdx;
|
|
||||||
tick.pool = pool;
|
|
||||||
tick.poolAddress = pool.id;
|
|
||||||
|
|
||||||
// 1.0001^tick is token1/token0.
|
|
||||||
const price0 = bigDecimalExponated(new GraphDecimal('1.0001'), tickIdx);
|
|
||||||
|
|
||||||
tick.price0 = price0;
|
|
||||||
tick.price1 = safeDiv(new GraphDecimal(1), price0);
|
|
||||||
|
|
||||||
return db.saveTick(dbTx, tick, block);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const feeTierToTickSpacing = (feeTier: bigint): bigint => {
|
|
||||||
if (feeTier === BigInt(10000)) {
|
|
||||||
return BigInt(200);
|
|
||||||
}
|
|
||||||
if (feeTier === BigInt(3000)) {
|
|
||||||
return BigInt(60);
|
|
||||||
}
|
|
||||||
if (feeTier === BigInt(500)) {
|
|
||||||
return BigInt(10);
|
|
||||||
}
|
|
||||||
if (feeTier === BigInt(100)) {
|
|
||||||
return BigInt(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Error('Unexpected fee tier');
|
|
||||||
};
|
|
@ -1,221 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { expect } from 'chai';
|
|
||||||
import { ethers } from 'ethers';
|
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import { OrderDirection, GraphDecimal } from '@vulcanize/util';
|
|
||||||
import { insertNDummyBlocks } from '@vulcanize/util/test';
|
|
||||||
|
|
||||||
import { Database } from '../src/database';
|
|
||||||
import { Block } from '../src/events';
|
|
||||||
import { Token } from '../src/entity/Token';
|
|
||||||
import { Client } from '../src/client';
|
|
||||||
|
|
||||||
export const checkUniswapDayData = async (client: Client): Promise<void> => {
|
|
||||||
// Checked values: date, tvlUSD.
|
|
||||||
// Unchecked values: volumeUSD.
|
|
||||||
|
|
||||||
// Get the latest UniswapDayData.
|
|
||||||
const uniswapDayDatas = await client.getUniswapDayDatas({}, 0, 1, 'date', OrderDirection.desc);
|
|
||||||
expect(uniswapDayDatas).to.not.be.empty;
|
|
||||||
|
|
||||||
const id: string = uniswapDayDatas[0].id;
|
|
||||||
const dayID = Number(id);
|
|
||||||
const date = uniswapDayDatas[0].date;
|
|
||||||
const tvlUSD = uniswapDayDatas[0].tvlUSD;
|
|
||||||
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
const factories = await client.getFactories(1);
|
|
||||||
const totalValueLockedUSD: string = factories[0].totalValueLockedUSD;
|
|
||||||
|
|
||||||
expect(date).to.be.equal(dayStartTimestamp);
|
|
||||||
expect(tvlUSD).to.be.equal(totalValueLockedUSD);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkPoolDayData = async (client: Client, poolAddress: string): Promise<void> => {
|
|
||||||
// Checked values: id, date, tvlUSD.
|
|
||||||
// Unchecked values: volumeUSD.
|
|
||||||
|
|
||||||
// Get the latest PoolDayData.
|
|
||||||
const poolDayDatas = await client.getPoolDayDatas({ pool: poolAddress }, 0, 1, 'date', OrderDirection.desc);
|
|
||||||
expect(poolDayDatas).to.not.be.empty;
|
|
||||||
|
|
||||||
const dayPoolID: string = poolDayDatas[0].id;
|
|
||||||
const poolID: string = dayPoolID.split('-')[0];
|
|
||||||
const dayID = Number(dayPoolID.split('-')[1]);
|
|
||||||
const date = poolDayDatas[0].date;
|
|
||||||
const tvlUSD = poolDayDatas[0].tvlUSD;
|
|
||||||
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
const poolData = await client.getPoolById(poolAddress);
|
|
||||||
const totalValueLockedUSD: string = poolData.pool.totalValueLockedUSD;
|
|
||||||
|
|
||||||
expect(poolID).to.be.equal(poolAddress);
|
|
||||||
expect(date).to.be.equal(dayStartTimestamp);
|
|
||||||
expect(tvlUSD).to.be.equal(totalValueLockedUSD);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkTokenDayData = async (client: Client, tokenAddress: string): Promise<void> => {
|
|
||||||
// Checked values: id, date, totalValueLockedUSD.
|
|
||||||
// Unchecked values: volumeUSD.
|
|
||||||
|
|
||||||
// Get the latest TokenDayData.
|
|
||||||
const tokenDayDatas = await client.getTokenDayDatas({ token: tokenAddress }, 0, 1, 'date', OrderDirection.desc);
|
|
||||||
expect(tokenDayDatas).to.not.be.empty;
|
|
||||||
|
|
||||||
const tokenDayID: string = tokenDayDatas[0].id;
|
|
||||||
const tokenID: string = tokenDayID.split('-')[0];
|
|
||||||
const dayID = Number(tokenDayID.split('-')[1]);
|
|
||||||
const date = tokenDayDatas[0].date;
|
|
||||||
const tvlUSD = tokenDayDatas[0].totalValueLockedUSD;
|
|
||||||
|
|
||||||
const dayStartTimestamp = dayID * 86400;
|
|
||||||
const tokenData = await client.getToken(tokenAddress);
|
|
||||||
const totalValueLockedUSD: string = tokenData.token.totalValueLockedUSD;
|
|
||||||
|
|
||||||
expect(tokenID).to.be.equal(tokenAddress);
|
|
||||||
expect(date).to.be.equal(dayStartTimestamp);
|
|
||||||
expect(tvlUSD).to.be.equal(totalValueLockedUSD);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkTokenHourData = async (client: Client, tokenAddress: string): Promise<void> => {
|
|
||||||
// Checked values: id, periodStartUnix, low, high, open, close.
|
|
||||||
// Unchecked values:
|
|
||||||
|
|
||||||
// Get the latest TokenHourData.
|
|
||||||
const tokenHourDatas = await client.getTokenHourDatas({ token: tokenAddress }, 0, 1, 'periodStartUnix', OrderDirection.desc);
|
|
||||||
expect(tokenHourDatas).to.not.be.empty;
|
|
||||||
|
|
||||||
const tokenHourID: string = tokenHourDatas[0].id;
|
|
||||||
const tokenID: string = tokenHourID.split('-')[0];
|
|
||||||
const hourIndex = Number(tokenHourID.split('-')[1]);
|
|
||||||
const periodStartUnix = tokenHourDatas[0].periodStartUnix;
|
|
||||||
const low = tokenHourDatas[0].low;
|
|
||||||
const high = tokenHourDatas[0].high;
|
|
||||||
const open = tokenHourDatas[0].open;
|
|
||||||
const close = tokenHourDatas[0].close;
|
|
||||||
|
|
||||||
const hourStartUnix = hourIndex * 3600;
|
|
||||||
const tokenData = await client.getToken(tokenAddress);
|
|
||||||
const bundles = await client.getBundles(1);
|
|
||||||
const tokenPrice = new GraphDecimal(tokenData.token.derivedETH).times(bundles[0].ethPriceUSD);
|
|
||||||
|
|
||||||
expect(tokenID).to.be.equal(tokenAddress);
|
|
||||||
expect(periodStartUnix).to.be.equal(hourStartUnix);
|
|
||||||
expect(low).to.be.equal(tokenPrice.toString());
|
|
||||||
expect(high).to.be.equal(tokenPrice.toString());
|
|
||||||
expect(open).to.be.equal(tokenPrice.toString());
|
|
||||||
expect(close).to.be.equal(tokenPrice.toString());
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchTransaction = async (client: Client): Promise<{transaction: any}> => {
|
|
||||||
// Get the latest Transaction.
|
|
||||||
// Get only the latest mint, burn and swap entity in the transaction.
|
|
||||||
const transactions = await client.getTransactions(
|
|
||||||
1,
|
|
||||||
{
|
|
||||||
orderBy: 'timestamp',
|
|
||||||
mintOrderBy: 'timestamp',
|
|
||||||
burnOrderBy: 'timestamp',
|
|
||||||
swapOrderBy: 'timestamp'
|
|
||||||
},
|
|
||||||
OrderDirection.desc
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(transactions).to.not.be.empty;
|
|
||||||
const transaction = transactions[0];
|
|
||||||
|
|
||||||
expect(transaction.mints).to.be.an.instanceOf(Array);
|
|
||||||
expect(transaction.burns).to.be.an.instanceOf(Array);
|
|
||||||
expect(transaction.swaps).to.be.an.instanceOf(Array);
|
|
||||||
|
|
||||||
return transaction;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createTestBlockTree = async (db: Database): Promise<Block[][]> => {
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 21|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 15|
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// 8 Blocks 3 Blocks
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// | 11| | 11| | 11|
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 9 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 7 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
|
|
||||||
const blocks: Block[][] = [];
|
|
||||||
|
|
||||||
const firstSeg = await insertNDummyBlocks(db, 9);
|
|
||||||
const secondSeg = await insertNDummyBlocks(db, 2, _.last(firstSeg));
|
|
||||||
const thirdSeg = await insertNDummyBlocks(db, 1, _.last(firstSeg));
|
|
||||||
const fourthSeg = await insertNDummyBlocks(db, 11, _.last(thirdSeg));
|
|
||||||
const fifthSeg = await insertNDummyBlocks(db, 5, _.last(thirdSeg));
|
|
||||||
|
|
||||||
blocks.push(firstSeg);
|
|
||||||
blocks.push(secondSeg);
|
|
||||||
blocks.push(thirdSeg);
|
|
||||||
blocks.push(fourthSeg);
|
|
||||||
blocks.push(fifthSeg);
|
|
||||||
|
|
||||||
return blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const insertDummyToken = async (db: Database, block: Block, token?: Token): Promise<Token> => {
|
|
||||||
// Insert a dummy Token entity at block.
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
const randomByte = ethers.utils.randomBytes(20);
|
|
||||||
const tokenAddress = ethers.utils.hexValue(randomByte);
|
|
||||||
|
|
||||||
token = new Token();
|
|
||||||
token.symbol = 'TEST';
|
|
||||||
token.name = 'TestToken';
|
|
||||||
token.id = tokenAddress;
|
|
||||||
token.totalSupply = BigInt(0);
|
|
||||||
token.decimals = BigInt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
|
|
||||||
try {
|
|
||||||
token = await db.saveToken(dbTx, token, block);
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
return token;
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
|
||||||
|
|
||||||
/* Basic Options */
|
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
|
||||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
|
||||||
"lib": [ "ES5", "ES6", "ES2020" ], /* Specify library files to be included in the compilation. */
|
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
|
||||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
|
||||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
||||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
||||||
"outDir": "dist", /* Redirect output structure to the directory. */
|
|
||||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
||||||
// "composite": true, /* Enable project compilation */
|
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
|
||||||
// "noEmit": true, /* Do not emit outputs. */
|
|
||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
|
||||||
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
|
||||||
|
|
||||||
/* Strict Type-Checking Options */
|
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
|
||||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
|
||||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
|
||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
|
||||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
|
||||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
|
||||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
|
||||||
|
|
||||||
/* Additional Checks */
|
|
||||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
||||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
||||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
|
||||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
|
||||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
|
||||||
|
|
||||||
/* Module Resolution Options */
|
|
||||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
|
||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
||||||
"typeRoots": [
|
|
||||||
"./src/types"
|
|
||||||
], /* List of folders to include type definitions from. */
|
|
||||||
// "types": [], /* Type declaration files to be included in compilation. */
|
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
|
||||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
||||||
|
|
||||||
/* Source Map Options */
|
|
||||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
|
||||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
||||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
||||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
||||||
|
|
||||||
/* Experimental Options */
|
|
||||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
||||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
||||||
|
|
||||||
/* Advanced Options */
|
|
||||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
|
||||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
|
||||||
"resolveJsonModule": true /* Enabling the option allows importing JSON, and validating the types in that JSON file. */
|
|
||||||
},
|
|
||||||
"include": ["src"],
|
|
||||||
"exclude": ["dist", "src/**/*.test.ts"]
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
# Don't lint node_modules.
|
|
||||||
node_modules
|
|
||||||
|
|
||||||
# Don't lint build output.
|
|
||||||
dist
|
|
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"semistandard",
|
|
||||||
"plugin:@typescript-eslint/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 12,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"allowArgumentsExplicitlyTypedAsAny": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.test.ts", "test/*.ts"],
|
|
||||||
"rules": {
|
|
||||||
"no-unused-expressions": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
10
packages/uni-watcher/.gitignore
vendored
10
packages/uni-watcher/.gitignore
vendored
@ -1,10 +0,0 @@
|
|||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
node_modules/
|
|
||||||
build/
|
|
||||||
tmp/
|
|
||||||
temp/
|
|
||||||
|
|
||||||
#Hardhat files
|
|
||||||
cache
|
|
||||||
artifacts
|
|
@ -1,4 +0,0 @@
|
|||||||
timeout: '70000'
|
|
||||||
bail: true
|
|
||||||
exit: true # TODO: Find out why the program doesn't exit on its own.
|
|
||||||
require: 'ts-node/register'
|
|
@ -1,133 +0,0 @@
|
|||||||
# Uniswap Watcher
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
Create a postgres12 database for the job queue:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo su - postgres
|
|
||||||
createdb uni-watcher-job-queue
|
|
||||||
```
|
|
||||||
|
|
||||||
Enable the `pgcrypto` extension on the job queue database (https://github.com/timgit/pg-boss/blob/master/docs/usage.md#intro).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
postgres@tesla:~$ psql -U postgres -h localhost uni-watcher-job-queue
|
|
||||||
Password for user postgres:
|
|
||||||
psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1))
|
|
||||||
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
|
|
||||||
Type "help" for help.
|
|
||||||
|
|
||||||
uni-watcher-job-queue=# CREATE EXTENSION pgcrypto;
|
|
||||||
CREATE EXTENSION
|
|
||||||
uni-watcher-job-queue=# exit
|
|
||||||
```
|
|
||||||
|
|
||||||
Create a postgres12 database for the address watcher:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo su - postgres
|
|
||||||
createdb uni-watcher
|
|
||||||
```
|
|
||||||
|
|
||||||
Update `environments/local.toml` with database connection settings for both the databases.
|
|
||||||
|
|
||||||
|
|
||||||
## Run
|
|
||||||
|
|
||||||
Build files:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn build
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn server
|
|
||||||
|
|
||||||
# For development.
|
|
||||||
$ yarn server:dev
|
|
||||||
|
|
||||||
# For specifying config file.
|
|
||||||
$ yarn server -f environments/local.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
Start the job runner:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn job-runner
|
|
||||||
|
|
||||||
# For development.
|
|
||||||
$ yarn job-runner:dev
|
|
||||||
|
|
||||||
# For specifying config file.
|
|
||||||
$ yarn job-runner -f environments/local.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
Start watching the factory contract:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn watch:contract --address 0xContractAddress --kind <contract-kind> --startingBlock <start-block>
|
|
||||||
|
|
||||||
# For specifying config file.
|
|
||||||
$ yarn watch:contract -f environments/local.toml --address 0xContractAddress --kind <contract-kind> --startingBlock <start-block>
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn watch:contract --address 0xfE0034a874c2707c23F91D7409E9036F5e08ac34 --kind factory --startingBlock 100
|
|
||||||
```
|
|
||||||
|
|
||||||
Start watching the NonFungiblePositionManager contract:
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn watch:contract --address 0xB171168C0df9457Ff3E3D795aE25Bf4f41e2FFE3 --kind nfpm --startingBlock 100
|
|
||||||
```
|
|
||||||
|
|
||||||
To fill a block range:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn fill --startBlock <from-block> --endBlock <to-block>
|
|
||||||
|
|
||||||
# For specifying config file.
|
|
||||||
$ yarn fill -f environments/local.toml --startBlock <from-block> --endBlock <to-block>
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn fill --startBlock 1000 --endBlock 2000
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test
|
|
||||||
|
|
||||||
To test the watchers locally:
|
|
||||||
|
|
||||||
* Deploy the Uniswap contracts
|
|
||||||
* Watch the Factory and NonFungiblePositionManager contracts
|
|
||||||
* Send transactions to trigger events
|
|
||||||
|
|
||||||
See https://github.com/vulcanize/uniswap-v3-periphery/blob/watcher-ts/demo.md for instructions.
|
|
||||||
|
|
||||||
### Smoke test
|
|
||||||
|
|
||||||
To run a smoke test:
|
|
||||||
|
|
||||||
* Start the server and the job-runner.
|
|
||||||
* To build contracts for tests, run the command below in root of the repository:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn build:contracts
|
|
||||||
```
|
|
||||||
|
|
||||||
* Run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ yarn smoke-test
|
|
||||||
```
|
|
@ -1,34 +0,0 @@
|
|||||||
[server]
|
|
||||||
host = "127.0.0.1"
|
|
||||||
port = 3003
|
|
||||||
|
|
||||||
[metrics]
|
|
||||||
host = "127.0.0.1"
|
|
||||||
port = 9000
|
|
||||||
|
|
||||||
[database]
|
|
||||||
type = "postgres"
|
|
||||||
host = "localhost"
|
|
||||||
port = 5432
|
|
||||||
database = "uni-watcher"
|
|
||||||
username = "postgres"
|
|
||||||
password = "postgres"
|
|
||||||
synchronize = true
|
|
||||||
logging = false
|
|
||||||
|
|
||||||
[upstream]
|
|
||||||
[upstream.ethServer]
|
|
||||||
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
|
|
||||||
rpcProviderEndpoint = "http://127.0.0.1:8081"
|
|
||||||
blockDelayInMilliSecs = 2000
|
|
||||||
|
|
||||||
[upstream.cache]
|
|
||||||
name = "requests"
|
|
||||||
enabled = false
|
|
||||||
deleteOnStart = false
|
|
||||||
|
|
||||||
[jobQueue]
|
|
||||||
dbConnectionString = "postgres://postgres:postgres@localhost/uni-watcher-job-queue"
|
|
||||||
maxCompletionLagInSecs = 300
|
|
||||||
jobDelayInMilliSecs = 100
|
|
||||||
eventsInBatch = 50
|
|
@ -1,30 +0,0 @@
|
|||||||
[server]
|
|
||||||
host = "127.0.0.1"
|
|
||||||
port = 3003
|
|
||||||
|
|
||||||
[database]
|
|
||||||
type = "postgres"
|
|
||||||
host = "localhost"
|
|
||||||
port = 5432
|
|
||||||
database = "uni-watcher"
|
|
||||||
username = "postgres"
|
|
||||||
password = "postgres"
|
|
||||||
synchronize = true
|
|
||||||
logging = false
|
|
||||||
|
|
||||||
[upstream]
|
|
||||||
[upstream.ethServer]
|
|
||||||
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
|
|
||||||
rpcProviderEndpoint = "http://127.0.0.1:8545"
|
|
||||||
blockDelayInMilliSecs = 2000
|
|
||||||
|
|
||||||
[upstream.cache]
|
|
||||||
name = "requests"
|
|
||||||
enabled = false
|
|
||||||
deleteOnStart = false
|
|
||||||
|
|
||||||
[jobQueue]
|
|
||||||
dbConnectionString = "postgres://postgres:postgres@localhost/uni-watcher-job-queue"
|
|
||||||
maxCompletionLagInSecs = 300
|
|
||||||
jobDelayInMilliSecs = 100
|
|
||||||
eventsInBatch = 50
|
|
@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@vulcanize/uni-watcher",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "Uniswap v3 Watcher",
|
|
||||||
"private": true,
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"scripts": {
|
|
||||||
"lint": "eslint .",
|
|
||||||
"test": "mocha src/**/*.test.ts",
|
|
||||||
"test:init": "ts-node test/init.ts",
|
|
||||||
"test:chain-pruning": "mocha src/chain-pruning.test.ts",
|
|
||||||
"build": "tsc",
|
|
||||||
"server": "DEBUG=vulcanize:* node --enable-source-maps dist/server.js",
|
|
||||||
"server:prof": "DEBUG=vulcanize:* node --require pprof --enable-source-maps dist/server.js",
|
|
||||||
"server:dev": "DEBUG=vulcanize:* nodemon --watch src src/server.ts",
|
|
||||||
"server:mock": "MOCK=1 nodemon src/server.ts ",
|
|
||||||
"job-runner": "DEBUG=vulcanize:* node --enable-source-maps dist/job-runner.js",
|
|
||||||
"job-runner:prof": "DEBUG=vulcanize:* node --require pprof --enable-source-maps dist/job-runner.js",
|
|
||||||
"job-runner:dev": "DEBUG=vulcanize:* nodemon --watch src src/job-runner.ts",
|
|
||||||
"smoke-test": "yarn test:init && mocha src/smoke.test.ts",
|
|
||||||
"fill": "DEBUG=vulcanize:* node --enable-source-maps dist/fill.js",
|
|
||||||
"fill:prof": "DEBUG=vulcanize:* node --require pprof --enable-source-maps dist/fill.js",
|
|
||||||
"fill:dev": "DEBUG=vulcanize:* ts-node src/fill.ts",
|
|
||||||
"watch:contract": "node --enable-source-maps dist/cli/watch-contract.js",
|
|
||||||
"watch:contract:dev": "ts-node src/cli/watch-contract.ts",
|
|
||||||
"reset": "DEBUG=vulcanize:* node --enable-source-maps dist/cli/reset.js",
|
|
||||||
"reset:dev": "DEBUG=vulcanize:* ts-node src/cli/reset.ts"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/vulcanize/watcher-ts.git"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "AGPL-3.0",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/vulcanize/watcher-ts/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/vulcanize/watcher-ts#readme",
|
|
||||||
"dependencies": {
|
|
||||||
"@apollo/client": "^3.3.19",
|
|
||||||
"@types/lodash": "^4.14.168",
|
|
||||||
"@vulcanize/cache": "^0.1.0",
|
|
||||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
|
||||||
"@vulcanize/solidity-mapper": "^0.1.0",
|
|
||||||
"@vulcanize/util": "^0.1.0",
|
|
||||||
"apollo-server-express": "^2.25.0",
|
|
||||||
"apollo-type-bigint": "^0.1.3",
|
|
||||||
"debug": "^4.3.1",
|
|
||||||
"ethers": "^5.4.4",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"graphql": "^15.5.0",
|
|
||||||
"graphql-import-node": "^0.0.4",
|
|
||||||
"graphql-request": "^3.4.0",
|
|
||||||
"json-bigint": "^1.0.0",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"reflect-metadata": "^0.1.13",
|
|
||||||
"typeorm": "^0.2.32",
|
|
||||||
"yargs": "^17.0.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/chai": "^4.2.18",
|
|
||||||
"@types/express": "^4.17.11",
|
|
||||||
"@types/json-bigint": "^1.0.0",
|
|
||||||
"@types/mocha": "^8.2.2",
|
|
||||||
"@types/yargs": "^17.0.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
|
||||||
"@typescript-eslint/parser": "^4.25.0",
|
|
||||||
"@uniswap/v3-core": "1.0.0",
|
|
||||||
"chai": "^4.3.4",
|
|
||||||
"eslint": "^7.27.0",
|
|
||||||
"eslint-config-semistandard": "^15.0.1",
|
|
||||||
"eslint-config-standard": "^16.0.3",
|
|
||||||
"eslint-plugin-import": "^2.23.3",
|
|
||||||
"eslint-plugin-node": "^11.1.0",
|
|
||||||
"eslint-plugin-promise": "^5.1.0",
|
|
||||||
"eslint-plugin-standard": "^5.0.0",
|
|
||||||
"mocha": "^8.4.0",
|
|
||||||
"nodemon": "^2.0.7",
|
|
||||||
"pprof": "^3.2.0",
|
|
||||||
"ts-node": "^10.0.0",
|
|
||||||
"typescript": "^4.3.2"
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,366 +0,0 @@
|
|||||||
{
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "FeeAmountEnabled",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "oldOwner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "newOwner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "OwnerChanged",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "pool",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "PoolCreated",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "tokenA",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "tokenB",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "createPool",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "pool",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "enableFeeAmount",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "feeAmountTickSpacing",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "getPool",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "owner",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "parameters",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "factory",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "fee",
|
|
||||||
"type": "uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setOwner",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageLayout": {
|
|
||||||
"storage": [
|
|
||||||
{
|
|
||||||
"astId": 2840,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "parameters",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "0",
|
|
||||||
"type": "t_struct(Parameters)2836_storage"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 56,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "owner",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "3",
|
|
||||||
"type": "t_address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 62,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "feeAmountTickSpacing",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "4",
|
|
||||||
"type": "t_mapping(t_uint24,t_int24)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 72,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "getPool",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "5",
|
|
||||||
"type": "t_mapping(t_address,t_mapping(t_address,t_mapping(t_uint24,t_address)))"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"types": {
|
|
||||||
"t_address": {
|
|
||||||
"encoding": "inplace",
|
|
||||||
"label": "address",
|
|
||||||
"numberOfBytes": "20"
|
|
||||||
},
|
|
||||||
"t_int24": {
|
|
||||||
"encoding": "inplace",
|
|
||||||
"label": "int24",
|
|
||||||
"numberOfBytes": "3"
|
|
||||||
},
|
|
||||||
"t_mapping(t_address,t_mapping(t_address,t_mapping(t_uint24,t_address)))": {
|
|
||||||
"encoding": "mapping",
|
|
||||||
"key": "t_address",
|
|
||||||
"label": "mapping(address => mapping(address => mapping(uint24 => address)))",
|
|
||||||
"numberOfBytes": "32",
|
|
||||||
"value": "t_mapping(t_address,t_mapping(t_uint24,t_address))"
|
|
||||||
},
|
|
||||||
"t_mapping(t_address,t_mapping(t_uint24,t_address))": {
|
|
||||||
"encoding": "mapping",
|
|
||||||
"key": "t_address",
|
|
||||||
"label": "mapping(address => mapping(uint24 => address))",
|
|
||||||
"numberOfBytes": "32",
|
|
||||||
"value": "t_mapping(t_uint24,t_address)"
|
|
||||||
},
|
|
||||||
"t_mapping(t_uint24,t_address)": {
|
|
||||||
"encoding": "mapping",
|
|
||||||
"key": "t_uint24",
|
|
||||||
"label": "mapping(uint24 => address)",
|
|
||||||
"numberOfBytes": "32",
|
|
||||||
"value": "t_address"
|
|
||||||
},
|
|
||||||
"t_mapping(t_uint24,t_int24)": {
|
|
||||||
"encoding": "mapping",
|
|
||||||
"key": "t_uint24",
|
|
||||||
"label": "mapping(uint24 => int24)",
|
|
||||||
"numberOfBytes": "32",
|
|
||||||
"value": "t_int24"
|
|
||||||
},
|
|
||||||
"t_struct(Parameters)2836_storage": {
|
|
||||||
"encoding": "inplace",
|
|
||||||
"label": "struct UniswapV3PoolDeployer.Parameters",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"astId": 2827,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "factory",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "0",
|
|
||||||
"type": "t_address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 2829,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "token0",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "1",
|
|
||||||
"type": "t_address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 2831,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "token1",
|
|
||||||
"offset": 0,
|
|
||||||
"slot": "2",
|
|
||||||
"type": "t_address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 2833,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "fee",
|
|
||||||
"offset": 20,
|
|
||||||
"slot": "2",
|
|
||||||
"type": "t_uint24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"astId": 2835,
|
|
||||||
"contract": "contracts/UniswapV3Factory.sol:UniswapV3Factory",
|
|
||||||
"label": "tickSpacing",
|
|
||||||
"offset": 23,
|
|
||||||
"slot": "2",
|
|
||||||
"type": "t_int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"numberOfBytes": "96"
|
|
||||||
},
|
|
||||||
"t_uint24": {
|
|
||||||
"encoding": "inplace",
|
|
||||||
"label": "uint24",
|
|
||||||
"numberOfBytes": "3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,988 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Burn",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Collect",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "CollectProtocol",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "paid0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "paid1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Flash",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNextOld",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNextNew",
|
|
||||||
"type": "uint16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "IncreaseObservationCardinalityNext",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Initialize",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Mint",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0Old",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1Old",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0New",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1New",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "SetFeeProtocol",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "sender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "liquidity",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Swap",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "burn",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "collect",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1Requested",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "collectProtocol",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "factory",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "fee",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint24",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "feeGrowthGlobal0X128",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "feeGrowthGlobal1X128",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "flash",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNext",
|
|
||||||
"type": "uint16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "increaseObservationCardinalityNext",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "initialize",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "liquidity",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "maxLiquidityPerTick",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "mint",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "index",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "observations",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "blockTimestamp",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulative",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityCumulativeX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "initialized",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint32[]",
|
|
||||||
"name": "secondsAgos",
|
|
||||||
"type": "uint32[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "observe",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int56[]",
|
|
||||||
"name": "tickCumulatives",
|
|
||||||
"type": "int56[]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160[]",
|
|
||||||
"name": "secondsPerLiquidityCumulativeX128s",
|
|
||||||
"type": "uint160[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "bytes32",
|
|
||||||
"name": "key",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "positions",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "_liquidity",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthInside0LastX128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthInside1LastX128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "tokensOwed0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "tokensOwed1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "protocolFees",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "token0",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "token1",
|
|
||||||
"type": "uint128"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol0",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol1",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setFeeProtocol",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "slot0",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationIndex",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinality",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint16",
|
|
||||||
"name": "observationCardinalityNext",
|
|
||||||
"type": "uint16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint8",
|
|
||||||
"name": "feeProtocol",
|
|
||||||
"type": "uint8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "unlocked",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickLower",
|
|
||||||
"type": "int24"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tickUpper",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "snapshotCumulativesInside",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulativeInside",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityInsideX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "secondsInside",
|
|
||||||
"type": "uint32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "recipient",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "zeroForOne",
|
|
||||||
"type": "bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amountSpecified",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "sqrtPriceLimitX96",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bytes",
|
|
||||||
"name": "data",
|
|
||||||
"type": "bytes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "swap",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount0",
|
|
||||||
"type": "int256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int256",
|
|
||||||
"name": "amount1",
|
|
||||||
"type": "int256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int16",
|
|
||||||
"name": "wordPosition",
|
|
||||||
"type": "int16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "tickBitmap",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "tickSpacing",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "int24",
|
|
||||||
"name": "tick",
|
|
||||||
"type": "int24"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "ticks",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint128",
|
|
||||||
"name": "liquidityGross",
|
|
||||||
"type": "uint128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int128",
|
|
||||||
"name": "liquidityNet",
|
|
||||||
"type": "int128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthOutside0X128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "feeGrowthOutside1X128",
|
|
||||||
"type": "uint256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "int56",
|
|
||||||
"name": "tickCumulativeOutside",
|
|
||||||
"type": "int56"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint160",
|
|
||||||
"name": "secondsPerLiquidityOutsideX128",
|
|
||||||
"type": "uint160"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint32",
|
|
||||||
"name": "secondsOutside",
|
|
||||||
"type": "uint32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "bool",
|
|
||||||
"name": "initialized",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "token0",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "token1",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,415 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { expect, assert } from 'chai';
|
|
||||||
import { AssertionError } from 'assert';
|
|
||||||
import 'mocha';
|
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import { getConfig, getCustomProvider, JobQueue, JobRunner, JOB_KIND_PRUNE } from '@vulcanize/util';
|
|
||||||
import { getCache } from '@vulcanize/cache';
|
|
||||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
|
||||||
import { insertNDummyBlocks, removeEntities } from '@vulcanize/util/test';
|
|
||||||
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { Database } from './database';
|
|
||||||
import { BlockProgress } from './entity/BlockProgress';
|
|
||||||
import { SyncStatus } from './entity/SyncStatus';
|
|
||||||
|
|
||||||
const CONFIG_FILE = './environments/test.toml';
|
|
||||||
|
|
||||||
describe('chain pruning', () => {
|
|
||||||
let db: Database;
|
|
||||||
let indexer: Indexer;
|
|
||||||
let jobRunner: JobRunner;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
// Get config.
|
|
||||||
const config = await getConfig(CONFIG_FILE);
|
|
||||||
|
|
||||||
const { upstream, database: dbConfig, jobQueue: jobQueueConfig } = config;
|
|
||||||
|
|
||||||
assert(dbConfig, 'Missing database config');
|
|
||||||
|
|
||||||
// Initialize database.
|
|
||||||
db = new Database(dbConfig);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
// Check if database is empty.
|
|
||||||
const isBlockProgressEmpty = await db.isEntityEmpty(BlockProgress);
|
|
||||||
const isSyncStatusEmpty = await db.isEntityEmpty(SyncStatus);
|
|
||||||
const isDbEmptyBeforeTest = isBlockProgressEmpty && isSyncStatusEmpty;
|
|
||||||
|
|
||||||
assert(isDbEmptyBeforeTest, 'Abort: Database not empty.');
|
|
||||||
|
|
||||||
// Create an Indexer object.
|
|
||||||
assert(upstream, 'Missing upstream config');
|
|
||||||
const { ethServer: { gqlApiEndpoint, rpcProviderEndpoint }, cache: cacheConfig } = upstream;
|
|
||||||
assert(gqlApiEndpoint, 'Missing upstream ethServer.gqlApiEndpoint');
|
|
||||||
|
|
||||||
const cache = await getCache(cacheConfig);
|
|
||||||
const ethClient = new EthClient({
|
|
||||||
gqlEndpoint: gqlApiEndpoint,
|
|
||||||
cache
|
|
||||||
});
|
|
||||||
|
|
||||||
const ethProvider = getCustomProvider(rpcProviderEndpoint);
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
|
|
||||||
indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue);
|
|
||||||
assert(indexer, 'Could not create indexer object.');
|
|
||||||
|
|
||||||
jobRunner = new JobRunner(jobQueueConfig, indexer, jobQueue);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await removeEntities(db, BlockProgress);
|
|
||||||
await removeEntities(db, SyncStatus);
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async () => {
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// head----->| 20|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 19|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 12 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 6 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 5 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 4 | ------> Block Height to be pruned
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 2 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// tail----->| 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should prune a block in chain without branches', async () => {
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
await insertNDummyBlocks(db, 20);
|
|
||||||
const pruneBlockHeight = 4;
|
|
||||||
|
|
||||||
// Should return only one block as there are no branches.
|
|
||||||
const blocks = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocks).to.have.lengthOf(1);
|
|
||||||
|
|
||||||
const job = { data: { kind: JOB_KIND_PRUNE, pruneBlockHeight } };
|
|
||||||
await jobRunner.processBlock(job);
|
|
||||||
|
|
||||||
// Only one canonical (not pruned) block should exist at the pruned height.
|
|
||||||
const blocksAfterPruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksAfterPruning).to.have.lengthOf(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// | 20|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 19|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 13 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 5 | | 5 |
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +---+ +----
|
|
||||||
// | 4 | | 4 | | 4 | ----> Block Height to be pruned
|
|
||||||
// +---+ +---+ +---+
|
|
||||||
// \ | /
|
|
||||||
// \ | /
|
|
||||||
// +---+ +---+
|
|
||||||
// | 3 | | 3 |
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 2 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should prune block at height with branches', async () => {
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
const firstSeg = await insertNDummyBlocks(db, 2);
|
|
||||||
const secondSeg = await insertNDummyBlocks(db, 2, _.last(firstSeg));
|
|
||||||
expect(_.last(secondSeg).number).to.equal(4);
|
|
||||||
const thirdSeg = await insertNDummyBlocks(db, 1, _.last(firstSeg));
|
|
||||||
const fourthSeg = await insertNDummyBlocks(db, 2, _.last(thirdSeg));
|
|
||||||
expect(_.last(fourthSeg).number).to.equal(5);
|
|
||||||
const fifthSeg = await insertNDummyBlocks(db, 17, _.last(thirdSeg));
|
|
||||||
expect(_.last(fifthSeg).number).to.equal(20);
|
|
||||||
|
|
||||||
const expectedCanonicalBlock = fifthSeg[0];
|
|
||||||
const expectedPrunedBlocks = [secondSeg[1], fourthSeg[0]];
|
|
||||||
|
|
||||||
const pruneBlockHeight = 4;
|
|
||||||
|
|
||||||
// Should return multiple blocks that are not pruned.
|
|
||||||
const blocksBeforePruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksBeforePruning).to.have.lengthOf(3);
|
|
||||||
|
|
||||||
const job = { data: { kind: JOB_KIND_PRUNE, pruneBlockHeight } };
|
|
||||||
await jobRunner.processBlock(job);
|
|
||||||
|
|
||||||
// Only one canonical (not pruned) block should exist at the pruned height.
|
|
||||||
const blocksAfterPruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksAfterPruning).to.have.lengthOf(1);
|
|
||||||
|
|
||||||
// Assert that correct block is canonical.
|
|
||||||
expect(blocksAfterPruning[0].blockHash).to.equal(expectedCanonicalBlock.hash);
|
|
||||||
|
|
||||||
// Assert that correct blocks are pruned.
|
|
||||||
const prunedBlocks = await indexer.getBlocksAtHeight(pruneBlockHeight, true);
|
|
||||||
expect(prunedBlocks).to.have.lengthOf(2);
|
|
||||||
const prunedBlockHashes = prunedBlocks.map(({ blockHash }) => blockHash);
|
|
||||||
const expectedPrunedBlockHashes = expectedPrunedBlocks.map(({ hash }) => hash);
|
|
||||||
expect(prunedBlockHashes).to.have.members(expectedPrunedBlockHashes);
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+ +---+
|
|
||||||
// | 20| | 20|
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +----
|
|
||||||
// | 19| | 19|
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +----
|
|
||||||
// | 18|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 17|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 11 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 5 | | 5 |
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +----
|
|
||||||
// | 4 | | 4 | ----> Block Height to be pruned
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +----
|
|
||||||
// | 3 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 2 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should prune block with multiple branches at chain head', async () => {
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
const firstSeg = await insertNDummyBlocks(db, 3);
|
|
||||||
const secondSeg = await insertNDummyBlocks(db, 2, _.last(firstSeg));
|
|
||||||
expect(_.last(secondSeg).number).to.equal(5);
|
|
||||||
const thirdSeg = await insertNDummyBlocks(db, 15, _.last(firstSeg));
|
|
||||||
const fourthSeg = await insertNDummyBlocks(db, 2, _.last(thirdSeg));
|
|
||||||
expect(_.last(fourthSeg).number).to.equal(20);
|
|
||||||
const fifthSeg = await insertNDummyBlocks(db, 2, _.last(thirdSeg));
|
|
||||||
expect(_.last(fifthSeg).number).to.equal(20);
|
|
||||||
|
|
||||||
const expectedCanonicalBlock = thirdSeg[0];
|
|
||||||
const expectedPrunedBlock = secondSeg[0];
|
|
||||||
|
|
||||||
const pruneBlockHeight = 4;
|
|
||||||
|
|
||||||
// Should return multiple blocks that are not pruned.
|
|
||||||
const blocksBeforePruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksBeforePruning).to.have.lengthOf(2);
|
|
||||||
|
|
||||||
const job = { data: { kind: JOB_KIND_PRUNE, pruneBlockHeight } };
|
|
||||||
await jobRunner.processBlock(job);
|
|
||||||
|
|
||||||
// Only one canonical (not pruned) block should exist at the pruned height.
|
|
||||||
const blocksAfterPruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksAfterPruning).to.have.lengthOf(1);
|
|
||||||
expect(blocksAfterPruning[0].blockHash).to.equal(expectedCanonicalBlock.hash);
|
|
||||||
|
|
||||||
// Assert that correct blocks are pruned.
|
|
||||||
const prunedBlocks = await indexer.getBlocksAtHeight(pruneBlockHeight, true);
|
|
||||||
expect(prunedBlocks).to.have.lengthOf(1);
|
|
||||||
expect(prunedBlocks[0].blockHash).to.equal(expectedPrunedBlock.hash);
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// | 21| ----> Latest Indexed
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 20|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 15 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 4 | | 4 |
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 3 | | 3 | ----> Block Height to be pruned
|
|
||||||
// +---+ +---+
|
|
||||||
// \ |
|
|
||||||
// \ |
|
|
||||||
// +---+
|
|
||||||
// | 2 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should prune block at depth greater than max reorg depth from latest indexed block', async () => {
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
const firstSeg = await insertNDummyBlocks(db, 2);
|
|
||||||
const secondSeg = await insertNDummyBlocks(db, 2, _.last(firstSeg));
|
|
||||||
expect(_.last(secondSeg).number).to.equal(4);
|
|
||||||
const thirdSeg = await insertNDummyBlocks(db, 19, _.last(firstSeg));
|
|
||||||
expect(_.last(thirdSeg).number).to.equal(21);
|
|
||||||
|
|
||||||
const expectedCanonicalBlock = thirdSeg[0];
|
|
||||||
const expectedPrunedBlock = secondSeg[0];
|
|
||||||
|
|
||||||
const pruneBlockHeight = 3;
|
|
||||||
|
|
||||||
// Should return multiple blocks that are not pruned.
|
|
||||||
const blocksBeforePruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksBeforePruning).to.have.lengthOf(2);
|
|
||||||
|
|
||||||
const job = { data: { kind: JOB_KIND_PRUNE, pruneBlockHeight } };
|
|
||||||
await jobRunner.processBlock(job);
|
|
||||||
|
|
||||||
// Only one canonical (not pruned) block should exist at the pruned height.
|
|
||||||
const blocksAfterPruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksAfterPruning).to.have.lengthOf(1);
|
|
||||||
expect(blocksAfterPruning[0].blockHash).to.equal(expectedCanonicalBlock.hash);
|
|
||||||
|
|
||||||
// Assert that correct blocks are pruned.
|
|
||||||
const prunedBlocks = await indexer.getBlocksAtHeight(pruneBlockHeight, true);
|
|
||||||
expect(prunedBlocks).to.have.lengthOf(1);
|
|
||||||
expect(prunedBlocks[0].blockHash).to.equal(expectedPrunedBlock.hash);
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// +---+
|
|
||||||
// | 20|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 19|
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 8 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+ +---+
|
|
||||||
// | 10| | 10|
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+ +----
|
|
||||||
// | 9 | | 9 | ----> Block Height to be pruned
|
|
||||||
// +---+ +---+
|
|
||||||
// | /
|
|
||||||
// | /
|
|
||||||
// +---+
|
|
||||||
// | 8 |
|
|
||||||
// +---+
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// 6 Blocks
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// +---+
|
|
||||||
// | 1 |
|
|
||||||
// +---+
|
|
||||||
//
|
|
||||||
it('should avoid pruning block in frothy region', async () => {
|
|
||||||
// Create BlockProgress test data.
|
|
||||||
const firstSeg = await insertNDummyBlocks(db, 8);
|
|
||||||
const secondSeg = await insertNDummyBlocks(db, 2, _.last(firstSeg));
|
|
||||||
expect(_.last(secondSeg).number).to.equal(10);
|
|
||||||
const thirdSeg = await insertNDummyBlocks(db, 12, _.last(firstSeg));
|
|
||||||
expect(_.last(thirdSeg).number).to.equal(20);
|
|
||||||
const pruneBlockHeight = 9;
|
|
||||||
|
|
||||||
// Should return multiple blocks that are not pruned.
|
|
||||||
const blocksBeforePruning = await indexer.getBlocksAtHeight(pruneBlockHeight, false);
|
|
||||||
expect(blocksBeforePruning).to.have.lengthOf(2);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const job = { data: { kind: JOB_KIND_PRUNE, pruneBlockHeight } };
|
|
||||||
await jobRunner.processBlock(job);
|
|
||||||
expect.fail('Job Runner should throw error for pruning at frothy region');
|
|
||||||
} catch (error) {
|
|
||||||
expect(error).to.be.instanceof(AssertionError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// No blocks should be pruned at frothy region.
|
|
||||||
const blocksAfterPruning = await indexer.getBlocksAtHeight(pruneBlockHeight, true);
|
|
||||||
expect(blocksAfterPruning).to.have.lengthOf(0);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
import { getConfig, resetJobs } from '@vulcanize/util';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:reset-job-queue');
|
|
||||||
|
|
||||||
export const command = 'job-queue';
|
|
||||||
|
|
||||||
export const desc = 'Reset job queue';
|
|
||||||
|
|
||||||
export const builder = {};
|
|
||||||
|
|
||||||
export const handler = async (argv: any): Promise<void> => {
|
|
||||||
const config = await getConfig(argv.configFile);
|
|
||||||
await resetJobs(config);
|
|
||||||
|
|
||||||
log('Job queue reset successfully');
|
|
||||||
};
|
|
@ -1,77 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import debug from 'debug';
|
|
||||||
import { MoreThan } from 'typeorm';
|
|
||||||
import assert from 'assert';
|
|
||||||
|
|
||||||
import { getConfig, initClients, resetJobs, JobQueue } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Database } from '../../database';
|
|
||||||
import { Indexer } from '../../indexer';
|
|
||||||
import { BlockProgress } from '../../entity/BlockProgress';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:reset-state');
|
|
||||||
|
|
||||||
export const command = 'state';
|
|
||||||
|
|
||||||
export const desc = 'Reset state to block number';
|
|
||||||
|
|
||||||
export const builder = {
|
|
||||||
blockNumber: {
|
|
||||||
type: 'number'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const handler = async (argv: any): Promise<void> => {
|
|
||||||
const config = await getConfig(argv.configFile);
|
|
||||||
await resetJobs(config);
|
|
||||||
const { ethClient, ethProvider } = await initClients(config);
|
|
||||||
|
|
||||||
// Initialize database.
|
|
||||||
const db = new Database(config.database);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
assert(config.jobQueue, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = config.jobQueue;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue);
|
|
||||||
|
|
||||||
const syncStatus = await indexer.getSyncStatus();
|
|
||||||
assert(syncStatus, 'Missing syncStatus');
|
|
||||||
|
|
||||||
const blockProgresses = await indexer.getBlocksAtHeight(argv.blockNumber, false);
|
|
||||||
assert(blockProgresses.length, `No blocks at specified block number ${argv.blockNumber}`);
|
|
||||||
assert(!blockProgresses.some(block => !block.isComplete), `Incomplete block at block number ${argv.blockNumber} with unprocessed events`);
|
|
||||||
const [blockProgress] = blockProgresses;
|
|
||||||
|
|
||||||
const dbTx = await db.createTransactionRunner();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await db.removeEntities(dbTx, BlockProgress, { blockNumber: MoreThan(blockProgress.blockNumber) });
|
|
||||||
|
|
||||||
if (syncStatus.latestIndexedBlockNumber > blockProgress.blockNumber) {
|
|
||||||
await indexer.updateSyncStatusIndexedBlock(blockProgress.blockHash, blockProgress.blockNumber, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncStatus.latestCanonicalBlockNumber > blockProgress.blockNumber) {
|
|
||||||
await indexer.updateSyncStatusCanonicalBlock(blockProgress.blockHash, blockProgress.blockNumber, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
await indexer.updateSyncStatusChainHead(blockProgress.blockHash, blockProgress.blockNumber, true);
|
|
||||||
|
|
||||||
dbTx.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await dbTx.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await dbTx.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
log('Reset state successfully');
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
import { getResetYargs } from '@vulcanize/util';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:reset');
|
|
||||||
|
|
||||||
const main = async () => {
|
|
||||||
return getResetYargs()
|
|
||||||
.commandDir('reset-cmds', { extensions: ['js', 'ts'], exclude: /([a-zA-Z0-9\s_\\.\-:])+(.d.ts)$/ })
|
|
||||||
.demandCommand(1)
|
|
||||||
.help()
|
|
||||||
.argv;
|
|
||||||
};
|
|
||||||
|
|
||||||
main().then(() => {
|
|
||||||
process.exit();
|
|
||||||
}).catch(err => {
|
|
||||||
log(err);
|
|
||||||
});
|
|
@ -1,75 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import yargs from 'yargs';
|
|
||||||
import 'reflect-metadata';
|
|
||||||
|
|
||||||
import { Config, DEFAULT_CONFIG_PATH, getConfig, initClients, JobQueue } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Database } from '../database';
|
|
||||||
import { Indexer } from '../indexer';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const argv = await yargs.parserConfiguration({
|
|
||||||
'parse-numbers': false
|
|
||||||
}).options({
|
|
||||||
configFile: {
|
|
||||||
alias: 'f',
|
|
||||||
type: 'string',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'configuration file path (toml)',
|
|
||||||
default: DEFAULT_CONFIG_PATH
|
|
||||||
},
|
|
||||||
address: {
|
|
||||||
type: 'string',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'Address of the deployed contract'
|
|
||||||
},
|
|
||||||
kind: {
|
|
||||||
type: 'string',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'Kind of contract (factory|pool|nfpm)'
|
|
||||||
},
|
|
||||||
checkpoint: {
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
describe: 'Turn checkpointing on'
|
|
||||||
},
|
|
||||||
startingBlock: {
|
|
||||||
type: 'number',
|
|
||||||
default: 1,
|
|
||||||
describe: 'Starting block'
|
|
||||||
}
|
|
||||||
}).argv;
|
|
||||||
|
|
||||||
const config: Config = await getConfig(argv.configFile);
|
|
||||||
const { database: dbConfig, jobQueue: jobQueueConfig } = config;
|
|
||||||
const { ethClient, ethProvider } = await initClients(config);
|
|
||||||
|
|
||||||
assert(dbConfig);
|
|
||||||
|
|
||||||
const db = new Database(dbConfig);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
assert(jobQueueConfig, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
await jobQueue.start();
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue);
|
|
||||||
await indexer.init();
|
|
||||||
|
|
||||||
await indexer.watchContract(argv.address, argv.kind, argv.checkpoint, argv.startingBlock);
|
|
||||||
|
|
||||||
await db.close();
|
|
||||||
await jobQueue.stop();
|
|
||||||
process.exit();
|
|
||||||
})();
|
|
@ -1,139 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client/core';
|
|
||||||
import { GraphQLClient, GraphQLConfig } from '@vulcanize/ipld-eth-client';
|
|
||||||
|
|
||||||
import {
|
|
||||||
queryGetPool,
|
|
||||||
queryPoolIdToPoolKey,
|
|
||||||
queryPosition,
|
|
||||||
queryEvents,
|
|
||||||
subscribeEvents,
|
|
||||||
queryGetContract,
|
|
||||||
queryEventsInRange,
|
|
||||||
queryCallGetPool,
|
|
||||||
queryPositions
|
|
||||||
} from './queries';
|
|
||||||
|
|
||||||
export class Client {
|
|
||||||
_config: GraphQLConfig;
|
|
||||||
_client: GraphQLClient;
|
|
||||||
|
|
||||||
constructor (config: GraphQLConfig) {
|
|
||||||
this._config = config;
|
|
||||||
|
|
||||||
this._client = new GraphQLClient(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
async watchEvents (onNext: (value: any) => void): Promise<ZenObservable.Subscription> {
|
|
||||||
return this._client.subscribe(
|
|
||||||
gql(subscribeEvents),
|
|
||||||
({ data }) => {
|
|
||||||
onNext(data.onEvent);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEvents (blockHash: string, contract?: string): Promise<any> {
|
|
||||||
const { events } = await this._client.query(
|
|
||||||
gql(queryEvents),
|
|
||||||
{
|
|
||||||
blockHash,
|
|
||||||
contract
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPosition (blockHash: string, tokenId: bigint): Promise<any> {
|
|
||||||
const { position } = await this._client.query(
|
|
||||||
gql(queryPosition),
|
|
||||||
{
|
|
||||||
blockHash,
|
|
||||||
tokenId: tokenId.toString()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
async poolIdToPoolKey (blockHash: string, poolId: bigint): Promise<any> {
|
|
||||||
const { poolIdToPoolKey } = await this._client.query(
|
|
||||||
gql(queryPoolIdToPoolKey),
|
|
||||||
{
|
|
||||||
blockHash,
|
|
||||||
poolId: poolId.toString()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return poolIdToPoolKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPool (blockHash: string, token0: string, token1: string, fee: bigint): Promise<any> {
|
|
||||||
const { getPool } = await this._client.query(
|
|
||||||
gql(queryGetPool),
|
|
||||||
{
|
|
||||||
blockHash,
|
|
||||||
token0,
|
|
||||||
token1,
|
|
||||||
fee: fee.toString()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return getPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
async callGetPool (blockHash: string, contractAddress: string, key0: string, key1: string, key2: number): Promise<any> {
|
|
||||||
const { callGetPool } = await this._client.query(
|
|
||||||
gql(queryCallGetPool),
|
|
||||||
{
|
|
||||||
blockHash,
|
|
||||||
contractAddress,
|
|
||||||
key0,
|
|
||||||
key1,
|
|
||||||
key2
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return callGetPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
async positions (blockHash: string, contractAddress: string, tokenId: bigint): Promise<any> {
|
|
||||||
const { positions } = await this._client.query(
|
|
||||||
gql(queryPositions),
|
|
||||||
{
|
|
||||||
blockHash,
|
|
||||||
contractAddress,
|
|
||||||
tokenId: tokenId.toString()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getContract (type: string): Promise<any> {
|
|
||||||
const { getContract } = await this._client.query(
|
|
||||||
gql(queryGetContract),
|
|
||||||
{
|
|
||||||
type
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return getContract;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEventsInRange (fromblockNumber: number, toBlockNumber: number): Promise<any> {
|
|
||||||
const { events } = await this._client.query(
|
|
||||||
gql(queryEventsInRange),
|
|
||||||
{
|
|
||||||
fromblockNumber,
|
|
||||||
toBlockNumber
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import { Connection, ConnectionOptions, DeepPartial, QueryRunner, FindConditions, FindManyOptions } from 'typeorm';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import { Database as BaseDatabase, DatabaseInterface, QueryOptions, Where } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Event } from './entity/Event';
|
|
||||||
import { Contract } from './entity/Contract';
|
|
||||||
import { BlockProgress } from './entity/BlockProgress';
|
|
||||||
import { SyncStatus } from './entity/SyncStatus';
|
|
||||||
|
|
||||||
export class Database implements DatabaseInterface {
|
|
||||||
_config: ConnectionOptions
|
|
||||||
_conn!: Connection
|
|
||||||
_baseDatabase: BaseDatabase
|
|
||||||
|
|
||||||
constructor (config: ConnectionOptions) {
|
|
||||||
assert(config);
|
|
||||||
|
|
||||||
this._config = {
|
|
||||||
...config,
|
|
||||||
entities: [path.join(__dirname, 'entity/*')]
|
|
||||||
};
|
|
||||||
|
|
||||||
this._baseDatabase = new BaseDatabase(this._config);
|
|
||||||
}
|
|
||||||
|
|
||||||
async init (): Promise<void> {
|
|
||||||
this._conn = await this._baseDatabase.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
async close (): Promise<void> {
|
|
||||||
return this._baseDatabase.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getLatestContract (kind: string): Promise<Contract | undefined> {
|
|
||||||
return this._conn.getRepository(Contract)
|
|
||||||
.createQueryBuilder('contract')
|
|
||||||
.where('kind = :kind', { kind })
|
|
||||||
.orderBy('id', 'DESC')
|
|
||||||
.getOne();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getContracts (): Promise<Contract[]> {
|
|
||||||
const repo = this._conn.getRepository(Contract);
|
|
||||||
|
|
||||||
return this._baseDatabase.getContracts(repo);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveContract (queryRunner: QueryRunner, address: string, kind: string, checkpoint: boolean, startingBlock: number): Promise<Contract> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Contract);
|
|
||||||
|
|
||||||
return this._baseDatabase.saveContract(repo, address, kind, checkpoint, startingBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
async createTransactionRunner (): Promise<QueryRunner> {
|
|
||||||
return this._baseDatabase.createTransactionRunner();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.getProcessedBlockCountForRange(repo, fromBlockNumber, toBlockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise<Array<Event>> {
|
|
||||||
const repo = this._conn.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.getEventsInRange(repo, fromBlockNumber, toBlockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveEventEntity (queryRunner: QueryRunner, entity: Event): Promise<Event> {
|
|
||||||
const repo = queryRunner.manager.getRepository(Event);
|
|
||||||
return this._baseDatabase.saveEventEntity(repo, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise<Event[]> {
|
|
||||||
const repo = this._conn.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.getBlockEvents(repo, blockHash, where, queryOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveEvents (queryRunner: QueryRunner, block: DeepPartial<BlockProgress>, events: DeepPartial<Event>[]): Promise<BlockProgress> {
|
|
||||||
const blockRepo = queryRunner.manager.getRepository(BlockProgress);
|
|
||||||
const eventRepo = queryRunner.manager.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.saveEvents(blockRepo, eventRepo, block, events);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateSyncStatusIndexedBlock(repo, blockHash, blockNumber, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSyncStatusCanonicalBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateSyncStatusCanonicalBlock(repo, blockHash, blockNumber, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSyncStatusChainHead (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSyncStatus (queryRunner: QueryRunner): Promise<SyncStatus | undefined> {
|
|
||||||
const repo = queryRunner.manager.getRepository(SyncStatus);
|
|
||||||
|
|
||||||
return this._baseDatabase.getSyncStatus(repo);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEvent (id: string): Promise<Event | undefined> {
|
|
||||||
const repo = this._conn.getRepository(Event);
|
|
||||||
|
|
||||||
return this._baseDatabase.getEvent(repo, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlocksAtHeight (height: number, isPruned: boolean): Promise<BlockProgress[]> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.getBlocksAtHeight(repo, height, isPruned);
|
|
||||||
}
|
|
||||||
|
|
||||||
async markBlocksAsPruned (queryRunner: QueryRunner, blocks: BlockProgress[]): Promise<void> {
|
|
||||||
const repo = queryRunner.manager.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.markBlocksAsPruned(repo, blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockProgress (blockHash: string): Promise<BlockProgress | undefined> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
return this._baseDatabase.getBlockProgress(repo, blockHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockProgressEntities (where: FindConditions<BlockProgress>, options: FindManyOptions<BlockProgress>): Promise<BlockProgress[]> {
|
|
||||||
const repo = this._conn.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.getBlockProgressEntities(repo, where, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateBlockProgress (queryRunner: QueryRunner, block: BlockProgress, lastProcessedEventIndex: number): Promise<BlockProgress> {
|
|
||||||
const repo = queryRunner.manager.getRepository(BlockProgress);
|
|
||||||
|
|
||||||
return this._baseDatabase.updateBlockProgress(repo, block, lastProcessedEventIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEntities<Entity> (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindConditions<Entity>): Promise<Entity[]> {
|
|
||||||
return this._baseDatabase.getEntities(queryRunner, entity, findConditions);
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeEntities<Entity> (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindManyOptions<Entity> | FindConditions<Entity>): Promise<void> {
|
|
||||||
return this._baseDatabase.removeEntities(queryRunner, entity, findConditions);
|
|
||||||
}
|
|
||||||
|
|
||||||
async isEntityEmpty<Entity> (entity: new () => Entity): Promise<boolean> {
|
|
||||||
return this._baseDatabase.isEntityEmpty(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAncestorAtDepth (blockHash: string, depth: number): Promise<string> {
|
|
||||||
return this._baseDatabase.getAncestorAtDepth(blockHash, depth);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn } from 'typeorm';
|
|
||||||
|
|
||||||
import { BlockProgressInterface } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
@Index(['blockHash'], { unique: true })
|
|
||||||
@Index(['blockNumber'])
|
|
||||||
@Index(['parentHash'])
|
|
||||||
export class BlockProgress implements BlockProgressInterface {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
@Column('varchar')
|
|
||||||
cid!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
blockHash!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66, nullable: true })
|
|
||||||
parentHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockNumber!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
blockTimestamp!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
numEvents!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
numProcessedEvents!: number;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
lastProcessedEventIndex!: number;
|
|
||||||
|
|
||||||
@Column('boolean')
|
|
||||||
isComplete!: boolean
|
|
||||||
|
|
||||||
@Column('boolean', { default: false })
|
|
||||||
isPruned!: boolean
|
|
||||||
|
|
||||||
@CreateDateColumn()
|
|
||||||
createdAt!: Date;
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';
|
|
||||||
|
|
||||||
export const KIND_FACTORY = 'factory';
|
|
||||||
export const KIND_POOL = 'pool';
|
|
||||||
export const KIND_NFPM = 'nfpm';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
@Index(['address'], { unique: true })
|
|
||||||
export class Contract {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
address!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 8 })
|
|
||||||
kind!: string;
|
|
||||||
|
|
||||||
@Column('boolean')
|
|
||||||
checkpoint!: boolean;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
startingBlock!: number;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, Index } from 'typeorm';
|
|
||||||
import { BlockProgress } from './BlockProgress';
|
|
||||||
|
|
||||||
export const UNKNOWN_EVENT_NAME = '__unknown__';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
// Index to query all events for a contract efficiently.
|
|
||||||
@Index(['contract'])
|
|
||||||
export class Event {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
@ManyToOne(() => BlockProgress, { onDelete: 'CASCADE' })
|
|
||||||
block!: BlockProgress;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
txHash!: string;
|
|
||||||
|
|
||||||
// Index of the log in the block.
|
|
||||||
@Column('integer')
|
|
||||||
index!: number;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 42 })
|
|
||||||
contract!: string;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 256 })
|
|
||||||
eventName!: string;
|
|
||||||
|
|
||||||
@Column('text')
|
|
||||||
eventInfo!: string;
|
|
||||||
|
|
||||||
@Column('text')
|
|
||||||
extraInfo!: string;
|
|
||||||
|
|
||||||
@Column('text')
|
|
||||||
proof!: string;
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
||||||
|
|
||||||
import { SyncStatusInterface } from '@vulcanize/util';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class SyncStatus implements SyncStatusInterface {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id!: number;
|
|
||||||
|
|
||||||
// Latest block hash and number from the chain itself.
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
chainHeadBlockHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
chainHeadBlockNumber!: number;
|
|
||||||
|
|
||||||
// Most recent block hash that's been indexed.
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
latestIndexedBlockHash!: string;
|
|
||||||
|
|
||||||
// Most recent block number that's been indexed.
|
|
||||||
@Column('integer')
|
|
||||||
latestIndexedBlockNumber!: number;
|
|
||||||
|
|
||||||
// Most recent block hash and number that we can consider as part
|
|
||||||
// of the canonical/finalized chain. Reorgs older than this block
|
|
||||||
// cannot be processed and processing will halt.
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
latestCanonicalBlockHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
latestCanonicalBlockNumber!: number;
|
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
|
||||||
initialIndexedBlockHash!: string;
|
|
||||||
|
|
||||||
@Column('integer')
|
|
||||||
initialIndexedBlockNumber!: number;
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import debug from 'debug';
|
|
||||||
import { PubSub } from 'apollo-server-express';
|
|
||||||
|
|
||||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
|
||||||
import {
|
|
||||||
JobQueue,
|
|
||||||
EventWatcher as BaseEventWatcher,
|
|
||||||
QUEUE_BLOCK_PROCESSING,
|
|
||||||
QUEUE_EVENT_PROCESSING,
|
|
||||||
EventWatcherInterface,
|
|
||||||
UpstreamConfig
|
|
||||||
} from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { Event, UNKNOWN_EVENT_NAME } from './entity/Event';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:events');
|
|
||||||
|
|
||||||
export const UniswapEvent = 'uniswap-event';
|
|
||||||
|
|
||||||
export class EventWatcher implements EventWatcherInterface {
|
|
||||||
_ethClient: EthClient
|
|
||||||
_indexer: Indexer
|
|
||||||
_subscription?: ZenObservable.Subscription
|
|
||||||
_pubsub: PubSub
|
|
||||||
_jobQueue: JobQueue
|
|
||||||
_baseEventWatcher: BaseEventWatcher
|
|
||||||
|
|
||||||
constructor (upstreamConfig: UpstreamConfig, ethClient: EthClient, indexer: Indexer, pubsub: PubSub, jobQueue: JobQueue) {
|
|
||||||
this._ethClient = ethClient;
|
|
||||||
this._indexer = indexer;
|
|
||||||
this._pubsub = pubsub;
|
|
||||||
this._jobQueue = jobQueue;
|
|
||||||
this._baseEventWatcher = new BaseEventWatcher(upstreamConfig, this._ethClient, this._indexer, this._pubsub, this._jobQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
getEventIterator (): AsyncIterator<any> {
|
|
||||||
return this._pubsub.asyncIterator([UniswapEvent]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockProgressEventIterator (): AsyncIterator<any> {
|
|
||||||
return this._baseEventWatcher.getBlockProgressEventIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
async start (): Promise<void> {
|
|
||||||
assert(!this._subscription, 'subscription already started');
|
|
||||||
|
|
||||||
await this.initBlockProcessingOnCompleteHandler();
|
|
||||||
await this.initEventProcessingOnCompleteHandler();
|
|
||||||
this._baseEventWatcher.startBlockProcessing();
|
|
||||||
}
|
|
||||||
|
|
||||||
async stop (): Promise<void> {
|
|
||||||
this._baseEventWatcher.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
async initBlockProcessingOnCompleteHandler (): Promise<void> {
|
|
||||||
this._jobQueue.onComplete(QUEUE_BLOCK_PROCESSING, async (job) => {
|
|
||||||
const { id, data: { failed } } = job;
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
log(`Job ${id} for queue ${QUEUE_BLOCK_PROCESSING} failed`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._baseEventWatcher.blockProcessingCompleteHandler(job);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async initEventProcessingOnCompleteHandler (): Promise<void> {
|
|
||||||
await this._jobQueue.onComplete(QUEUE_EVENT_PROCESSING, async (job) => {
|
|
||||||
const { id, data: { request, failed, state, createdOn } } = job;
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
log(`Job ${id} for queue ${QUEUE_EVENT_PROCESSING} failed`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dbEvents = await this._baseEventWatcher.eventProcessingCompleteHandler(job);
|
|
||||||
const timeElapsedInSeconds = (Date.now() - Date.parse(createdOn)) / 1000;
|
|
||||||
|
|
||||||
// Cannot publish individual event as they are processed together in a single job.
|
|
||||||
// TODO: Use a different pubsub to publish event from job-runner.
|
|
||||||
// https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
|
|
||||||
for (const dbEvent of dbEvents) {
|
|
||||||
log(`Job onComplete event ${dbEvent.id} publish ${!!request.data.publish}`);
|
|
||||||
|
|
||||||
if (!failed && state === 'completed' && request.data.publish) {
|
|
||||||
// Check for max acceptable lag time between request and sending results to live subscribers.
|
|
||||||
if (timeElapsedInSeconds <= this._jobQueue.maxCompletionLag) {
|
|
||||||
await this.publishUniswapEventToSubscribers(dbEvent, timeElapsedInSeconds);
|
|
||||||
} else {
|
|
||||||
log(`event ${dbEvent.id} is too old (${timeElapsedInSeconds}s), not broadcasting to live subscribers`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async publishUniswapEventToSubscribers (dbEvent: Event, timeElapsedInSeconds: number): Promise<void> {
|
|
||||||
if (dbEvent && dbEvent.eventName !== UNKNOWN_EVENT_NAME) {
|
|
||||||
const resultEvent = this._indexer.getResultEvent(dbEvent);
|
|
||||||
|
|
||||||
log(`pushing event to GQL subscribers (${timeElapsedInSeconds}s elapsed): ${resultEvent.event.__typename}`);
|
|
||||||
|
|
||||||
// Publishing the event here will result in pushing the payload to GQL subscribers for `onEvent`.
|
|
||||||
await this._pubsub.publish(UniswapEvent, {
|
|
||||||
onEvent: resultEvent
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
import assert from 'assert';
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import yargs from 'yargs';
|
|
||||||
import { hideBin } from 'yargs/helpers';
|
|
||||||
import debug from 'debug';
|
|
||||||
import { PubSub } from 'apollo-server-express';
|
|
||||||
|
|
||||||
import { getConfig, Config, fillBlocks, JobQueue, DEFAULT_CONFIG_PATH, initClients } from '@vulcanize/util';
|
|
||||||
|
|
||||||
import { Database } from './database';
|
|
||||||
import { Indexer } from './indexer';
|
|
||||||
import { EventWatcher } from './events';
|
|
||||||
|
|
||||||
const log = debug('vulcanize:server');
|
|
||||||
|
|
||||||
export const main = async (): Promise<any> => {
|
|
||||||
const argv = await yargs(hideBin(process.argv)).parserConfiguration({
|
|
||||||
'parse-numbers': false
|
|
||||||
}).options({
|
|
||||||
configFile: {
|
|
||||||
alias: 'f',
|
|
||||||
type: 'string',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'configuration file path (toml)',
|
|
||||||
default: DEFAULT_CONFIG_PATH
|
|
||||||
},
|
|
||||||
startBlock: {
|
|
||||||
type: 'number',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'Block number to start processing at'
|
|
||||||
},
|
|
||||||
endBlock: {
|
|
||||||
type: 'number',
|
|
||||||
require: true,
|
|
||||||
demandOption: true,
|
|
||||||
describe: 'Block number to stop processing at'
|
|
||||||
},
|
|
||||||
prefetch: {
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
describe: 'Block and events prefetch mode'
|
|
||||||
},
|
|
||||||
batchBlocks: {
|
|
||||||
type: 'number',
|
|
||||||
default: 10,
|
|
||||||
describe: 'Number of blocks prefetched in batch'
|
|
||||||
}
|
|
||||||
}).argv;
|
|
||||||
|
|
||||||
const config: Config = await getConfig(argv.configFile);
|
|
||||||
const { ethClient, ethProvider } = await initClients(config);
|
|
||||||
|
|
||||||
const db = new Database(config.database);
|
|
||||||
await db.init();
|
|
||||||
|
|
||||||
// Note: In-memory pubsub works fine for now, as each watcher is a single process anyway.
|
|
||||||
// Later: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
|
|
||||||
const pubsub = new PubSub();
|
|
||||||
|
|
||||||
const jobQueueConfig = config.jobQueue;
|
|
||||||
assert(jobQueueConfig, 'Missing job queue config');
|
|
||||||
|
|
||||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
|
||||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
|
||||||
|
|
||||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
|
||||||
await jobQueue.start();
|
|
||||||
|
|
||||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue);
|
|
||||||
await indexer.init();
|
|
||||||
|
|
||||||
const eventWatcher = new EventWatcher(config.upstream, ethClient, indexer, pubsub, jobQueue);
|
|
||||||
|
|
||||||
await fillBlocks(jobQueue, indexer, eventWatcher, config.upstream.ethServer.blockDelayInMilliSecs, argv);
|
|
||||||
};
|
|
||||||
|
|
||||||
main().catch(err => {
|
|
||||||
log(err);
|
|
||||||
}).finally(() => {
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
log(`Exiting process ${process.pid} with code 0`);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
export * from './client';
|
|
||||||
export * from './utils/index';
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user