如何构建符合反洗钱和反恐融资合规要求的安全去中心化应用程序(dApp)

  • QuickNode
  • 发布于 2025-03-21 16:23
  • 阅读 317

本文介绍了如何构建一个符合反洗钱(AML)和打击恐怖主义融资(CFT)规范的去中心化金融(DeFi)质押去中心化应用(dApp),使用了QuickNode的风险评估API和Chainlink Functions,将外部数据集成到智能合约中。通过此指南,开发者可以理解在去中心化应用中实施合规性检查的重要性、评估钱包风险的方式以及如何在EVM网络上部署相应的dApp。

概述

遵守反洗钱(AML)反恐融资(CFT) 法规在去中心化金融(DeFi)中已成为一种优先事项。监管检查在增加,区块链项目必须实施安全措施以防止非法金融活动。你即将构建的应用程序利用 QuickNode 的风险评估 API 来评估钱包的风险配置,并使用 Chainlink Functions 将这些链下数据引入智能合约。

本指南将引导你构建一个符合 AML 和 CFT 的质押 dApp,该 dApp 集成了 QuickNode 的风险评估 API 和 Chainlink Functions,以在前端智能合约层面实施安全策略。无论你是一个新的 DeFi 合规性开发者还是经验丰富的区块链工程师,本指南都将帮助你理解在 dApp 中实施合规检查的原因、内容和方法。

免责声明

本指南中提供的智能合约和代码仅用于教育目的,没有经过审计。在未经彻底测试、审计和安全审查之前,不应在生产环境中使用。

你将学习到什么

  • 为什么 AML/CFT 合规性在 DeFi 中至关重要
  • 如何使用 QuickNode 的风险评估 API 评估钱包风险
  • 如何使用 Chainlink Functions 在链上实施合规性
  • 如何在 Base 主网(或其他 EVM 网络)上部署符合 AML 和 CFT 的质押 dApp

你需要的东西

为什么 AML 和 CFT 合规性很重要

区块链的匿名和无需许可的特性使其在合法和非法金融活动中都具有吸引力。全球各地的当局正在收紧监管,以打击 DeFi 中的欺诈、制裁违规和恐怖融资。

遵守 AML 和 CFT 法规可能是区块链项目的战略必要性。理由如下:

  • 监管要求: 各国政府和金融监管机构越来越关注加密货币和 DeFi。不遵从可能导致法律行动、罚款,甚至项目关闭。
  • 风险缓解: 如果没有合规检查,dApp 可能成为洗钱或恐怖融资的通道,使平台面临非法活动和声誉损害的风险。
  • 用户信任: 实施合规措施表明了对安全和合法性的承诺,从而在用户和机构之间建立信任。
  • 未来保障: 随着法规的收紧,现在在你的 dApp 中嵌入合规性可以简化未来要求的适应。

QuickNode 的安全插件

QuickNode 市场 提供两种强大的安全插件,以帮助开发者实施合规性:

该插件分析链下数据(例如,交易模式、已知关联)以为钱包地址分配风险分数(0–100)。较低的分数表示更高的风险,还有其他细节如严重性和实体类型(例如,“制裁名单”)。这是你即将构建的应用程序中使用的插件。

该插件利用 AI 驱动的风险分析高效监控钱包风险,提供风险分数、实体标签,并标记可疑活动,以确保交易的安全和合规。它使用 AI 解析交易行为并识别各方,提供准确的钱包风险分数和实体标签(例如,“已知交易所”或“嫌疑诈骗者”)。钱包风险检查器访问一个巨大的全球制裁名单数据库,包括美国 OFAC、联合国、加拿大、英国、欧盟、瑞士和澳大利亚,并从主要区块链网络和全球情报源提取数据。

风险评估 API 和钱包风险检查器都通过简单的 API 调用提供风险分数和实体标签,使它们易于集成到应用程序中进行合规检查。它们都着眼于 AML/CFT 合规,利用链下数据评估钱包风险。对于本指南,我们关注于风险评估 API,但请注意,可以通过最小的调整将钱包风险检查器替换使用。

链上合规性的挑战

