Table of Contents
产品分析
TVL

其TVL列表分为3类
CBV
- Canonically Bridged Value 锁定在以太坊上,跨到L2EBV
- Externally Bridged Value 锁定在其他链上,跨到L2NMV
- Natively Minted Value 直接在L2上mint的
Activity

主要展示昨日TPS,7日环比变化,最高记录,30日总量
L2BEAT实现
TVL

其实现入口位于l2beat/packages/backend/src/modules/tvl/api/TvlRouter.ts
/api/tvl
接口
取数据:

其实现方式为从aggregated_reports表中直接查询数据,根据sql判断,该表存的是每小时聚合的数据,字段为:

aggregated_reports表的数据源是report表,每小时从report表中查询数据,汇总到aggregated_reports中。report表字段为:

大致流程:
在token.jsonc配置文件中,为每条链配置token列表,
如果是代币类型是EBV,则计算方式为totalsupply,查询该代币在当前链上合约的totalsupply,存储在total_supplies表;

如果是NMV,则计算方式为circulatingSupply,从coingecko的api查询流通供应,存储在circulating_supplies表;

如果是CBV,则计算方式为查询以太坊链上的官方桥合约对应代币的balance,存储在balances表中。

还有一个定时任务从total_supplies,circulating_supplies,balances三张表中查询数据,再从coingecko的api获取币价,存储到report表中。
Activity

其实现入口位于l2beat/packages/backend/src/modules/tvl/api/ActivityRouter.ts
/api/activity
接口
取数据:


其实现方式为从activity.daily_count_view表中直接查询数据,但未看到写入代码,根据表名推测应该是某个表的视图,根据sql判断,该视图为每天的tps数据。
进一步阅读代码,其实现逻辑为调用项目rpc,轮询最新区块,在packages/backend/src/modules/activity/SequenceProcessor.ts
process函数中,把每个区块的交易数写入block表,其字段为:

随后写入状态表sequence_processor,该表记录block表同步的最新区块状态:

