Autonomous Finance 推出第一款 AgentFi 应用

  • PermaDAO
  • 更新于 2024-05-15 13:24
  • 阅读 711

Autonomous Finance 在 AO 上推出第一个去中心化自主投资代理(Autonomous Investment Agent)应用,可以使用美元平均成本(DCA)策略在 AO 生态的各种流动性池中执行交易。

1.png 作者: Autonomous Finan

翻译: Jomosis

审阅: Tina


导读

Autonomous Finance 在 AO 上推出第一个去中心化自主投资代理(Autonomous Investment Agent)应用,可以使用美元平均成本(DCA)策略在 AO 生态的各种流动性池中执行交易。 自主投资代理拥有完全的自主性。一旦启动,其将会在 AO 生态上自主运行,无需链外信号或人为干预。用户可以通过前端界面配置代理的参数,包括定投资产种类、滑点范围、DEX 的 AMM 流动池等。存入资金后,启动即可自动运行,用户也可以随时修改参数或停止运行。本文除了介绍自主投资代理的概念以及使用方法,还为开发者提供了详细的代码示例,敬请阅读!

简介

这个软件是一个自主投资代理(AIA),它可以使用动态的定投(DCA)投资策略,在 AO 生态系统内的各种流动性池中执行交易。该代理会根据预设的、可由用户配置的间隔,使用一定数量的报价代币为每笔交易自动购买基础代币。

它最大的特点是功能自主性,这是 AO 网络独有的,对于自动化功能至关重要。一旦启动,它将在AO 平台上自主运行,无需离线信号或人为干预。

DCA 代理的管理界面通过托管在 Arweave 的 Permaweb 上的前端实现,并且无需信任的中间人。

DCA代理凭借其设计和技术堆栈,成为了第一个完全去中心化和抗审查的 AgentFi 应用程序。一旦部署,代理将按照编程方式运行,并且只能由其创建者停用。

如何使用

可以在 Permaweb 上访问最新的 DCA代理,或在 GitHub 上复刻代码仓库。

在创建时,首先配置您的代理

2.png

配置包括设置DCA参数、定义可接受的滑点范围,并选择DEX(AMM流动性池)进行交换。

只要有足够的报价存入代币,您的代理将执行 DCA 买入的操作:

3.png

仪表板为代理所有者提供以下功能:

  • 详细的配置和资产信息
  • 提取和清算资产的选项
  • 对于代理历史和性能的评价
  • 生命周期管理操作,如暂停、退役或转移代理

所有者控制权

  • 您的资产由代理安全持有,并始终保持100%的流动性,允许随时提取。
  • 作为概念验证,代理的所有权可以转移到另一方。
    • 所有者可以是常规用户或其他 AO 进程。它使用多重签名,并能与其他代理类型进行组合的特性增加了 DCA 代理的兼容性。

我们的愿景

DCA 代理充当更进一步发展的基础蓝图,旨在促进更复杂的多代理配置。虽然处于初始阶段并不断改进,但它挑起了执行大部分特定应用的重担,为有远见的构建者提供了重要的先机。

随着 AO 自主金融生态系统的发展,我们预期会为 DCA 代理和 AIAs 开发更先进和复杂的功能。由于其高度可配置性和可组合性,DCA 代理可以轻松地定制并集成到多代理配置中。想象一下,通过简单地集成 DCA 代理,作为策略的一部分,即可将 AIA 包括在其中。

以下是关于 DCA 代理未来潜力和可组合性的一些思考。

高级交易能力

  • DCA 代理能够根据高度可定制的参数执行高级交易策略:
    • 基于价格行动的购买(%偏差)。
    • 固定间隔和加权时间的操作(在价格较低时购买更多)。
    • 数据驱动的利润获取和利润再投资信号。
  • 当前版本的 DCA 代理使用单个流动性池进行交换。然而,多元化流动性来源和开发全球 RFQ 系统的计划正在进行中。这些优化将不仅自动化购买过程,还将确保在 DEX 和私人做市商之间聚合最佳的交换价格。