在前端使用这些插件阻止用户交互非常简单,只需进行 API 调用并检查响应。然而,在智能合约层面实施合规性需要弥合链下数据和链上逻辑之间的差距,因为它们在一个隔离的环境中操作,无法直接访问像 API 这样的外部数据源。

为了解决这个问题,我们需要一种安全的去中心化解决方案从智能合约获取和传递链下数据。这就是 Chainlink Functions 的作用。

Chainlink Functions 的工作原理

Chainlink Functions 是一种去中心化的预言机解决方案,旨在将智能合约与外部数据源和链下计算连接起来。

对于不熟悉 Chainlink Functions 的开发者来说,它扩展了 Chainlink 预言机网络的能力,通过在安全、去中心化的环境中执行自定义 JavaScript 代码。该代码可以与 API 交互、处理数据,并将结果返回到区块链,同时保持去中心化预言机网络的信任性和可靠性。

Chainlink Functions Diagram来源:Chainlink Functions 文档

在 AML 和 CFT 合规 dApp 的背景下,Chainlink Functions 在实现链上合规性方面发挥着关键作用,通过连接智能合约和 QuickNode 风险评估 API 来弥合二者之间的差距。其工作原理如下:

  • 自定义 JavaScript 执行: Chainlink Functions 允许开发者编写在链下运行的 JavaScript 代码(例如,source.js)。在此 dApp 中,代码通过钱包地址调用风险评估 API,提取响应中的 score 字段(例如,{"score": 1, "severity": "CRITICAL_RISK"}),并将数值风险分数返回给区块链。
  • 去中心化执行: 该 JavaScript 任务由 Chainlink 去中心化预言机网络(DON)执行,确保计算是在去中心化和防篡改的方式下进行,避免单点故障。
  • 安全回调机制: 一旦获取到风险分数,Chainlink Functions 会通过 fulfillRequest 回调函数将其发送到智能合约。这会更新 RiskBasedStaking.sol 合约中的 riskScores 映射,启用链上合规性执行。
  • 秘密管理: Chainlink Functions 使使用秘密(例如,QuickNode 端点 URL)变得更加容易,支持 DON 托管或用户托管的 托管方法。这确保 API 凭据保密,不会在链上暴露,从而增强安全性。
  • 订阅模型: Chainlink Functions 采用订阅模型,允许智能合约在每次请求中无需进行 LINK 代币转账。

项目架构和数据流

该 dApp 的架构无缝集成了前端、智能合约和预言机组件。以下是数据流:

  1. 用户交互: 用户将他们的钱包连接到 Next.js 前端并发起风险检查。
  2. 前端 API 调用: 前端触发对 /api/check-risk 路由的请求。
  3. Chainlink Functions 请求: API 路由使用 Chainlink Functions 工具包向 Chainlink 网络发送请求。
  4. API 调用: Chainlink Functions 执行一个 JavaScript 任务,通过钱包地址调用风险评估 API。
  5. 风险分数检索: API 返回风险分数(例如,{ "score": 1, "severity": "CRITICAL_RISK" })。
  6. 智能合约更新: Chainlink Functions 调用智能合约的 fulfillRequest 函数,更新钱包的风险分数。
  7. 合规执行: 智能合约执行质押规则(例如,风险分数 < 阈值)。
  8. 前端更新: 前端反映更新后的风险分数和质押状态。

RiskBasedStaking.sol风险评估 APIChainlink FunctionsAPI (api/check-risk)Next.js 前端用户RiskBasedStaking.sol风险评估 APIChainlink FunctionsAPI (api/check-risk)Next.js 前端用户交互触发 api/check-risk发送请求调用风险评估 API返回分数更新风险基础质押合约执行规则

理解智能合约和 Chainlink 函数

在进入部署部分之前,了解智能合约和 Chainlink Functions 集成的组件至关重要。本节提供有关智能合约和 API 如何协同工作更多的细节。

智能合约概述:RiskBasedStaking.sol

RiskBasedStaking.sol 智能合约管理质押操作,通过 Chainlink Functions 获取的风险分数执行合规。它确保存款中的钱包仅限于具有可接受风险水平的钱包。

