跳转到主要内容
本教程向您展示 如何使用 Web3 Action 在 Uniswap V3 上创建新池时向 Discord 频道发送消息。您可以使用此 Web3 Action 在链上发生事件时通知您的社区。
完整代码可在 此 GitHub 仓库 中获取。请注意,目前它位于一个单独的分支中。

项目概览

本项目的目标是教您如何使用 Web3 Actions 在创建 Uniswap 池时发送 Discord 消息。我们将向您展示两种方式 —— 更方便的方式是使用 PoolCreated 事件作为我们 Web3 Action 的触发器(参见 函数、事件和触发器 以及 Uniswap 文档)。

计划

  • 将合约添加到您的 Tenderly 项目 —— UniswapV3ContractFactory。它已经在 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 并点击 “Add to Project”。对 UniswapV2Pair 执行相同操作。

2:为 PoolCreated 事件创建 Web3 Action

以下是我们 Web3 Action 的代码以及它如何工作的说明:
example.ts


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 中的 UniswapV3Factory 合约,点击 “View ABI”,将其复制/粘贴到 actions 目录中的本地文件。 基本上,我们要查找 topic PoolCreate 中的日志条目。首先,我们获取该 topic 的引用(poolCreatedTopic = ifc.getEventTopic("PoolCreated")),然后过滤实际日志(tx.logs),直到找到引用该 topic 的条目。最后,我们使用 Ethers 解码找到的日志(poolCreatedEventLog)。这就是我们要找的事件,它包含代币的地址:token0token1 使用 TheGraph 上的 Uniswap Graph API 获取代币数据。 Uniswap 通过 TheGraph 公开其数据的访问。我们使用 getTokensData 函数查询 TheGraph,获取来自第一步 PoolCreated 事件中 token0token1 ID 的若干字段。 通知 Discord 社区。 收集了所有相关信息后,我们准备向 Discord 频道发送消息。在 notifyDiscord 函数中,我们需要从 secrets 中获取 Webhook URL。我们使用 Axios 发起 HTTP POST 请求以运行 Webhook 并传递内容。

3:配置您的 Web3 Action

tenderly.yaml 文件中,我们需要指定当从 UniswapV3Factory 合约(地址为 0xd849b2af570ffa3033973ea11be6e01b7ba661d9)在 Mainnet(网络 1)上打包的事务中触发事件时,运行 uniswapActions:onPoolCreatedEventEmitted
example.yaml
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:
example.yaml
tenderly actions deploy
要试用您的 Web3 Action 是否正常工作,请前往 Tenderly Dashboard 中的 Actions 页面。选择您的 Action 并点击 Manual Trigger。 就是这样!希望您已经在您的 Discord 频道上收到了消息 🎉