提升可组合性

DCA 代理已经具有高度可组合性,为了获得更大的灵活性,还可以探索一些替代方案。其中一种方法涉及到永不托管用户资金的代理。在这种模型中,多个专门的代理只有在出现盈利机会时会被授予访问用户资金的权限。例如,DCA 代理可能访问获得许可的资金,执行盈利交易,然后将资金返回给用户的自托管钱包。

这种方法显著提高了资本效率。用户不需要将资本锁定在特定的策略或池中;相反,他们授权代理使用预定义金额的资金,在任何代理执行盈利行动之前,这些资金仍然可供用户使用。

技术见解与经验教训

通过对 DCA 代理的初步开发,我们对 AO 平台有了更深入的了解,包括其能力限制。这个过程也让我们对适用于 DCA 代理开发的有效设计模式有了重要的见解。

我们将在即将发布的文章中详细阐述这些见解。

功能范围

这个项目作为新兴的 AgentFI 领域中的基础示例,展示了如何通过一个无需第三方工具或基础设施的无需信任、完全链上的过程来管理自主投资。它旨在为社区搭建更复杂代理的起点。

我们的意图是以更健壮的设计迭代这个基础,使用高级模式,这些模式将在更多的文章和蓝图中进行阐述。

目前项目的版本包括:

  1. 一个最小可行的 DCA 代理
  2. 一个在 AO 上的后端处理,便于聚合和管理DCA代理。
  3. 一个基本的 Web 界面用于管理代理,可以作为静态网站部署在永久网络上。

未来,我们计划扩展功能,包括与 DEXI 更紧密集成 - 这是我们的应用程序,允许 DeFi 用户浏览和发现 AO 生态系统。

可扩展性

未来版本的代理可能包括以下功能:

  1. 在固定时间间隔下的扩展配置,如提供流动性策略和重新平衡前五大代币指数。
  2. 由特定外部信号触发的复杂任务,这些任务将有效地重用基本功能,如存款、提款、清算和生命周期管理(暂停、退役、转移所有权)。
  3. 作为一个投资基金运作,利用各种策略,并为一群权益证明者提供服务,而不是单一所有者。

提供 DCA 代理活动历史的可视化,包括每次与 AOLINK 相关的链接,将允许所有者通过其唯一 ID 检查每次交换。

  • 实现此功能将涉及将与 DCA 购买和交换回购相关的最终信用通知的 ID 持久化,使所有者可以通过其唯一 ID 检查每次已完成的交换。

重要自动化 - AO Cron

AO 平台通过原生的任务支持自动化,在 dApp 开发领域有着独特的优势。开发者可以设置完全基于链上运行的计划任务,这对于实现金融代理的完全自主性至关重要。

鉴于仍在致力于不断增强 cron 计划任务能力和可靠性,现在确定最佳实践还为时过早。但是,在当前阶段,我们可以分享一个在当前阶段相关的见解。

直接触发 vs. 间接触发

我们设计了一种称为直接触发的模式,用于在简单情况下利用 cron计划任务,这种情况仅需要定期执行一次操作。在这种情况下,进程在创建(或生成)时被标记以接收 cron 时钟信号。而触发的信号频率由一个参数确定。

4.png

直接触发

// spawning cron process from @permaweb/ao-connect

const signer = createDataItemSigner(window.arweaveWallet)

const process = await ao.spawn({
  module: "SBNb1qPQ1TDwpD_mboxm2YllmMLXpWw4U8P9Ff8W9vk",
  scheduler: "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA",
  signer,

  // -- configure cron
  tags: [
    { name: "Cron-Interval", value: "1-minute" },
    { name: "Cron-Tag-Action", value: "TriggerSwap" },
  ],
})

// Turn on monitoring to activate cron triggering
await monitor({
  process,
  signer,
})

/*
 * As a result, our process starts receiving cron ticks once per minute.
 * If it has a handler that matches { "Action" : "TriggerSwap" }
 * these ticks will execute said handler.
 */
-- process.lua

