> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tenderly.co/llms.txt
> Use this file to discover all available pages before exploring further.

# 新 Uniswap 池的 Discord 告警

> 按照分步指南创建一个 Web3 Action，在 Uniswap V3 上 创建新池时向您发送 Discord 消息。

本教程向您展示 **如何使用 [Web3 Action](/monitoring/web3-actions/introduction) 在 Uniswap V3 上创建新池时向 Discord 频道发送消息**。您可以使用此 Web3 Action 在链上发生事件时通知您的社区。

<Note>
  完整代码可在 [**此 GitHub
  仓库**](https://github.com/Tenderly/examples-web3-actions/) 中获取。请注意，目前它位于一个单独的分支中。
</Note>

## 项目概览

本项目的目标是教您如何使用 Web3 Actions 在创建 Uniswap 池时发送 Discord 消息。我们将向您展示两种方式 —— 更方便的方式是使用 `PoolCreated` 事件作为我们 Web3 Action 的触发器（参见 [函数、事件和触发器](/monitoring/web3-actions/references/functions-events-triggers) 以及 [**Uniswap 文档**](https://developers.uniswap.org/protocol/V2/reference/smart-contracts/factory#paircreated)）。

## 计划

* 将合约添加到您的 Tenderly 项目 —— [**UniswapV3ContractFactory**](https://dashboard.tenderly.co/nenad/uniswap/contract/mainnet/0x1f98431c8ad98523631ae4a59f267346ea31f984)。它已经在 Tenderly 中经过验证，因此您只需将它们添加到您的项目即可。
* 将 Discord Webhook URL 存储在您的 Web3 Action Secrets 中。
* 创建一个响应 `[PoolCreated](<https://developers.uniswap.org/protocol/reference/core/interfaces/IUniswapV3Factory#poolcreated>)` 事件的 Web3 Action。

### 1：将 Uniswap 合约添加到您的 Tenderly 项目

Web3 Actions 要求用于指定触发器的智能合约在 Tenderly 中经过验证。

Web3 Actions 要求用于指定触发器的智能合约在 Tenderly 中经过验证。由于我们使用的是现有合约，您可以通过在搜索栏中输入合约名称或地址来查找它们。

或者，前往 [**UniswapV2ContractFactory**](https://dashboard.tenderly.co/contract/mainnet/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f) 并点击 **"Add to Project"**。对 [**UniswapV2Pair**](https://dashboard.tenderly.co/contract/mainnet/0xd849b2af570ffa3033973ea11be6e01b7ba661d9) 执行相同操作。

### 2：为 PoolCreated 事件创建 Web3 Action

以下是我们 Web3 Action 的代码以及它如何工作的说明：

```typescript title="example.ts" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}


export const onPoolCreatedEventEmitted: ActionFn = async (context: Context, event: Event) => {
  try {
    const txEvent = event as TransactionEvent;

    const eventLog = await getPoolCreatedEvent(txEvent);

    const tokensData = await getTokensData(eventLog.token0, eventLog.token1);
    console.log('Received Tokens Data: ', tokensData);

    await notifyDiscord(`${tokensData.token0.name} ↔️ ${tokensData.token1.name}`, context);
  } catch (error) {
    console.error(error);
  }
};

const getPoolCreatedEvent = async (txEvent: TransactionEvent) => {
  const ifc = new ethers.utils.Interface(UniswapV3FactoryAbi);
  const poolCreatedTopic = ifc.getEventTopic('PoolCreated');

  const poolCreatedEventLog = txEvent.logs.find(log => {
    return log.topics.find(topic => topic == poolCreatedTopic) !== undefined;
  });

  if (poolCreatedEventLog == undefined) {
    throw Error('PoolCreatedEvent missing');
  }
  return ifc.decodeEventLog(
    'PoolCreated',
    poolCreatedEventLog.data,
    poolCreatedEventLog.topics,
  ) as unknown as UniswapPool;
};

const getTokensData = async (token0: string, token1: string) => {
  const tokenFields = `id, name, symbol, totalValueLocked, totalSupply, derivedETH`;
  const theGraphQuery = `
{
	token0: token(id:"${token0.toLowerCase()}"){${tokenFields}},
	token1: token(id:"${token1.toLowerCase()}"){${tokenFields}}
}`;

  const UNISWAP_THE_GRAPH = 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3';
  const resp = await axios.post(UNISWAP_THE_GRAPH, {
    query: theGraphQuery,
  });

  return resp.data.data as unknown as {
    token0: UniwswapToken;
    token1: UniwswapToken;
  };
};

const notifyDiscord = async (text: string, context: Context) => {
  console.log('Sending to Discord:', `🐥 ${text}`);
  const webhookLink = await context.secrets.get('discord.uniswapChannelWebhook');
  await axios.post(
    webhookLink,
    {
      content: `🐥 ${text}`,
    },
    {
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    },
  );
};

type UniswapPool = {
  token0: string;
  token1: string;
  fee: number;
  tickSpacing: number;
  pool: number;
};

type UniwswapToken = {
  id: string;
  name: string;
  symbol: string;
  tokenValueLocked: number;
  totalSupply: number;
  derivedEth: number;
};
```

**获取新创建池中的代币。** 为了获取新池中两个代币的信息，我们需要在 `getEventLog` 函数中搜索事务日志。我们使用 Ethers 和合约的 ABI：`UniswapV3FactoryAbi`。前往 [**Tenderly 中的**](https://dashboard.tenderly.co/nenad/uniswap/contract/mainnet/0x1f98431c8ad98523631ae4a59f267346ea31f984) `UniswapV3Factory` 合约，点击 **"View ABI"**，将其复制/粘贴到 `actions` 目录中的本地文件。

基本上，我们要查找 topic `PoolCreate` 中的日志条目。首先，我们获取该 topic 的引用（`poolCreatedTopic = ifc.getEventTopic("PoolCreated")`），然后过滤实际日志（`tx.logs`），直到找到引用该 topic 的条目。最后，我们使用 Ethers 解码找到的日志（`poolCreatedEventLog`）。这就是我们要找的事件，它包含代币的地址：`token0` 和 `token1`。

**使用 TheGraph 上的 Uniswap Graph API 获取代币数据。** Uniswap 通过 [**TheGraph**](https://thegraph.com/hosted-service/subgraph/uniswap/uniswap-v3) 公开其数据的访问。我们使用 `getTokensData` 函数查询 TheGraph，获取来自第一步 `PoolCreated` 事件中 `token0` 和 `token1` ID 的若干字段。

**通知 Discord 社区。** 收集了所有相关信息后，我们准备向 Discord 频道发送消息。在 `notifyDiscord` 函数中，我们需要从 `secrets` 中获取 Webhook URL。我们使用 Axios 发起 HTTP POST 请求以运行 Webhook 并传递内容。

### 3：配置您的 Web3 Action

在 `tenderly.yaml` 文件中，我们需要指定当从 `UniswapV3Factory` 合约（地址为 `0xd849b2af570ffa3033973ea11be6e01b7ba661d9`）在 Mainnet（网络 1）上打包的事务中触发事件时，运行 `uniswapActions:onPoolCreatedEventEmitted`。

```yaml title="example.yaml" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
account_id: ''
actions:
  YOUR_USERNAME/YOUR_PROJECT_SLUG:
    runtime: v1
    sources: actions
    specs:
      uniswapNewPool:
        description: Runs when a new swap is made on Uniswap
        function: uniswapActions:onPoolCreatedEventEmitted
        trigger:
          type: transaction
          transaction:
            status:
              - mined
            filters:
              - network: 1
                eventEmitted:
                  contract:
                    address: 0xd849b2af570ffa3033973ea11be6e01b7ba661d9
                  name: PoolCreated
project_slug: ''
```

### 4：在 Secrets 中存储 Discord Webhook URL

在 Tenderly 中运行我们的 Web3 Action 之前，我们需要为 Discord Webhook 设置值。

在 Tenderly Dashboard 中，前往您项目的 Actions 页面并点击 Secrets。添加一个名为 `discord.uniswapChannelWebhook` 的新 secret，并粘贴您 Discord 频道的 Webhook。

### 5：部署并试用您的 Web3 Action

通过运行以下命令部署您的 Web3 Action：

```yaml title="example.yaml" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
tenderly actions deploy
```

**要试用您的 Web3 Action 是否正常工作，请前往 Tenderly Dashboard 中的 Actions 页面。选择您的 Action 并点击 Manual Trigger。**

就是这样！希望您已经在您的 Discord 频道上收到了消息 🎉
