Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tron integration #205

Open
wants to merge 14 commits into
base: devel
Choose a base branch
from
Open
312 changes: 312 additions & 0 deletions yarn.lock

Large diffs are not rendered by default.

52 changes: 34 additions & 18 deletions zp-relayer/configs/baseConfig.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
const config = {
poolAddress: process.env.COMMON_POOL_ADDRESS as string,
startBlock: parseInt(process.env.COMMON_START_BLOCK || '0'),
colorizeLogs: process.env.COMMON_COLORIZE_LOGS === 'true',
logLevel: process.env.COMMON_LOG_LEVEL || 'debug',
redisUrl: process.env.COMMON_REDIS_URL as string,
rpcUrls: (process.env.COMMON_RPC_URL as string).split(' ').filter(url => url.length > 0),
requireHTTPS: process.env.COMMON_REQUIRE_RPC_HTTPS === 'true',
rpcSyncCheckInterval: parseInt(process.env.COMMON_RPC_SYNC_STATE_CHECK_INTERVAL || '0'),
rpcRequestTimeout: parseInt(process.env.COMMON_RPC_REQUEST_TIMEOUT || '1000'),
jsonRpcErrorCodes: (process.env.COMMON_JSONRPC_ERROR_CODES || '-32603 -32002 -32005')
.split(' ')
.filter(s => s.length > 0)
.map(s => parseInt(s, 10)),
eventsProcessingBatchSize: parseInt(process.env.COMMON_EVENTS_PROCESSING_BATCH_SIZE || '10000'),
screenerUrl: process.env.COMMON_SCREENER_URL || null,
screenerToken: process.env.COMMON_SCREENER_TOKEN || null,
}
import { z } from 'zod'

export const zBooleanString = () => z.enum(['true', 'false']).transform(value => value === 'true')
export const zNullishString = () =>
z
.string()
.optional()
.transform(x => x ?? null)

const schema = z.object({
COMMON_POOL_ADDRESS: z.string(),
COMMON_START_BLOCK: z.coerce.number().default(0),
COMMON_COLORIZE_LOGS: zBooleanString().default('false'),
COMMON_LOG_LEVEL: z.string().default('debug'),
COMMON_REDIS_URL: z.string(),
COMMON_RPC_URL: z.string().transform(us => us.split(' ').filter(url => url.length > 0)),
COMMON_REQUIRE_RPC_HTTPS: zBooleanString().default('false'),
COMMON_RPC_SYNC_STATE_CHECK_INTERVAL: z.coerce.number().default(0),
COMMON_RPC_REQUEST_TIMEOUT: z.coerce.number().default(1000),
COMMON_JSONRPC_ERROR_CODES: z
.string()
.transform(s =>
s
.split(' ')
.filter(s => s.length > 0)
.map(s => parseInt(s, 10))
)
.default('-32603 -32002 -32005'),
COMMON_EVENTS_PROCESSING_BATCH_SIZE: z.coerce.number().default(10000),
COMMON_SCREENER_URL: zNullishString(),
COMMON_SCREENER_TOKEN: zNullishString(),
})

const config = schema.parse(process.env)

export default config
22 changes: 22 additions & 0 deletions zp-relayer/configs/guardConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { z } from 'zod'
import { Network } from '@/services/network/types'

export const zBooleanString = () => z.enum(['true', 'false']).transform(value => value === 'true')

const schema = z.object({
GUARD_PORT: z.coerce.number(),
GUARD_NETWORK: z.nativeEnum(Network),
COMMON_RPC_URL: z.string().transform(us => us.split(' ').filter(url => url.length > 0)),
GUARD_ADDRESS_PRIVATE_KEY: z.string(),
GUARD_TOKEN_ADDRESS: z.string(),
COMMON_REQUIRE_RPC_HTTPS: zBooleanString().default('false'),
COMMON_POOL_ADDRESS: z.string(),
GUARD_TX_VK_PATH: z.string().default('../params/transfer_verification_key.json'),
GUARD_TREE_VK_PATH: z.string().default('../params/tree_verification_key.json'),
})

const config = schema.parse(process.env)

export default {
...config,
}
12 changes: 12 additions & 0 deletions zp-relayer/configs/loggerConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { z } from 'zod'

export const zBooleanString = () => z.enum(['true', 'false']).transform(value => value === 'true')

const schema = z.object({
COMMON_COLORIZE_LOGS: zBooleanString().default('false'),
COMMON_LOG_LEVEL: z.string().default('debug'),
})