Handlers.add(
  "triggerSwap",
  function(msg)-- ensure only authentic cron ticks are matched
      return Handlers.utils.hasMatchingTag("Action", "TriggerSwap")(msg)
          and msg.Cron
  end,
  function(msg)-- ... perform swap
  end
)

在需要定期执行多种类型动作的场景中,我们采用一种间接触发模式。这种方法使用独立的过程作为触发-通知器。这些是简单的 cron 驱动的代理,它们会提醒主要过程执行其任务。

这种模式的一个实际用例,它用于管理重新尝试失败消息传递的 DCA 代理。该代理:

  • 在固定间隔内执行 DCA 购买。
  • 在这些间隔内监视自身状态,以处理任何在预定超时内未收到响应的请求。

5.png

间接触发

-- swap_notifier.lua

Agent = Agent or nil -- set after creation via dedicated handler

Handlers.add(
  "cron",
  function(msg)return Handlers.utils.hasMatchingTag("Action", "Cron")(msg)
          and msg.Cron
  end,
  function(msg)
    ao.send({Target = Agent})
  end
)

-- retry_notifier.lua

-- analogous to swap_notifier.lua, but handler execution is
-- ...
    ao.send({Target = Agent})
-- ...

-- process.lua

SwapNotifier = SwapNotifier or nil -- set via handler after notifier is spawned
RetryNotifier = SwapNotifier or nil -- set via handler after notifier is spawned

Handlers.add(
  "triggerSwap",
  function(msg)return msg.From == SwapNotifier
  end,
  function(msg)-- ... perform swap
  end
)

Handlers.add(
  "checkQueue",
  function(msg)return msg.From == RetryNotifier
  end,
  function(msg)-- ... perform check on retry queue
  end
)

在实施间接触发模式时,对于主要过程来说,识别其触发-通知器的身份变得至关重要,以确保它不会被冒名顶替者激活。

此外,这种模式在更新 cron 时钟间隔方面具有战略优势,这在单个 cron 操作情景下是无法实现的。虽然 cron 间隔在创建时被设置为进程标记,并且之后无法更改,但使用间接触发允许灵活性。通过简单地生成一个具有不同间隔的新触发-通知器,就可以轻松调整任务的时间安排。

其他 Cron 注意事项

  • Cron 进程需要主动监控以正确运行并确保实时触发。监控和取消监控功能可以有效地切换实时cron 任务触发的开关。目前,监控只能通过 AO Connect 中的过程发起或停止,而不能在 Lua 处理器中执行。
  • 有时,由 cron 任务执行触发的消息可能会在消息传输单元之间滑过,导致触发执行时的轻微不一致或延迟。我们预计随着主网发布的临近,改进将带来更大的稳定性。

AO 应用架构

在接下来的部分中,我们将主要探讨对我们项目至关重要的 AO 进程。我们可能还会重点介绍前端功能,或深入探讨体现技术价值的实施细节。

我们的项目围绕两个对 DCA 代理应用至关重要的关键 AO 进程构建:

  1. 带有 Cron 任务触发器的代理进程
    • 促进用户触发和自动 DCA 购买,包括:
      • 存款
      • 取款
      • DCA交换
      • 清算(交换回购和取款)
    • 通过状态机隔离资产上的动作
    • 跟踪两种代币的资金余额
    • 向 AO 进程(后端)更新已完成的操作
  2. AO 进程(后端)
    • 管理与所有者关联的代理的注册和跟踪
    • 通过与代理的集成跟踪每个代理的历史数据

这些进程与以下组件交互:

  • 报价代币
  • 基础代币
  • AMM 池(特定于所选的报价和基础代币)

6.png

DCA 代理,后端以及相关的进程

交换

下面的图表展示了 DCA 购买的架构流程,其中发生了从报价代币到基础代币的交换。这种可视化有助于详细描述此类交易中的步骤和交互。

7.png

DCA 购买的步骤

在相反方向的代币(从基础到报价两方)进行兑换时,涉及到的消息序列与 DCA 购买类似,这在代理资产清算中起着关键作用。

