Skip to content

Commit

Permalink
Merge pull request #36 from zkBob/feature/polygon-gasstation
Browse files Browse the repository at this point in the history
Add polygon gas station
  • Loading branch information
Leonid Tyurin authored Sep 14, 2022
2 parents 7c587c3 + 7f91f84 commit 79f4a65
Show file tree
Hide file tree
Showing 23 changed files with 194 additions and 87 deletions.
4 changes: 3 additions & 1 deletion CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
| TREE_UPDATE_PARAMS_PATH | Local path to tree update parameters | string |
| TX_VK_PATH | Local path to transaction curcuit verification key | string |
| GAS_PRICE_FALLBACK | Default fallback gas price | integer |
| GAS_PRICE_ESTIMATION_TYPE | Gas price estimation type | `web3` / `gas-price-oracle` / `eip1559-gas-estimation` |
| GAS_PRICE_ESTIMATION_TYPE | Gas price estimation type | `web3` / `gas-price-oracle` / `eip1559-gas-estimation` / `polygon-gasstation-v2` |
| GAS_PRICE_SPEED_TYPE | This parameter specifies the desirable transaction speed | `instant` / `fast` / `standard` / `low` |
| GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer |
| GAS_PRICE_UPDATE_INTERVAL | Interval in milliseconds used to get the updated gas price value using specified estimation type | integer |
| RELAYER_LOG_LEVEL | Log level | Winston log level |
| RELAYER_REDIS_URL | Url to redis instance | URL |
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"chai": "^4.3.4",
"prettier": "^2.7.1",
"ts-loader": "^9.2.4",
"tsconfig-paths": "^4.1.0",
"typescript": "^4.3.5"
},
"workspaces": [
Expand Down
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
"strict": true,
"declaration": true,
"lib": ["es2019.array", "dom"]
},
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
40 changes: 36 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,11 @@ clone-response@^1.0.2:
dependencies:
mimic-response "^1.0.0"

clone@2.x:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==

cluster-key-slot@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
Expand Down Expand Up @@ -2533,13 +2538,14 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==

gas-price-oracle@^0.4.7:
version "0.4.7"
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.4.7.tgz#47406048083074bcab677efb9de08663e742153d"
integrity sha512-Ti8nhpATm83YebWU/Pz5xclZoTkzOblIhT504ZViZJUcd8jOxgj9pWtCasg8RYw+d0f19m0dJUPvdj04RC4o3A==
gas-price-oracle@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.5.1.tgz#f9a8a758014a584ee1a242edb3b34eb6e2cd94a7"
integrity sha512-Jb1w127I0wSRKQNqNUE61bQInbJzbyaapAlFjRgtYOTVHOJ+3VZuKPt0dyz5Mo40Ax5I7Z+rB6vQmTIQHLnt9Q==
dependencies:
axios "^0.21.2"
bignumber.js "^9.0.0"
node-cache "^5.1.2"

get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
Expand Down Expand Up @@ -3479,6 +3485,11 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"

json5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==

jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
Expand Down Expand Up @@ -3843,6 +3854,11 @@ minimist@^1.2.0, minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==

minimist@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==

minipass@^2.6.0, minipass@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
Expand Down Expand Up @@ -4119,6 +4135,13 @@ node-addon-api@^2.0.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==

node-cache@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d"
integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==
dependencies:
clone "2.x"

node-environment-flags@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
Expand Down Expand Up @@ -5671,6 +5694,15 @@ tsconfig-paths@^3.5.0:
minimist "^1.2.0"
strip-bom "^3.0.0"

tsconfig-paths@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz#f8ef7d467f08ae3a695335bf1ece088c5538d2c1"
integrity sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow==
dependencies:
json5 "^2.2.1"
minimist "^1.2.6"
strip-bom "^3.0.0"

tslib@^1.14.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
Expand Down
4 changes: 3 additions & 1 deletion zp-relayer/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './env'
import Web3 from 'web3'
import { toBN } from 'web3-utils'
import type { EstimationType } from './services/GasPrice'
import type { EstimationType, GasPriceKey } from './services/gas-price'