const config = schema.parse(process.env)

export default config
212 changes: 144 additions & 68 deletions zp-relayer/configs/relayerConfig.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import Web3 from 'web3'
import { toBN } from 'web3-utils'
import baseConfig from './baseConfig'
import baseConfig, { zBooleanString, zNullishString } from './baseConfig'
import { FeeManagerType } from '@/services/fee'
import { PriceFeedType } from '@/services/price-feed'
import type { EstimationType, GasPriceKey } from '@/services/gas-price'
import { EstimationType } from '@/services/gas-price'
import { ProverType } from '@/prover'
import { countryCodes } from '@/utils/countryCodes'
import { logger } from '@/services/appLogger'
import { PermitType } from '@/utils/permit/types'
import { TxType } from 'zp-memo-parser'
import { z } from 'zod'
import { Network } from '@/services/network/types'

const relayerAddress = new Web3().eth.accounts.privateKeyToAccount(
process.env.RELAYER_ADDRESS_PRIVATE_KEY as string
Expand All @@ -17,72 +19,146 @@ const relayerAddress = new Web3().eth.accounts.privateKeyToAccount(
const defaultHeaderBlacklist =
'accept accept-language accept-encoding connection content-length content-type postman-token referer upgrade-insecure-requests'

const config = {
...baseConfig,
relayerRef: process.env.RELAYER_REF || null,
relayerSHA: process.env.RELAYER_SHA || null,
port: parseInt(process.env.RELAYER_PORT || '8000'),
relayerAddress,
relayerPrivateKey: process.env.RELAYER_ADDRESS_PRIVATE_KEY as string,
tokenAddress: process.env.RELAYER_TOKEN_ADDRESS as string,
relayerGasLimit: toBN(process.env.RELAYER_GAS_LIMIT as string),
minBaseFee: toBN(process.env.RELAYER_MIN_BASE_FEE || '0'),
relayerFee: process.env.RELAYER_FEE ? toBN(process.env.RELAYER_FEE) : null,
maxNativeAmount: toBN(process.env.RELAYER_MAX_NATIVE_AMOUNT || '0'),
treeUpdateParamsPath: process.env.RELAYER_TREE_UPDATE_PARAMS_PATH || './params/tree_params.bin',
transferParamsPath: process.env.RELAYER_TRANSFER_PARAMS_PATH || './params/transfer_params.bin',
directDepositParamsPath: process.env.RELAYER_DIRECT_DEPOSIT_PARAMS_PATH || './params/delegated_deposit_params.bin',
txVKPath: process.env.RELAYER_TX_VK_PATH || './params/transfer_verification_key.json',
requestLogPath: process.env.RELAYER_REQUEST_LOG_PATH || './zp.log',
stateDirPath: process.env.RELAYER_STATE_DIR_PATH || './POOL_STATE',
gasPriceFallback: process.env.RELAYER_GAS_PRICE_FALLBACK as string,
gasPriceEstimationType: (process.env.RELAYER_GAS_PRICE_ESTIMATION_TYPE as EstimationType) || 'web3',
gasPriceSpeedType: (process.env.RELAYER_GAS_PRICE_SPEED_TYPE as GasPriceKey) || 'fast',
gasPriceFactor: parseInt(process.env.RELAYER_GAS_PRICE_FACTOR || '1'),
gasPriceUpdateInterval: parseInt(process.env.RELAYER_GAS_PRICE_UPDATE_INTERVAL || '5000'),
gasPriceSurplus: parseFloat(process.env.RELAYER_GAS_PRICE_SURPLUS || '0.1'),
minGasPriceBumpFactor: parseFloat(process.env.RELAYER_MIN_GAS_PRICE_BUMP_FACTOR || '0.1'),
maxFeeLimit: process.env.RELAYER_MAX_FEE_PER_GAS_LIMIT ? toBN(process.env.RELAYER_MAX_FEE_PER_GAS_LIMIT) : null,
maxSentQueueSize: parseInt(process.env.RELAYER_MAX_SENT_QUEUE_SIZE || '20'),
relayerTxRedundancy: process.env.RELAYER_TX_REDUNDANCY === 'true',
sentTxDelay: parseInt(process.env.RELAYER_SENT_TX_DELAY || '30000'),
sentTxLogErrorThreshold: parseInt(process.env.RELAYER_SENT_TX_ERROR_THRESHOLD || '3'),
insufficientBalanceCheckTimeout: parseInt(process.env.RELAYER_INSUFFICIENT_BALANCE_CHECK_TIMEOUT || '60000'),
permitDeadlineThresholdInitial: parseInt(process.env.RELAYER_PERMIT_DEADLINE_THRESHOLD_INITIAL || '300'),
requireTraceId: process.env.RELAYER_REQUIRE_TRACE_ID === 'true',
requireLibJsVersion: process.env.RELAYER_REQUIRE_LIBJS_VERSION === 'true',
logIgnoreRoutes: (process.env.RELAYER_LOG_IGNORE_ROUTES || '').split(' ').filter(r => r.length > 0),
logHeaderBlacklist: (process.env.RELAYER_LOG_HEADER_BLACKLIST || defaultHeaderBlacklist)
.split(' ')
.filter(r => r.length > 0),
blockedCountries: (process.env.RELAYER_BLOCKED_COUNTRIES || '').split(' ').filter(c => {
if (c.length === 0) return false
const zBN = () => z.string().transform(toBN)

const zTreeProver = z.discriminatedUnion('RELAYER_TREE_PROVER_TYPE', [
z.object({ RELAYER_TREE_PROVER_TYPE: z.literal(ProverType.Local) }),
z.object({ RELAYER_TREE_PROVER_TYPE: z.literal(ProverType.Remote) }), // TODO remote prover url
])

const exists = countryCodes.has(c)
if (!exists) {
logger.error(`Country code ${c} is not valid, skipping`)
}
return exists
const zDirectDepositProver = z.discriminatedUnion('RELAYER_DD_PROVER_TYPE', [
z.object({ RELAYER_DD_PROVER_TYPE: z.literal(ProverType.Local) }),
z.object({ RELAYER_DD_PROVER_TYPE: z.literal(ProverType.Remote) }), // TODO remote prover url
])

const zPriceFeed = z.discriminatedUnion('RELAYER_PRICE_FEED_TYPE', [
z.object({ RELAYER_PRICE_FEED_TYPE: z.literal(PriceFeedType.Native) }),
z.object({
RELAYER_PRICE_FEED_TYPE: z.literal(PriceFeedType.OneInch),
RELAYER_PRICE_FEED_CONTRACT_ADDRESS: z.string(),
RELAYER_PRICE_FEED_BASE_TOKEN_ADDRESS: z.string(),
}),
trustProxy: process.env.RELAYER_EXPRESS_TRUST_PROXY === 'true',
treeProverType: (process.env.RELAYER_TREE_PROVER_TYPE || ProverType.Local) as ProverType,
directDepositProverType: (process.env.RELAYER_DD_PROVER_TYPE || ProverType.Local) as ProverType,
feeManagerType: (process.env.RELAYER_FEE_MANAGER_TYPE || FeeManagerType.Dynamic) as FeeManagerType,
feeManagerUpdateInterval: parseInt(process.env.RELAYER_FEE_MANAGER_UPDATE_INTERVAL || '10000'),
feeMarginFactor: toBN(process.env.RELAYER_FEE_MARGIN_FACTOR || '100'),
feeScalingFactor: toBN(process.env.RELAYER_FEE_SCALING_FACTOR || '100'),
priceFeedType: (process.env.RELAYER_PRICE_FEED_TYPE || PriceFeedType.Native) as PriceFeedType,
priceFeedContractAddress: process.env.RELAYER_PRICE_FEED_CONTRACT_ADDRESS || null,
priceFeedBaseTokenAddress: process.env.RELAYER_PRICE_FEED_BASE_TOKEN_ADDRESS || null,
precomputeParams: process.env.RELAYER_PRECOMPUTE_PARAMS === 'true',
permitType: (process.env.RELAYER_PERMIT_TYPE || PermitType.SaltedPermit) as PermitType,
baseTxGas: {
[TxType.DEPOSIT]: toBN(process.env.RELAYER_BASE_TX_GAS_DEPOSIT || '650000'),
[TxType.PERMITTABLE_DEPOSIT]: toBN(process.env.RELAYER_BASE_TX_GAS_PERMITTABLE_DEPOSIT || '650000'),
[TxType.TRANSFER]: toBN(process.env.RELAYER_BASE_TX_GAS_TRANSFER || '650000'),
[TxType.WITHDRAWAL]: toBN(process.env.RELAYER_BASE_TX_GAS_WITHDRAWAL || '650000'),
nativeConvertOverhead: toBN(process.env.RELAYER_BASE_TX_GAS_NATIVE_CONVERT || '200000'),
},
}
])

const zBaseTxGas = z
.object({
RELAYER_BASE_TX_GAS_DEPOSIT: zBN().default('650000'),
RELAYER_BASE_TX_GAS_PERMITTABLE_DEPOSIT: zBN().default('650000'),
RELAYER_BASE_TX_GAS_TRANSFER: zBN().default('650000'),
RELAYER_BASE_TX_GAS_WITHDRAWAL: zBN().default('650000'),
RELAYER_BASE_TX_GAS_NATIVE_CONVERT: zBN().default('200000'),
})
.transform(o => ({
baseTxGas: {
[TxType.DEPOSIT]: o.RELAYER_BASE_TX_GAS_DEPOSIT,
[TxType.PERMITTABLE_DEPOSIT]: o.RELAYER_BASE_TX_GAS_PERMITTABLE_DEPOSIT,
[TxType.TRANSFER]: o.RELAYER_BASE_TX_GAS_TRANSFER,
[TxType.WITHDRAWAL]: o.RELAYER_BASE_TX_GAS_WITHDRAWAL,
RELAYER_BASE_TX_GAS_NATIVE_CONVERT: o.RELAYER_BASE_TX_GAS_NATIVE_CONVERT,
},
}))

const zFeeManager = z
.object({
RELAYER_FEE_MARGIN_FACTOR: zBN().default('100'),
RELAYER_FEE_SCALING_FACTOR: zBN().default('100'),
RELAYER_FEE_MANAGER_UPDATE_INTERVAL: z.coerce.number().default(10000),
})
.and(
z.discriminatedUnion('RELAYER_FEE_MANAGER_TYPE', [
z.object({ RELAYER_FEE_MANAGER_TYPE: z.literal(FeeManagerType.Optimism) }),
z.object({ RELAYER_FEE_MANAGER_TYPE: z.literal(FeeManagerType.Dynamic) }),
z.object({ RELAYER_FEE_MANAGER_TYPE: z.literal(FeeManagerType.Static), RELAYER_FEE: zBN() }),
])
)

const zGasPrice = z.object({
RELAYER_GAS_PRICE_ESTIMATION_TYPE: z.nativeEnum(EstimationType).default(EstimationType.Web3),
RELAYER_GAS_PRICE_UPDATE_INTERVAL: z.coerce.number().default(5000),
RELAYER_GAS_PRICE_SURPLUS: z.coerce.number().default(0.1),
RELAYER_MIN_GAS_PRICE_BUMP_FACTOR: z.coerce.number().default(0.1),
RELAYER_GAS_PRICE_FACTOR: z.coerce.number().default(1),
RELAYER_GAS_PRICE_SPEED_TYPE: z.string().default('fast'),
RELAYER_GAS_PRICE_FALLBACK: z.string(),
RELAYER_MAX_FEE_PER_GAS_LIMIT: zBN().nullable().default(null),
})
z.discriminatedUnion('RELAYER_GAS_PRICE_ESTIMATION_TYPE', [
z.object({ RELAYER_GAS_PRICE_ESTIMATION_TYPE: z.literal(EstimationType.EIP1559) }),
z.object({ RELAYER_GAS_PRICE_ESTIMATION_TYPE: z.literal(EstimationType.Web3) }),
z.object({
RELAYER_GAS_PRICE_ESTIMATION_TYPE: z.literal(EstimationType.Oracle),
RELAYER_GAS_PRICE_FALLBACK: z.string(),
}),
])

const zGuards = z.object({
RELAYER_GUARDS_CONFIG_PATH: z.string().optional(),
RELAYER_MPC_GUARD_CONTRACT: z.string().optional(),
})

const zSchema = z
.object({
RELAYER_NETWORK: z.nativeEnum(Network),
RELAYER_REF: zNullishString(),
RELAYER_SHA: zNullishString(),
RELAYER_PORT: z.coerce.number().default(8000),
RELAYER_ADDRESS_PRIVATE_KEY: z.string(),
RELAYER_TOKEN_ADDRESS: z.string(),
RELAYER_GAS_LIMIT: zBN(),
RELAYER_MIN_BASE_FEE: zBN().default('0'),
RELAYER_MAX_NATIVE_AMOUNT: zBN().default('0'),
RELAYER_TREE_UPDATE_PARAMS_PATH: z.string().default('./params/tree_params.bin'),
RELAYER_TRANSFER_PARAMS_PATH: z.string().default('./params/transfer_params.bin'),
RELAYER_DIRECT_DEPOSIT_PARAMS_PATH: z.string().default('./params/delegated_deposit_params.bin'),
RELAYER_TX_VK_PATH: z.string().default('./params/transfer_verification_key.json'),
RELAYER_REQUEST_LOG_PATH: z.string().default('./zp.log'),
RELAYER_STATE_DIR_PATH: z.string().default('./POOL_STATE'),
RELAYER_GAS_PRICE_FALLBACK: z.string(),
RELAYER_TX_REDUNDANCY: zBooleanString().default('false'),
RELAYER_SENT_TX_DELAY: z.coerce.number().default(30000),
RELAYER_SENT_TX_ERROR_THRESHOLD: z.coerce.number().default(3),
RELAYER_INSUFFICIENT_BALANCE_CHECK_TIMEOUT: z.coerce.number().default(60000),
RELAYER_PERMIT_DEADLINE_THRESHOLD_INITIAL: z.coerce.number().default(300),
RELAYER_REQUIRE_TRACE_ID: zBooleanString().default('false'),
RELAYER_REQUIRE_LIBJS_VERSION: zBooleanString().default('false'),
RELAYER_EXPRESS_TRUST_PROXY: zBooleanString().default('false'),
RELAYER_PRECOMPUTE_PARAMS: zBooleanString().default('false'),
RELAYER_LOG_IGNORE_ROUTES: z
.string()
.default('')
.transform(rs => rs.split(' ').filter(r => r.length > 0)),
RELAYER_LOG_HEADER_BLACKLIST: z
.string()
.default(defaultHeaderBlacklist)
.transform(hs => hs.split(' ').filter(r => r.length > 0)),
RELAYER_PERMIT_TYPE: z.nativeEnum(PermitType).default(PermitType.SaltedPermit),
RELAYER_BLOCKED_COUNTRIES: z
.string()
.default('')
.transform(cs =>
cs.split(' ').filter(c => {
if (c.length === 0) return false

const exists = countryCodes.has(c)
if (!exists) {
logger.error(`Country code ${c} is not valid, skipping`)
}
return exists
})
),
})
.and(zTreeProver)
.and(zDirectDepositProver)
.and(zPriceFeed)
.and(zBaseTxGas)
.and(zFeeManager)
.and(zGasPrice)
.and(zGuards)

export default config
const config = zSchema.parse(process.env)

export default {
...config,
...baseConfig,
RELAYER_ADDRESS: relayerAddress,
}
13 changes: 13 additions & 0 deletions zp-relayer/guard/guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import express from 'express'
import { logger } from '../services/appLogger'
import { createRouter } from './router'
import { init } from './init'
import config from '@/configs/guardConfig'

const app = express()

init().then(({ poolContract }) => {
app.use(createRouter({ poolContract }))
const PORT = config.GUARD_PORT
app.listen(PORT, () => logger.info(`Started guard on port ${PORT}`))
})
30 changes: 30 additions & 0 deletions zp-relayer/guard/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// @ts-ignore
import TronWeb from 'tronweb'
import config from '@/configs/guardConfig'
import { Network, NetworkContract } from '@/services/network'
import { EthereumContract } from '@/services/network/evm/EvmContract'
import { TronContract } from '@/services/network/tron/TronContract'
import Web3 from 'web3'
import PoolAbi from '../abi/pool-abi.json'

function getPoolContract(): NetworkContract<Network> {
if (config.GUARD_NETWORK === Network.Tron) {
const tronWeb = new TronWeb(config.COMMON_RPC_URL[0], config.COMMON_RPC_URL[0], config.COMMON_RPC_URL[0])

const address = tronWeb.address.fromPrivateKey(config.GUARD_ADDRESS_PRIVATE_KEY.slice(2))
tronWeb.setAddress(address)

return new TronContract(tronWeb, PoolAbi, config.COMMON_POOL_ADDRESS)
} else if (config.GUARD_NETWORK === Network.Ethereum) {
const web3 = new Web3(config.COMMON_RPC_URL[0])
return new EthereumContract(web3, PoolAbi, config.COMMON_POOL_ADDRESS)
} else {
throw new Error('Unsupported network')
}
}

export async function init() {
const poolContract = getPoolContract()

return { poolContract }
}
Loading
Loading