代理进程安全地持有资金,需要存款来促进 DCA 购买。在执行交换后,它保留了所得到的资产,确保所有资产保持流动性(即,用户随时可以提取)。

代理与后端

目前,ao 后端进程与代理紧密耦合。我们设想标准化这两个组件,使它们可以轻松地与其他组件进行交换,同时保持系统兼容性。然而,鉴于我们特定的目标是将这些代理与 DEXI 集成,我们决定将DCA 代理和后端的标准化推迟到未来的迭代中。

前端架构

前端利用 Arweave 网关与 AO 进程进行交互。它与以下组件进行交互:

  • 代理执行操作。
  • 代理的后端进程检索所有关联的代理。
  • DEXI 访问可用的 AMM 池信息并获取最新价格。

8.png

前端架构概述

Web 前端支持基本的代理管理和交互,每个用户可以支持多个代理。为了保的独立性并增强去中心化,UI 设计为部署在永久网络上的静态网站。所有持久化数据存储在 AO 上,在AO 进程的状态中维护。

简单且安全的后端注册

为了简化操作,代理是独立生成的,并且它们的所有者可以在没有任何访问控制的情况下将它们注册到后端。这种设置是安全的,因为后端在其当前配置中不需要访问控制;也意味着它不能被滥用。注册的代理与其所有者的帐户关联,防止未经授权的注册污染其他用户的数据。

另一种方法可能涉及一个工厂设置,其中代理直接从后端生成。有关我们不采用此方法的更多详细信息,请参阅这里的讨论

-- backend.lua

Handlers.add(
  'registerAgent',
  Handlers.utils.hasMatchingTag('Action', 'RegisterAgent'),
  registration.registerAgent
)

-- registration.lua

mod.registerAgent = function(msg)local agent = msg.Tags.Agent
  -- ...
  local sender = msg.From

  -- 👇 registration only affects sender-related data
  -- => ok to do without access control
  RegisteredAgents[agent] = msg.From
  AgentsPerUser[sender] = AgentsPerUser[sender] or {}
  AgentInfosPerUser[sender] = AgentInfosPerUser[sender] or {}

  table.insert(AgentsPerUser[sender], agent)
  table.insert(AgentInfosPerUser[sender], {
     -- ...
  })
  response.success("RegisterAgent")(msg)
end

不选择使用工厂模式的原因

尽管将后端设计为生成代理的工厂是可行的,但我们发现这种方法对用户来说更加繁琐。因此,我们选择了非工厂设置。然而,如果未来需要访问受控制的注册,返回到基于工厂的方法可能是一个可行的解决方案。

以下是在工厂版本中代理创建和注册将如何运作:

  1. 创建: 创建者(用户)通过工厂生成代理,包括一个唯一的创建 nonce。
    • 工厂尝试预注册代理进程。如果创建 nonce 不唯一,则此注册应失败。
  2. 确认: 创建者轮询后端进程,直到确认指定 nonce 的创建成功为止。
    • 在确认后,创建者获得生成的代理 ID。
  3. 初始化: 创建者初始化代理,从而成为其所有者。
    • 代理被完全初始化,其所有者已设定,并与后端进行完整注册,后端现在将代理视为可信进程。

前端的变化:

  • 用户与后端交互以创建新代理。
  • 用户轮询后端确认代理的预注册。
  • 注册和初始化过程在单个步骤中完成和确认。

这种方法确保了一个简化的过程,集成了安全性和用户便利性,如果未来需要转向工厂设置的话,则会更加方便。

进程所有权、托管和可组合性

在我们的实现中,用户通常作为代理的所有者开始,但所有权可以在初始化阶段转移,允许所有者是另一个进程。这种灵活性支持各种操作场景,例如:

  • 一个自主代理利用此代理执行 DCA 购买。
  • 一个多签钱包进程使用此代理进行 DCA 交易,有效地同时为多个共同所有者提供服务。