const relayerAddress = new Web3().eth.accounts.privateKeyToAccount(
process.env.RELAYER_ADDRESS_PRIVATE_KEY as string
Expand All @@ -20,6 +20,8 @@ const config = {
txVKPath: process.env.TX_VK_PATH || './params/transfer_verification_key.json',
gasPriceFallback: process.env.GAS_PRICE_FALLBACK as string,
gasPriceEstimationType: (process.env.GAS_PRICE_ESTIMATION_TYPE as EstimationType) || 'web3',
gasPriceSpeedType: (process.env.GAS_PRICE_SPEED_TYPE as GasPriceKey) || 'fast',
gasPriceFactor: Number((process.env.GAS_PRICE_FACTOR as string) || '1'),
gasPriceUpdateInterval: parseInt(process.env.GAS_PRICE_UPDATE_INTERVAL || '5000'),
logLevel: process.env.RELAYER_LOG_LEVEL || 'debug',
redisUrl: process.env.RELAYER_REDIS_URL,
Expand Down
7 changes: 5 additions & 2 deletions zp-relayer/init.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { pool } from './pool'
import { GasPrice } from './services/GasPrice'
import { GasPrice } from './services/gas-price'
import { web3 } from './services/web3'
import config from './config'
import { Mutex } from 'async-mutex'
Expand All @@ -12,7 +12,10 @@ export async function init() {
await initializeDomain(web3)

await pool.init()
const gasPriceService = new GasPrice(web3, config.gasPriceUpdateInterval, config.gasPriceEstimationType, {})
const gasPriceService = new GasPrice(web3, config.gasPriceUpdateInterval, config.gasPriceEstimationType, {
speedType: config.gasPriceSpeedType,
factor: config.gasPriceFactor,
})
await gasPriceService.start()
const workerMutex = new Mutex()
;(await createPoolTxWorker(gasPriceService, workerMutex)).run()
Expand Down
2 changes: 1 addition & 1 deletion zp-relayer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-winston": "4.2.0",
"gas-price-oracle": "^0.4.7",
"gas-price-oracle": "0.5.1",
"ioredis": "4.27.10",
"libzkbob-rs-node": "0.1.27",
"node-fetch": "^2.6.1",
Expand Down
4 changes: 2 additions & 2 deletions zp-relayer/queue/poolTxQueue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Queue } from 'bullmq'
import { redis } from '../services/redisClient'
import { TX_QUEUE_NAME } from '../utils/constants'
import { redis } from '@/services/redisClient'
import { TX_QUEUE_NAME } from '@/utils/constants'
import { Proof } from 'libzkbob-rs-node'
import { TxType } from 'zp-memo-parser'

Expand Down
4 changes: 2 additions & 2 deletions zp-relayer/queue/sentTxQueue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Queue, QueueScheduler } from 'bullmq'
import { redis } from '../services/redisClient'
import { SENT_TX_QUEUE_NAME } from '../utils/constants'
import { redis } from '@/services/redisClient'
import { SENT_TX_QUEUE_NAME } from '@/utils/constants'
import { TxPayload } from './poolTxQueue'
import type { TransactionConfig } from 'web3-core'

Expand Down
2 changes: 1 addition & 1 deletion zp-relayer/services/appLogger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createLogger, format, transports } from 'winston'
import config from '../config'
import config from '@/config'