daily_count_view视图由block表创建。
BTCLayer2技术方案
tvl直接使用defillama的API,每日请求一次,缓存至内存。
tps采用L2beat的实现思路,创建定时任务,使用eth_getBlock轮询区块,计算出TPS,但不落数据库,直接缓存至内存中。如果项目方不支持eth jsonrpc的api,需要单独开发进行接入。
chain | rpc |
---|---|
Merlin Chain | https://rpc.merlinchain.io |
Rootstock | https://public-node.rsk.co https://rpc.rootstock.io/ |
Stacks | 不支持eth_getBlock |
Bitlayer | https://rpc.bitlayer.org https://rpc.bitlayer-rpc.com https://rpc.ankr.com/bitlayer |
B^Square | https://rpc.bsquared.network https://b2-mainnet.alt.technology |
BEVM | https://rpc-mainnet-1.bevm.io https://rpc-mainnet-2.bevm.io |
BOB | https://rpc.gobob.xyz/ |
L2BEAT源码部署
tvl模块
代码目录l2beat/backend
建库:
docker run -d --name=l2beat_postgres -p 5432:5432 -e POSTGRES_PASSWORD=password postgres:14docker exec -it l2beat_postgres psql -U postgres -c 'CREATE DATABASE l2beat_local'docker exec -it l2beat_postgres psql -U postgres -c 'CREATE DATABASE l2beat_test'
创建环境变量.env文件(打开arbitrum eth的tvl统计功能)
LOCAL_DB_URL=postgresql://postgres:123456@localhost:5432/l2beat_localTEST_DB_URL=postgresql://postgres:123456@localhost:5432/l2beat_testFEATURES=tvl,!tvl.*,tvl.arbitrum,tvl.ethereum,status
ARBITRUM_RPC_URL=https://arb-mainnet.g.alchemy.com/v2/xxxARBITRUM_ETHERSCAN_API_KEY=xxx
ETHEREUM_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/xxxETHEREUM_ETHERSCAN_API_KEY=xxx
COINGECKO_API_KEY=xxx
配置目录l2beat/config
配置tokens.jsonc文件
{
"arbitrum": [ { "symbol": "FRAX", "address": "0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F", "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, { "symbol": "FXS", "address": "0x9d2F299715D94d8A7E6F5eaa8E654E8c74a988A7", "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, ]}
运行yarn tokens,生成generated.json文件
{ "comment": "This file was autogenerated. Please do not edit it manually.", "tokens": [ { "id": "zrx-0x-protocol-token", "name": "0x Protocol Token", "coingeckoId": "0x", "address": "0xE41d2489571d322189246DaFA5ebDe1F4699F498", "symbol": "ZRX", "decimals": 18, "deploymentTimestamp": 1502476756, "coingeckoListingTimestamp": 1573689600, "category": "other", "iconUrl": "https://assets.coingecko.com/coins/images/863/large/0x.png?1696501996", "chainId": 1, "type": "CBV", "formula": "locked" }, { "id": "arbitrum:frax-frax", "name": "Frax", "coingeckoId": "frax", "address": "0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F", "symbol": "FRAX", "decimals": 18, "deploymentTimestamp": 1632766868, "coingeckoListingTimestamp": 1718507527, "category": "other", "iconUrl": "https://coin-images.coingecko.com/coins/images/13422/large/FRAX_icon.png?1696513182", "chainId": 42161, "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, { "id": "arbitrum:frxeth-frax-ether", "name": "Frax Ether", "coingeckoId": "frax-ether", "address": "0x178412e79c25968a32e89b11f63B33F733770c2A", "symbol": "frxETH", "decimals": 18, "deploymentTimestamp": 1673211956, "coingeckoListingTimestamp": 1718511102, "category": "other", "iconUrl": "https://coin-images.coingecko.com/coins/images/28284/large/frxETH_icon.png?1696527284", "chainId": 42161, "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, { "id": "arbitrum:fpi-frax-price-index", "name": "Frax Price Index", "coingeckoId": "frax-price-index", "address": "0x1B01514A2B3CdEf16fD3c680a818A0Ab97Da8a09", "symbol": "FPI", "decimals": 18, "deploymentTimestamp": 1677013204, "coingeckoListingTimestamp": 1718514309, "category": "other", "iconUrl": "https://coin-images.coingecko.com/coins/images/24945/large/FPI_icon.png?1696524100", "chainId": 42161, "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, { "id": "arbitrum:fpis-frax-price-index-share", "name": "Frax Price Index Share", "coingeckoId": "frax-price-index-share", "address": "0x3405E88af759992937b84E58F2Fe691EF0EeA320", "symbol": "FPIS", "decimals": 18, "deploymentTimestamp": 1677013206, "coingeckoListingTimestamp": 1718510810, "category": "other", "iconUrl": "https://coin-images.coingecko.com/coins/images/24944/large/FPIS_icon.png?1696524099", "chainId": 42161, "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, { "id": "arbitrum:fxs-frax-share", "name": "Frax Share", "coingeckoId": "frax-share", "address": "0x9d2F299715D94d8A7E6F5eaa8E654E8c74a988A7", "symbol": "FXS", "decimals": 18, "deploymentTimestamp": 1632766868, "coingeckoListingTimestamp": 1718510434, "category": "other", "iconUrl": "https://coin-images.coingecko.com/coins/images/13423/large/Frax_Shares_icon.png?1696513183", "chainId": 42161, "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } }, { "id": "arbitrum:sfrxeth-staked-frax-ether", "name": "Staked Frax Ether", "coingeckoId": "staked-frax-ether", "address": "0x95aB45875cFFdba1E5f451B950bC2E42c0053f39", "symbol": "sfrxETH", "decimals": 18, "deploymentTimestamp": 1673211957, "coingeckoListingTimestamp": 1718510623, "category": "other", "iconUrl": "https://coin-images.coingecko.com/coins/images/28285/large/sfrxETH_icon.png?1696527285", "chainId": 42161, "type": "EBV", "formula": "totalSupply", "bridgedUsing": { "bridge": "Frax Ferry", "slug": "fraxferry" } } ]}
在config的project目录下配置layer2s,bridge,layer3,移除不需要的链

项目运行
yarn start:dev

访问http://localhost:3000 /api/tvl/aggregate?projectSlugs=arbitrum
运行过程中可能出现的问题:
- 由于网络问题,alchemy请求失败,可修改share文件夹下的httpclient.ts文件,使用本地代理
import fetch, { RequestInit, Response } from 'node-fetch'import {HttpsProxyAgent} from 'https-proxy-agent';
export class HttpClient { private readonly agent!: HttpsProxyAgent<string>; constructor(private readonly defaultTimeoutMs = 10_000) { this.agent = new HttpsProxyAgent("http://localhost:7890"); }
fetch(url: string, init?: RequestInit): Promise<Response> { const requestInit: RequestInit = { ...init, // 设置代理代理(如果存在) agent: this.agent ?? init?.agent, // 设置超时时间 timeout: (init && 'timeout' in init ? init.timeout : this.defaultTimeoutMs), };
return fetch(url, requestInit); }}
- COINGECKO的api请求报错,demokey无法获取365日之前的数据,修改请求开始时间

activity模块
features增加activity开关,必须配置STARKEX_API_KEY,可随意填写
FEATURES=tvl,!tvl.*,tvl.arbitrum,tvl.ethereum,status,activity,tvlCleaner
STARKEX_API_KEY=xxx
packages/backend/src/config/features/activity.ts配置eth起始区块

packages/config/src/projects/layer2s/arbitrum.ts配置arb起始区块