备选所有权模型: 一个有趣的备选所有权模型涉及一个不持有资金本身的代理,但被授权从另一个来源访问资金,比如一个负责维护这些资金的不同进程。

用例示例: 作为所有者,我可以利用多个代理来管理投资,而无需在它们之间分配资金。如果代理不是按固定间隔投资而是响应不可预测的信号,则这特别有用。这种设置不仅减少了操作开销,还提高了可用资金的有效利用率,提高了整体资本效率。

所有权和初始化 - AO vs. 以太坊

在 AO 中,每个进程都有一个全局变量 Owner ,在进程创建时自动分配。进程的所有者可以是钱包或另一个进程。

  • 当通过前端签名的消息生成一个进程时,就像我们的 DCA 代理那样,钱包 ID 成为进程的所有者。
  • 如果一个进程由另一个进程发起,那么发起进程会自动成为所有者。

所有权可以通过更新 Owner 的值来转移。我们通过增强我们的处理程序功能,类似于 Solidity 智能合约中常用的 onlyOwner 修饰符,将此机制纳入我们的应用程序中,以确保操作仅限于进程所有者。

-- process.lua

Handlers.add(
  "retire",
  Handlers.utils.hasMatchingTag("Action", "Retire"),
  function(msg)
    permissions.onlyOwner(msg)
    lifeCycle.retire(msg)
  end
)

...

-- permissions.lua

mod.onlyOwner = function(msg)assert(msg.From == Owner, "Only the owner is allowed")
end

初始化差异:AO 进程与以太坊智能合约

与以太坊智能合约不同,AO 进程没有构造函数。因此,为了使代理正常运行所需的任何比哟啊的初始化都必须通过后续消息执行。这个消息类似于常规消息,但是专门设计用于更新代理的状态。

为了管理初始化状态,我们采用一个IsInitialized标志。尚未初始化的进程将拒绝处理(几乎)任何消息。它们只允许:

  • 查询当前所有者。
  • 检查当前进程状态。
  • 执行初始化本身。

这种有选择性的消息处理是通过在 Handlers 列表的顶部放置一个 “catch-all” 消息处理程序来实现的。这种设置充当了门卫,确保进程在正确初始化之前不能执行或响应任何操作。

-- msg to be sent by end user or another process
Handlers.add(
  "initialize",
  Handlers.utils.hasMatchingTag("Action", "Initialize"),
  lifeCycle.initialize
)

-- ! every handler below is gated on Initialized == true
Handlers.add(
  "checkInit",
  function(msg)return not Initialized  -- the match is positive if we're not initialized yet
  end,
  response.errorMessage("error - process is not initialized")
)

DCA代理应用中的所有者初始化和安全性

在我们的 DCA 代理应用中,虽然创建代理的用户通常应该是所有者,但我们的目标是最大限度地提高可组合性和设置灵活性。这种方法允许将其他进程指定为 DCA 代理的所有者。此外,我们正在探索与 DEXI 的未来集成,使用户可以通过 DEXI UI 创建代理,使用潜在可信的代理工厂。这种设置理想情况下会分离生成进程的角色、成为真正所有者的角色以及执行初始化的角色。

在智能合约开发中,对初始化进行严格的访问控制通常是至关重要的,以确保只有指定的所有者可以执行初始化。然而,为了保持简单,我们选择了一种更加宽松的方法。

为了简化我们的设计,我们将“真正所有者初始化”和“DCA配置初始化”合并为单个“初始化”操作。在执行此初始化之前,代理保持“无用”。发送“初始化”消息的人将自动成为进程的真正所有者。

理论上,这种设计选择确实开启了恶意破坏的可能性。如果其他人在预设的所有者之前初始化进程,他们可能会控制它。然而,我们评估认为在 AO 上,与其他全局状态虚拟机平台相比,这种前置运行的风险要低得多。有关安全方面的更多信息以及为什么这个问题在 AO 上不那么突出,请参阅我们详细的安全讨论

状态管理

在我们的系统中,所有关键数据都直接存储在进程状态中,也就消除了通过 Arweave 网关进行查询的需要。