关键状态变量
  • stakedBalances:一个映射(address => uint256),跟踪每个用户存入的 ETH。
  • riskScores:一个映射(address => uint256),存储每个钱包的风险分数。0 的分数表示该钱包尚未被检查。
  • riskThreshold:一个 uint256 值(例如,30),表示质押所需的最低风险分数。较低的分数表示更高的风险。
  • pendingRequests:一个映射(address => bool),防止同一用户的重复风险检查请求。
  • s_lastRequestId, s_lastResponse, s_lastError:存储最近的 Chainlink Functions 请求 ID、响应和错误的变量,用于调试。
核心函数
  • isAllowedToStake(address user)

    • 目的:检查用户是否可以质押。
    • 逻辑:如果用户的 riskScores[user] 大于 0(即已检查)并至少等于 riskThreshold,则返回 true
    • 用法:由 stake() 调用以执行合规性。
  • sendRequest(...)

    • 目的:发起 Chainlink Functions 请求以获取风险分数。

    • 访问:限制为合约所有者(onlyOwner)。

    • 参数:包括 source(JavaScript 代码)、args(用户地址)、subscriptionIdgasLimit

    • 逻辑

    • 确保仅提供一个参数(用户地址)。

    • 如果 pendingRequests[user]true 则防止重复请求。

    • 使用 Chainlink 的 FunctionsRequest 库初始化并发送请求。

    • 通过映射 s_lastRequestId 跟踪请求。

    • 事件:发出 RiskCheckRequested(user, requestId)

  • fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err)

    • 目的:处理 Chainlink Functions 响应。

    • 访问:内部,由 Chainlink 自动调用。

    • 逻辑

    • requestToUser[requestId] 获取用户地址。

    • 清除 pendingRequests[user]

    • 如果没有错误(err.length == 0),解码 responseuint256 风险分数,更新 riskScores[user],并发出 RiskScoreUpdated(user, score)

    • 存储响应/错误并发出 Response(requestId, response, err)

  • stake()

    • 目的:允许用户在通过风险检查后质押 ETH。

    • 逻辑

    • 检查 riskScores[user] 是否为 0

      • 如果 pendingRequests[user]true,则回滚并返回 PendingRiskCheck
      • 否则,回滚并返回 NoRiskScore
    • 如果 riskScores[user] &lt; riskThreshold,则回滚并返回 RiskyAddress

    • 更新 stakedBalances[user]totalStaked,然后发出 Staked(user, amount)

  • withdraw(uint256 amount)

    • 目的:允许用户提取已质押的 ETH。

    • 逻辑

    • 确保 stakedBalances[user] >= amount,否则回滚并返回 InsufficientBalance

    • 更新余额并将 ETH 转移给用户。

    • 发出 Withdrawn(user, amount)

Chainlink Functions 集成:/api/check-risk

/api/check-risk 路由连接前端和智能合约,使用 Chainlink Functions 工具包触发风险评估。它处理链下请求过程并用结果更新合约。

关键配置
  • routerAddress:Chainlink Functions 路由器地址(例如,Base 主网的 0xf9B8fc078197181C841c296C876945aaa425B278)。
  • donId:去中心化预言机网络(DON) ID(例如,fun-base-mainnet-1)。
  • gatewayUrls:上传密钥到 Chainlink 网关的 URL。
  • source.js:Chainlink Functions 执行的 JavaScript 代码,调用风险评估 API 并返回风险分数。
  • secrets:包含敏感数据的对象(例如,QUICKNODE_ENDPOINT),加密并上传到 DON。

Chainlink Functions Playground 是一个出色的工具,可用于测试和调试源代码。你可以用它来模拟请求并查看响应。

Chainlink Functions Playground

