Introducing the DCA/Limit Order Template Contract ready for PowerPool Automation

Mr FOS
PowerPool
Published in
5 min readApr 23, 2024

DCA stands for Dollar Cost Averaging — a strategy where an investor instead of investing the whole sum, gradually buys an asset in set increments. In blockchain, this is equal to the regular execution of swap transactions on a DEX of choice. There exist blockchain DCA instruments like Cowswap and Neon, however, they commonly lack the core feature present in PowerAgent — blockchain-native automated transaction execution. That means with this template, automated by the PowerAgent network, you as a token purchaser may enjoy the DCA strategy without ever leaving the blockchain and resorting to centralized automation protocols.

Limit orders, on the other hand, are a predefined action of buying or selling an asset when a set price threshold is met. For example, a limit order may be formulated as “buy 1 ETH when the price of ETH reaches 3050$”. Again, in the scope of decentralized finance, this action may be reformulated as “Execute the swap transaction as soon as the oracle of choice returns the desired price for the asset”.

The technical difference between a DCA strategy and a limit order is that a limit order is a one-time action, while the DCA is a recurrent action of buying the same asset no matter what price (however, the threshold may also be utilized to avoid buying the asset at a spike).

On the other hand, the implementation of the DCA or a limit order contract is basically the same. One may notice that the DCA strategy is a limit order without a price threshold, set to be repeated indefinitely (or at least while active). Hence, in this article, we describe an implementation of a combined DCA/Limit Order contract which is ready for deployment and automation by the PowerAgent network.

Limit Order/DCA Contract

In this prototype implementation, the contract acts as an intermediary between the person and the DEX pool. The contract must be topped up with the total amount of funds that a user wishes to spend on the strategy. Note that the regular top-up may be configured with another PowerAgent Job. We have chosen UniSwapV3 as the target protocol for swap execution, however, any DEX can be utilized by making the appropriate changes to the code and utilizing the correct interfaces. The contract is written in a generalized way that allows one to set up a recurring swap with either input or output amount known (i.e., either selling or buying tokens, resp.), the total expenditure regulated by the amount of funds allocated to the contract and the threshold set at possibly zero or the largest available number in order to make the contract be able to automate DCA orders as well as repeated limit orders.

Find the DCA/Limit Order Template contract on PowerPool’s GitHub: https://github.com/powerpool-finance/powerpool-research/tree/main/DCA

Main components

Initialization

When deployed, the contract is initialized with the following parameters:

  • uint256 delay — the time delay for the contract to be executable after the deployment
  • uint256 interval — the interval for DCA strategy (how often to perform swap operation)
  • uint256 threshold — the threshold price for the swap (if the price is higher/lower than the threshold, where the direction is dependent on the swap kind, the swap will not occur). Setting a threshold of 0 for selling (i.e., a lower bound of zero on the received token amount) or a threshold of type(uint256).max for buying (i.e., a maximal possible number as the upper bound on the price of the token to buy), you receive a pure DCA strategy with no price criteria.
  • bool highLow — this parameter chooses which way to swap the tokens (1 — sell, 0 — buy)
  • uint256 terminus — the timestamp for the end of the strategy (type(uint256).max for a strategy with indefinite lifetime)
  • uint256 amount — the amount of tokens to swap each time
  • bytes memory _path — the path for swap (see detailed description below)
  • uint256 tolerance — slippage tolerance

The _path variable is obtained as a packed encoding (abi.encodePacked(tokenIn_0, poolFee_0, tokenOut_0, poolFee_1, tokenOut_1…). In other words, this is a byte encoding of token addresses and pool fees, as per UniSwapV3 specification. The list of available pools and corresponding fees may be found here (https://info.uniswap.org/#/pools) or here (https://www.geckoterminal.com/eth/uniswap_v3/pools). The owner of the contract should provide this field on deployment.

Having deployed the strategy contract, the user is to supply it with a sufficient amount of tokens for a period of operations (as deemed expedient by the user) and possibly create an automated replenishment solution if he so desires. Thereafter, no user involvement is necessary (aside from possibly replenishing the input tokens) as the output tokens will automatically be deposited to his EOA upon the swap taking place. The user is also to invoke the setAllowance function to allow swaps to occur from the strategy contract before any swap Jobs can become operational.

Below are highlights of the core contract functionality.

Setting the path of the swap

The owner may change the path of the swap (i.e. what exact route to use) at any time. Refer to the Uniswap documentation (or the above section) for details.

Setting parameters of the DCA

The parameters may be changed at any time and the changes will be effective immediately. Note that, for example, changing the delay of an already working strategy will not have any effect.

Quoting

The contract’s quote function can be used to quickly check the output of a swap with parameters determined by the Job configuration. Quoting the price is also a part of the price Resolver check.

Temporal and price Resolvers

The Resolver has a temporal component and a price-dependent component. The former asserts that the specified delay has passed since the contract deployment, that the specified interval of time has passed since the most recent execution (beware that changing the interval will only have effect after the next execution event), and that the terminal time is yet to be reached. The latter asserts that the amount of tokens obtained by buying/selling is not too little relative to the amount of tokens expended as specified in the contract parameters.

The performSwap() function is the main function responsible for swapping tokens. It checks the temporal and price resolvers before executing the swap by calling the corresponding function of the UniSwap pool. This function is intentionally public as it is guarded by the resolver checks from inappropriate usage. Someone may call this function and pay for your swap, that is. This function is designed to be targeted by the PowerAgent Keepers during execution.

Limit Order / DCA Job

Creating the PowerAgent job to automate the DCA strategy is fairly straightforward. The owner of the contract registers a Resolver Job which checks on the resolver() function of the contract, targets the performSwap() function, and tops up the balance of the Job. After that, once the delay passes, the swaps will be performed automatically by the PowerAgent Keepers according to the parameters set by the owner. The parameters (s.a. terminal time, amount, slippage tolerance, etc.) may be changed at any time by interacting with the contract directly.

Twitter | Discord | YouTube |Telegram | CMC Community | Debank | Medium

--

--

Mr FOS
PowerPool

DePIN layer powering AI Agents and DeFi automation in multichain universe. https://powerpool.finance