通过后端进程,我们可以轻松地检索每个用户的所有可用代理列表,包括关键信息,如购买和出售的历史记录。

为了确保在资产上执行的多步操作(如DCA购买、取款和清算)的原子性和隔离性,我们的代理松散地采用了状态机模型,类似于互斥锁。这个模型也跟踪相关的成功和失败。

IsSwapping = IsSwapping or false
IsWithdrawing = IsWithdrawing or false
IsDepositing = IsDepositing or false
IsLiquidating = IsLiquidating or false

LastWithdrawalNoticeId = LastWithdrawalNoticeId or nil
LastDepositNoticeId = LastDepositNoticeId or nil
LastLiquidationNoticeId = LastLiquidationNoticeId or nil
LastSwapNoticeId = LastSwapNoticeId or nil

LastWithdrawalError = LastWithdrawalError or nil
LastLiquidationError = LastLiquidationError or nil
LastSwapError = LastSwapError or nil

一个更高级的状态机将有助于跟踪每个特定的多步操作的进度。这种改进可以帮助开发开发一个 UI,为用户提供有关任何特定操作的准确进度。

目前,我们的代理提供的隔离性相当简单。如果在进行另一个操作时尝试执行资产操作,代理只会返回错误信息。

mod.checkNotBusy = function()local flags = json.encode({
    IsSwapping = IsSwapping,
    IsDepositing = IsDepositing,
    IsWithdrawing = IsWithdrawing,
    IsLiquidating = IsLiquidating
  })
  if IsDepositing or IsWithdrawing or IsLiquidating or IsSwapping then
    response.errorMessage(
      "error - process is busy with another action on funds" .. flags
    )()
  end
end

这里的示例展示了如何使用检查来实现类似互斥锁的行为:

Handlers.add(
  "withdrawQuoteToken",
  Handlers.utils.hasMatchingTag("Action", "WithdrawQuoteToken"),
  function(msg)
    permissions.onlyOwner(msg)
    status.checkNotBusy()
    progress.startWithdrawal(msg)
    withdrawals.withdrawQuoteToken(msg)
  end
)

更优化的行为是对触发资产操作的传入消息进行排队,而不是拒绝它们。这种变化将减轻触发实体重新尝试操作的频率,提升用户体验和系统效率。

保持前端同步

在为 AO 平台开发 JavaScript 时,需要注意没有直接订阅 AO 事件的方法——这是以太坊虚拟机开发中才有得常用功能,通过智能合约事件和 JavaScript 库(如 web3 和 ethers)实现。

对于我们的 DCA 代理 UI,一种方法涉及轮询 Arweave 网关端点,以获取带有特定标签的 AO 消息。然而,考虑到我们的代理在其进程内存中有大量重要的状态管理,我们选择直接从代理进程通过dryRun调用轮询更新。这个选择使我们的 UI 能够更准确地反映代理的实时状态,尽管需要额外的开销来管理 React Hook 以检测状态变化。目前,鉴于代理的复杂程度,这种复杂性是可管理的。

映射远程真实数据源

对于 DCA 代理,特别是对于更复杂的代理,保持对其操作相关数据的实时感知至关重要。例如,一个代理需要知道特定代币的余额,以便根据传入信号做出及时决策。

虽然代理可能会本地跟踪这种状态,但它也必须警惕由于分布式计算平台固有的无序性可能导致的潜在不一致。让数据随时可用有助于做出有效的实时决策,尽管代理必须不断检查和协调任何不一致之处。

动机和示例

考虑一个例子,其中一个代理被编程来响应两种类型的信号,AB信号A 表示异常的、高利润的机会,而 信号B 则定期发生。当检测到 信号A 时,代理应该使用其资金执行特定的交换。然而,这些资金也被用于由 信号B 触发的活动。挑战在于在为 信号A 最大化资金使用的同时,确保为 信号B 留有足够的储备。

这种情况强调了代理需要准确了解其代币余额的必要性,这可能因未记录的存款或第三方可能的取款而波动,如果 AO 代币进程曾支持类似于 ERC20 代币的批准。