流程
  1. 读取源代码: 路由从文件系统读取 source.js,该代码定义了通过用户地址调用风险评估 API 以提取风险分数的逻辑。

  2. 设置签名者: 使用 ethers.jsPRIVATE_KEY(存储在 .env 文件中)创建一个钱包,并将其连接到 QuickNode 提供者(QUICKNODE_ENDPOINT)。

  3. 管理密钥: SecretsManager 加密 secrets 对象(例如,QUICKNODE_ENDPOINT)并使用指定的 slotId 和到期时间将其上传到 DON。

  4. 发送请求: 使用以下参数调用智能合约的 sendRequest

    • source.js 代码。
    • 加密密钥引用(slotIdversion)。
    • 用户地址作为 args
    • Chainlink 订阅 ID 和 gas 限制。
  5. 监听响应: ResponseListener 等待 Chainlink 的响应。使用 decodeResultresponseBytesHexstring 解码为 uint256 风险分数。

  6. 错误处理: 处理无效地址或 API 失败等错误,返回适当的 JSON 响应(例如,{ success: false, error: "无效的钱包地址" })。

现在,你已经理解了 dApp 的架构和组件,让我们来看看如何在本地机器或首选网络上设置它。

设置项目

虽然 Chainlink Functions 支持测试网进行实验(例如,Sepolia),但 QuickNode 的安全插件如风险评估 API 设计用于在主网上操作(你可以在它们的插件页面上确认支持的网络)。在本指南中,我们将在 Base 主网上进行部署,以确保与风险评估 API 的完全兼容。

按照以下详细步骤在本地或首选网络上设置 dApp:

第 1 步:克隆代码库

git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/sample-dapps/aml-and-cft-compliant-dapp

第 2 步:设置你的 QuickNode 端点

  1. QuickNode 注册并创建一个端点(例如,Base 主网)。
  2. 在你的端点中启用风险评估 API插件。这通过你的端点启用 sc_getAddressAnalysissc_getTransactionAnalysis 方法。
  3. 保存你的端点 URL。

第 3 步:配置 Foundry 并部署智能合约

  1. 安装 Foundry:
curl -L https://foundry.paradigm.xyz | bash
foundryup

这将安装 Foundry,一个用于以太坊智能合约开发的工具包,我们将使用它来编译和部署我们的合约。

  1. 导航到 Foundry 目录:
cd foundry
  1. 安装依赖: 安装 Chainlink Functions 集成和 Foundry 标准所需的依赖:
forge install smartcontractkit/foundry-chainlink-toolkit --no-commit
forge install foundry-rs/forge-std --no-commit

这些库提供用于与 Chainlink Functions 交互的工具和智能合约开发的标准实用工具。

  1. 创建重映射文件: 生成一个 remappings.txt 文件,以便在 Foundry 中正确映射已安装的依赖项:
forge remappings > remappings.txt
  1. 导入你的钱包: 安全地将你的钱包导入 Foundry,用于部署:
cast wallet import your-wallet-name --interactive

your-wallet-name 替换为你钱包的名称(例如,deployer)。你将被提示输入私钥并设置加密密码。--interactive 标志确保私钥不会以任何形式保存在你的 shell 历史记录中,以提高安全性。

  1. 设置环境变量:

.env.sample 复制为 .env 并进行更新:

BASE_RPC_URL=&lt;your-quicknode-endpoint>
BASESCAN_API_KEY=&lt;your-basescan-api-key>

BASE_RPC_URL 替换为你的 QuickNode 端点 URL,将 BASESCAN_API_KEY 替换为你的 BaseScan API 密钥。

检查 BaseScan API 密钥文档 以获取有关如何获取你的 BaseScan API 密钥的说明。

使变量生效:

source .env
  1. 更新部署脚本:

修改 script/RiskBasedStaking.s.sol 文件,将 Chainlink Functions router 地址更新为与你所选网络匹配的地址。请参考 Chainlink Functions 支持的网络 文档以获取适合你的网络的正确地址。

确保使用经过校验的以太坊地址,以避免部署错误。如果你不确定校验和验证,可以使用 地址校验和工具 来生成和验证正确的校验和格式。

script/RiskBasedStaking.s.sol

// 针对特定链的 Chainlink Functions 路由器地址
address router = 0xf9B8fc078197181C841c296C876945aaa425B278;
  1. 部署合约:RiskBasedStaking 智能合约部署到 Base 主网(或你选择的网络):