export const logger = createLogger({
level: config.logLevel,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import type Web3 from 'web3'
import { toBN, toWei } from 'web3-utils'
import config from '../config'
import { setIntervalAndRun } from '../utils/helpers'
import { toWei } from 'web3-utils'
import config from '@/config'
import { setIntervalAndRun } from '@/utils/helpers'
import { estimateFees } from '@mycrypto/gas-estimation'
import { GasPriceOracle } from 'gas-price-oracle'
import type { GasPriceKey } from 'gas-price-oracle/lib/types'
import { logger } from './appLogger'
import { logger } from '@/services/appLogger'
import {
EstimationType,
FetchFunc,
EstimationOptions,
GasPriceValue,
EstimationEIP1559,
EstimationOracle,
EstimationPolygonGSV2,
EstimationWeb3,
PolygonGSV2Response,
PolygonGSV2GasPriceKey,
GasPriceKey,
} from './types'

// GasPrice fields
interface LegacyGasPrice {
gasPrice: string
const polygonGasPriceKeyMapping: Record<GasPriceKey, PolygonGSV2GasPriceKey> = {
low: 'safeLow',
standard: 'standard',
fast: 'fast',
instant: 'fast',
}
interface EIP1559GasPrice {
maxFeePerGas: string
maxPriorityFeePerGas: string
}
export type GasPriceValue = LegacyGasPrice | EIP1559GasPrice

type EstimationEIP1559 = 'eip1559-gas-estimation'
type EstimationOracle = 'gas-price-oracle'
type EstimationWeb3 = 'web3'
export type EstimationType = EstimationEIP1559 | EstimationOracle | EstimationWeb3

type EstimationOracleOptions = { speedType: GasPriceKey; factor: number }
type EstimationOptions<ET extends EstimationType> = ET extends EstimationOracle ? EstimationOracleOptions : {}

type FetchFunc<ET extends EstimationType> = (_: EstimationOptions<ET>) => Promise<GasPriceValue>

export class GasPrice<ET extends EstimationType> {
private fetchGasPriceInterval: NodeJS.Timeout | null = null
Expand Down Expand Up @@ -63,16 +62,17 @@ export class GasPrice<ET extends EstimationType> {
return this.cachedGasPrice
}

private getFetchFunc(estimationType: ET): FetchFunc<ET> {
private getFetchFunc(estimationType: EstimationType): FetchFunc<EstimationType> {
const funcs: Record<EstimationType, FetchFunc<EstimationType>> = {
'web3': this.fetchGasPriceWeb3,
'eip1559-gas-estimation': this.fetchGasPriceEIP1559,
'web3': this.fetchWeb3,
'eip1559-gas-estimation': this.fetchEIP1559,
'gas-price-oracle': this.fetchGasPriceOracle,
'polygon-gasstation-v2': this.fetchPolygonGasStationV2,
}
return funcs[estimationType]
}

private fetchGasPriceEIP1559: FetchFunc<EstimationEIP1559> = async () => {
private fetchEIP1559: FetchFunc<EstimationEIP1559> = async () => {
// @ts-ignore
const options = await estimateFees(this.web3)
const res = {
Expand All @@ -82,21 +82,31 @@ export class GasPrice<ET extends EstimationType> {
return res
}

private fetchGasPriceWeb3: FetchFunc<EstimationWeb3> = async () => {
private fetchWeb3: FetchFunc<EstimationWeb3> = async () => {
const gasPrice = await this.web3.eth.getGasPrice()
return { gasPrice }
}

// TODO: defaults to Mainnet; provide options for other supported oracles
private fetchGasPriceOracle: FetchFunc<EstimationOracle> = async options => {
const gasPriceOracle = new GasPriceOracle()
const json = await gasPriceOracle.fetchGasPricesOffChain()
const gasPrice = GasPrice.normalizeGasPrice(json[options.speedType], options.factor).toString(10)
const json = await gasPriceOracle.legacy.fetchGasPricesOffChain()
const gasPrice = GasPrice.normalizeGasPrice(json[options.speedType], options.factor)
return { gasPrice }
}

static normalizeGasPrice(oracleGasPrice: number, factor: number, limits = null) {
const gasPrice = oracleGasPrice * factor
return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei'))
private fetchPolygonGasStationV2: FetchFunc<EstimationPolygonGSV2> = async options => {
const response = await fetch('https://gasstation-mainnet.matic.network/v2')
const json: PolygonGSV2Response = await response.json()
const speedType = polygonGasPriceKeyMapping[options.speedType]
const { maxFee, maxPriorityFee } = json[speedType]
return {
maxFeePerGas: GasPrice.normalizeGasPrice(maxFee),
maxPriorityFeePerGas: GasPrice.normalizeGasPrice(maxPriorityFee),
}
}

static normalizeGasPrice(rawGasPrice: number, factor = 1) {
const gasPrice = rawGasPrice * factor
return toWei(gasPrice.toFixed(2).toString(), 'gwei')
}
}
2 changes: 2 additions & 0 deletions zp-relayer/services/gas-price/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './GasPrice'
export * from './types'
48 changes: 48 additions & 0 deletions zp-relayer/services/gas-price/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// GasPrice fields
interface LegacyGasPrice {
gasPrice: string
}
interface EIP1559GasPrice {
maxFeePerGas: string
maxPriorityFeePerGas: string
}
export type GasPriceValue = LegacyGasPrice | EIP1559GasPrice

// In Gwei
export interface PolygonGSV2Response {
safeLow: {
maxPriorityFee: number
maxFee: number
}
standard: {
maxPriorityFee: number
maxFee: number
}
fast: {
maxPriorityFee: number
maxFee: number
}
estimatedBaseFee: number
blockTime: number
blockNumber: number
}

export type GasPriceKey = 'instant' | 'fast' | 'standard' | 'low'
export type PolygonGSV2GasPriceKey = 'safeLow' | 'standard' | 'fast'

// Estimation types
export type EstimationEIP1559 = 'eip1559-gas-estimation'
export type EstimationOracle = 'gas-price-oracle'
export type EstimationWeb3 = 'web3'
export type EstimationPolygonGSV2 = 'polygon-gasstation-v2'
export type EstimationType = EstimationEIP1559 | EstimationOracle | EstimationWeb3 | EstimationPolygonGSV2

export type EstimationOracleOptions = { speedType: GasPriceKey; factor: number }
export type EstimationPolygonGSV2Options = { speedType: GasPriceKey }
export type EstimationOptions<ET extends EstimationType> = ET extends EstimationOracle
? EstimationOracleOptions
: ET extends EstimationPolygonGSV2
? EstimationPolygonGSV2Options
: {}

export type FetchFunc<ET extends EstimationType> = (_: EstimationOptions<ET>) => Promise<GasPriceValue>
2 changes: 1 addition & 1 deletion zp-relayer/services/redisClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Redis from 'ioredis'
import { logger } from './appLogger'
import config from '../config'
import config from '@/config'

export const redis = new Redis(config.redisUrl, {
maxRetriesPerRequest: null,
Expand Down
2 changes: 1 addition & 1 deletion zp-relayer/services/web3.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Web3 from 'web3'
import config from '../config'
import config from '@/config'

export const web3 = new Web3(config.rpcUrl)
6 changes: 5 additions & 1 deletion zp-relayer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "build"
"outDir": "build",
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
},
"exclude": ["./test", "./build"]
}
4 changes: 2 additions & 2 deletions zp-relayer/utils/EIP712SaltedPermit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import config from '../config'
import config from '@/config'
import { recoverTypedSignature, SignTypedDataVersion } from '@metamask/eth-sig-util'
import Web3 from 'web3'
import TokenAbi from '../abi/token-abi.json'
import TokenAbi from '@/abi/token-abi.json'
import { getChainId } from './web3'
import { AbiItem } from 'web3-utils'

Expand Down
2 changes: 1 addition & 1 deletion zp-relayer/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BN from 'bn.js'
import { padLeft, toBN } from 'web3-utils'
import { logger } from '../services/appLogger'
import { logger } from '@/services/appLogger'
import { SnarkProof } from 'libzkbob-rs-node'
import { TxType } from 'zp-memo-parser'
import type { Mutex } from 'async-mutex'
Expand Down
Loading

0 comments on commit 79f4a65

Please sign in to comment.