尽管这个具体的挑战只出现过一次,但它代表了一个真实的机会损失风险,可能影响代理的竞争优势。因此,解决这个问题至关重要。

  • *解决方案:**为了解决这个问题,代理监听来自代币进程的任何 Credit-NoticeDebit-Notice,并回应一个 {"Action" : "Balance"} 消息来更新其余额。然后,它根据带有“Balance”标签的响应来更新其内部余额。

然而,由于缺乏有序消息保证,存在响应可能不对应最近的余额查询的风向。这可能错误地影响到本地镜像的余额。

我们的方法通过跟踪每次余额更新的时间戳来缓解这个问题。如果新的更新时间戳不晚于上次的更新时间戳,则代理会忽略这个更新,确保余额信息的完整性和准确性。

mod.latestBalanceUpdateBaseToken = function(msg)-- balance responses may come in any order, so we disregard delayed ones (possibly stale values)
  if (msg.Timestamp > LatestBaseTokenBalTimestamp) then
    LatestBaseTokenBal = msg.Balance
    LatestBaseTokenBalTimestamp = msg.Timestamp
    ao.send({ Target = Backend, Action = "UpdateBaseTokenBalance", Balance = msg.Balance })
  end
end

与AMM相关的安全性

1. 前置运行

在典型的去中心化金融平台中,DCA 代理对交换时间和金额的可预测性可能会引发前置运行的担忧,特别是在全局状态虚拟机中,交易可以被精确排序以利于攻击者,从而实施诸如夹击攻击之类的战术。然而,在 AO 上,情况则完全不同。

由于缺乏关于交易排序的保证,因此在 AO 上认为前置运行不太可能发生。尽管攻击者可能会尝试通过在 DCA 代理预定的 swap 交易周围安排其交易,来执行夹击攻击,但这些操作对其他人是可见的,后者可能会自行进行前置运行攻击,从而抵消攻击的盈利性。与传统 DeFi 设置相比,这种固有风险使得在 AO 上前置运行不是一种有效的策略。

2. 无需预言机的价格

在确定交换的预期输出时,AMM 池本身可以作为 AO 上定价的可靠来源。这与基于EVM的系统形成对比,后者在交换执行时依赖于池的价格,可能会让用户更容易被前置运行者利用。

在具有全局状态虚拟机的平台上,DeFi 应用程序通常依赖于外部预言机来减轻与操纵定价相关的风险。这些预言机本身则成为潜在的攻击向量。考虑到在 AO 上前置运行不太可能发生,因此对外部价格预言机的需求降低了,使我们能够直接依赖 AMM 池价格,而无需采纳其他 DeFi 环境中常见的外部预言机最佳实践。

挑战与解决方案

设计代理进程的一个关键挑战围绕着对传入消息的编码和处理。准确识别每条消息的目的对于适当的响应行动至关重要。

消息处理复杂性的示例:

来自Quote Token进程的Credit-Notice可能表示几种情况:

  • 成功的存款。
  • 从基础代币(Base) 到报价代币 (Quote) 的成功交换。
  • 因报价代币 (Quote) 到基础代币(Base)的交换失败而导致的退款。

为了解决这种复杂性,我们选择了增强处理程序内部匹配函数的粒度。这种方法使我们能够:

  • 精确识别每条消息的意图。
  • 在处理程序函数内部保持更干净和更有效的执行。

消息处理的区分确保了每个动作都被准确处理,提升了代理操作的整体稳健性和清晰度。

-- process.lua

--[[
    This file defines all the handlers.
    It should give a clear overview for understanding
    everything the process can do in terms of handling messages
--]]

--[[
    The handler below matches Credit-Notice messages from the BaseToken,
    but is not the only one doing so ==>> we use the patterns.continue()
    wrapper to allow for matching of other handlers, too
]]

Handlers.add(
  "balanceUpdateCreditBaseToken",
  patterns.continue(function(msg)return Handlers.utils.hasMatchingTag("Action", "Credit-Notice")(msg)
        and msg.From == BaseToken
  end),
  balances.balanceUpdateCreditBaseToken
)