forge script script/RiskBasedStaking.s.sol:RiskBasedStakingScript --rpc-url $BASE_RPC_URL --account your-wallet-name --broadcast --verify -vvv

--verify 标志会在区块浏览器(例如,Basescan)上验证合约;如果你不想验证,可以将其删除。

合同部署

注意输出中的已部署合约地址——你将需要它进行 Chainlink Functions 和前端设置。

第 4 步:设置 Chainlink Functions 订阅

部署智能合约后,你需要设置Chainlink Functions 订阅,以允许合约请求风险评估。请按照以下步骤进行:

  1. 创建 Chainlink Functions 订阅

  2. 将你的智能合约添加为消费者

    • 一旦订阅设置完成,将你部署的合约地址添加为消费者。
    • 这将允许合约通过 Chainlink Functions 发起请求。
  3. 检查特定网络的详细信息

    • 每个网络都有自己的Functions 路由器地址DON ID(去中心化预言机网络)。
    • 请参考 Chainlink Functions 支持的网络 页面以查找适合你网络的正确值。
  4. 获取你的订阅 ID

    • 访问 Chainlink Functions UI 并选择你的订阅。
    • 从 URL 复制 订阅 ID,你将在下一步中需要它。

有关详细设置指南,请参阅 Chainlink Functions 文档

第 5 步:配置并运行前端

我们使用 Next.jsTypeScript 进行类型安全,使用 WagmiViem 进行钱包连接和智能合约交互,使用 Mantine UI 实现精美的 UI 设计。

  1. 导航到 Next.js 目录:
cd ../next-app

该目录包含前端代码,经过 Next.js 构建,支持服务器端渲染和 API 路由。

  1. 安装依赖:
npm install

此命令将安装 package.json 中列出的所有所需包。关键依赖项包括:

  • nextreact用于构建 Next.js 应用程序的核心库。
  • wagmiviem:以太坊钱包连接和智能合约交互的库,实现与区块链的无缝集成。
  • @mantine/core@mantine/hooks:Mantine UI 组件和Hook,用于构建现代响应式界面。
  • @chainlink/functions-toolkit:与 Chainlink Functions 交互的工具包,使用于 /api/check-risk 路由,以触发风险评估请求。
  • ethers:用于以太坊实用工具的库,支持对交易的签名和与智能合约的交互。

为什么需要同时使用 viemethers 因为 ethers 是 chainlink-functions-toolkit 的依赖,而 viem 是 wagmi 的依赖。我们需要两者来与区块链交互并执行钱包操作。

  1. 设置环境变量:
  • next-app 目录中创建一个 .env 文件以存储环境变量:

  • 添加以下变量:

WALLETCONNECT_PROJECT_ID=&lt;your-walletconnect-id>
PRIVATE_KEY=&lt;your-private-key>
QUICKNODE_ENDPOINT=&lt;your-quicknode-endpoint>
CONTRACT_ADDRESS=&lt;deployed-contract-address>
SUBSCRIPTION_ID=&lt;chainlink-subscription-id>