--[[
    The handler below is another Credit-Notice matcher for messages from
    BaseToken. It uses an imported function to perform a match,
    but keeps the matching of the 'Action' Tag right here in explicit form,
    so that we can rapidly find all the 'Credit-Notice' handlers of the process.
    Furthermore, using the patterns.continue() wrapper has the effect that this
--]]

Handlers.add(
  'swapBackErrorByPool',
  function(msg)return Handlers.utils.hasMatchingTag('Action', 'Credit-Notice')(msg)
        and liquidation.isSwapBackErrorByRefundCreditNotice(msg)
  end,
  progress.concludeLiquidationOnErrorByRefundCreditNotice
)

-- liquidation.lua

mod.isSwapBackErrorByRefundCreditNotice = function(msg)return msg.From == BaseToken
      and msg.Sender == Pool
      and msg.Tags["X-Refunded-Transfer"] ~= nil
end

焦点放在核心问题上

在开发我们的代理时,我们策略性地决定省略一些通常用于在 AO 上创建生产级代理的最佳实践。这样做是为了集中我们的精力有效解决更具挑战性的问题。

未来改进的领域

  1. 输入验证:
    • 目前,代理对输入进行了最少的验证,例如检查地址输入是否为非空字符串。实施更高级的验证可以提升安全性和可靠性。
  2. 消息和处理程序的类型支持:
    • 代理和后端进程目前对消息和某些处理程序实用程序缺乏强大的类型支持。增强类型支持可以消除误报并提高代码可靠性(如msg.FromPatternFunction等)。
  3. Web 前端的用户体验:
    • 在以下方面有很大潜力改进用户体验:
      • 优化余额和当前价格的轮询。
      • 在成功的资产操作后实现余额的乐观更新。
  4. 启动/暂停功能和状态转换:
    • 启动/暂停功能和从“无资金”到“活跃”状态的转换不会触发即时操作,这意味着由于资金不足而“错过”的交换不会通过延迟交换进行补偿。虽然这种功能可能可取的,但它可能改变代理的DCA性质:
      • 用户可以通过频繁启动和暂停代理来操纵交换的频率,从而影响基于等间隔交换假设的性能指标。
      • 尽管对这些问题有潜在的解决方案,但它们被认为对当前的蓝图来说过于雄心勃勃,不适合包含在内。
  5. 防御性编程:
    • 通过捕获执行错误并正确完成操作,增强代理进程的健壮性可以使状态机标志保持一致的状态,从而增加系统的韧性。

这些省略是为了专注于提供一个功能原型,以解决核心功能,同时承认未来可以进行改进的领域。

最后的说明

感谢您抽出时间来探索我们在 AO 上开发 DCA 代理的复杂性。本文旨在公示我们的开发过程,分享我们当前的成就和我们计划改进的领域。我们希望这些见解能够增进对去中心化代理开发中挑战和潜在解决方案的深入理解,推动 AgentFi 领域的发展。

请继续关注我们随着技术的不断完善和新可能性的探索。我们致力于推进这一领域并分享我们的经验教训。

要获取更多信息,贡献意见或了解我们的进展,请访问以下资源:

  • 阅读我们的 博客
  • 贡献或探索我们在 GitHub 上的项目
  • 关注我们的 Twitter 以获取实时更新

我们对未来充满期待。请继续期待我们有关推动去中心化金融的边界更详细的文章和更新!


关于 PermaDAOWebsite | Twitter | Telegram | DiscordMediumYoutube

0.png

  • 原创
  • 学分: 0
  • 标签:
点赞 0
收藏 0
分享

0 条评论

请先 登录 后评论
PermaDAO
PermaDAO
0x40F9...8718
Arweave 生态系统的共建者 DAO。 @ArweaveEco will be adopted by more developers. All projects of Arweave ecology can post their tasks and rewards here. @everVisionHQ@permaswap@ArweaveSCP