变量的说明和获取方法:

  • WALLETCONNECT_PROJECT_ID这为你 WalletConnect 项目 ID,启用前端钱包连接所需。请在 WalletConnect Cloud 上注册以创建项目并获取你的 ID(例如,a1b2c3d4...)。
  • PRIVATE_KEY指定用于签署 Chainlink Functions 请求的钱包的私钥。这可确保只有授权请求被发出,从而防止滥用你的 Chainlink 订阅。你可以使用步骤 3 中导入的同一钱包。安全地使用 MetaMask 或钱包 CLI 导出私钥,但绝不要公开它。
  • QUICKNODE_ENDPOINT你的含有风险评估 API 的 QuickNode RPC 端点 URL。你在步骤 2 中设置 QuickNode 端点时获得(例如,https://your-endpoint.quicknode.com)。
  • CONTRACT_ADDRESS已部署 RiskBasedStaking.sol 合约的地址。你在步骤 3 中运行部署脚本后记下(例如,0x1234...)。
  • SUBSCRIPTION_IDChainlink Functions 订阅 ID,允许访问风险评估请求。你将在步骤 4 中设置 Chainlink 订阅时获得(例如,1234)。
  1. 更新 Chainlink Functions 配置

src/app/api/check-risk/route.ts 文件中更新链和网络的正确路由器地址和 DON ID。

src/app/api/check-risk/route.ts

// Chainlink Functions 配置
const routerAddress = "0xf9B8fc078197181C841c296C876945aaa425B278";
const donId = "fun-base-mainnet-1";
const gatewayUrls = [
  "https://01.functions-gateway.chain.link/",
  "https://02.functions-gateway.chain.link/",
];
  1. 运行应用程序: 启动 Next.js 开发服务器:
npm run dev

此命令将以开发模式启动应用程序,并启用热重载以便更轻松調试。

测试应用程序

一旦你的 dApp 设置完成,可以通过浏览器界面访问并与之交互。

  1. 访问应用程序: 打开浏览器并导航到 http://localhost:3000 以与 dApp 交互。检查你的分数以测试应用程序的功能。
应用概述 带分数的应用概述
没有分数的概述 带分数的概述
  1. 验证 Chainlink Functions 订阅:
    • 前往 Chainlink Functions UI 以监控你的订阅。
    • 检查请求历史,以确保风险检查请求正在成功处理。

Chainlink Functions 请求

  1. 与智能合约交互:

查询智能合约中的 riskScores 映射,以确认你的风险分数已正确更新:

如果你是新的智能合约交互用户,可以按照我们的 与智能合约交互指南 了解如何使用 tools.js 或区块浏览器的界面读取和写入合约。

此验证确保风险评估 API 的风险分数在链上得到妥善反映。

附加步骤

要将你的 dApp 从一个可运行的原型提升到一个适合生产的应用程序,考虑以下实用改进:

  • 审计和安全性:

    • 进行 thorough 审计你的智能合约和 Chainlink Functions 集成,以识别和解决潜在漏洞。这将帮助确保应用程序的安全和可靠性。
  • 风险检查的速率限制:

    • 通过限制用户请求风险检查的频率来防止滥用。例如,对每个钱包地址施加每日 24 小时的冷却时间,以避免不必要地消耗你的 Chainlink 订阅的 LINK 余额。
    • 这个可以通过智能合约中的时间戳检查实现。
  • 优化 LINK 和交易成本:

    • LINK 成本: 监控你的 Chainlink 订阅中的 LINK 使用情况并设置余额警报。通过批量请求或降低风险检查频率来减少成本。
    • Gas 费用: 通过为 Chainlink Functions 请求设置恰当的 gasLimit 和最小化链上操作优化 gas 使用情况。
  • 用户体验增强:

    • 在风险检查期间添加加载指示器或实时通知,以使用户保持知情。
    • 利用来自风险评估 API 的元数据(例如,severityentityType)提供反馈,如果风险分数未达到阈值。
  • 安全最佳实践:

    • 安全管理你的 PRIVATE_KEY——切勿在客户端代码中暴露。使用专用签署钱包来进行 Chainlink 请求,并保持最小资金。
    • 考虑为关键更新(例如更改 riskThreshold)添加访问控制或多重签名要求。
  • 测试和验证:

    • 在可用的测试网(如有的话)上进行广泛测试,以修复错误,然后寻求专业审计,以确保 dApp 的安全和可靠。

结论

本指南为你提供了构建符合 AML 和 CFT 的 dApp 的步骤,使用 QuickNode 的风险评估 API 和 Chainlink Functions。你已经设置了质押界面,验证了 Chainlink 订阅和智能合约交互,并探讨了增强解决方案的方法。通过实施上述附加步骤,你可以创建一个不仅合规,而且高效、安全、用户友好的 dApp。

如果你有任何问题,请随时使用我们的 Discord 服务器或通过以下表单提供反馈。通过关注我们 Twitter 和我们的 Telegram公告频道,保持最新消息。

我们 ❤️ 反馈!

告诉我们 如果你有任何反馈或新主题请求。我们非常乐意听取你的意见。

附加资源

  • 原文链接: quicknode.com/guides/eth...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。