This repository contains the UniV3Automan contract, serving Aperture's Uniswap V3 liquidity position automation product.
The automation product allows UniV3 liquidity position holders to schedule the following actions when certain conditions are met:
- Close an existing position.
- Rebalance a position to another price range.
- Reinvest a position, i.e., collect accrued fees and add to the position's liquidity.
Example of a supported condition: when ETH price remains above $2000 for at least 72 hours, according to Coingecko price feed.
Aperture's automation service keeps track of scheduled tasks, periodically check whether user-specified conditions are met, and trigger actions on-chain when conditions become satisfied.
The UniV3Automan
contract exposes external functions that allow Aperture's automation
service to trigger the three supported actions. Note that 'rebalance' may involve the need to perform a swap such that
the ratio of the two tokens meets the requirement of the new position's price range; similarly, 'reinvest' involves a
swap among the collected fees such that the two tokens' ratio matches what's in the liquidity position in order to add
liquidity. The OptimalSwap
library makes use of a closed form solution that finds
the optimal amount of token to swap in order to achieve a specified outcome of the two token's ratio, taking into
account the effect of the swap on the token amounts in the liquidity position.
Include an .env
file at the root directory and consider adding the following environment variables:
PRIVATE_KEY="" # used as the contract deployer.
MAINNET_RPC_URL="" # used to test UniV3 and PCSV3
BASE_RPC_URL="" # used to test Aerodrome SlipStream
First, the unit tests interact with Ethereum and Base mainnet where relevant contracts are deployed; you need to provide rpc
nodes (preferably Alchemy's) in a .env
file placed in the root directory of this repository.
Template:
MAINNET_RPC_URL="https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
BASE_RPC_URL="https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
Second, install Yarn and run yarn
to install dependencies.
Third, install Foundry. Install git submodules
forge install
When via_ir
is enabled in foundry.toml
, it takes one to two minutes to compile the project via
the IR pipeline. For faster compilation and testing, the lite profile can be enabled by setting the environment
variable FOUNDRY_PROFILE
to lite
which shortens the compilation time to about 10 seconds.
FOUNDRY_PROFILE=lite forge test
The tests may take anywhere between seconds to minutes to complete depending on whether contract storage slots in scope are cached.
In case of mysterious failures such as "failed to set up invariant testing environment", it may be caused by a Foundry issue. Try again with the following commands:
forge clean
forge build
forge test
To simulate scripts, we can pass in --fork-url <network>
to forge script
. The network
can be an
rpc_endpoints
defined in foundry.toml
or an url to a node.
forge script DeployUniV3Automan --fork-url [NETWORK_NAME] -vvvv
To run broadcast transactions on-chain, use:
forge script DeployUniV3Automan --rpc-url [NETWORK_NAME] --broadcast -vvvv
We use https://github.com/pcaversaccio/create2deployer to deploy contracts. If the network we want to deploy to doesn't currently have a create2deployer
deployment then we need to first contact the owner to deploy that.
First, dry-run the deployment script on a local fork to get the initCodeHash
of UniV3Automan
contract:
forge script DeployUniV3Automan --fork-url [NETWORK_NAME] -vvvv
The output of the above command should contain text like "Automan initCodeHash: 0xbafd4e1d1ff7f7979102d9e80884c2a93d0e1160dae77b5f88e9bca95eb5e4d0".
Second, use the initCodeHash obtained above to mine a vanity address using the following commands:
git clone https://github.com/0age/create2crunch
cd create2crunch
export FACTORY="0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"
export CALLER="[DEPLOYER_ADDRESS_GOES_HERE]"
export INIT_CODE_HASH="[INIT_CODE_HASH_GOES_HERE]"
cargo run --release $FACTORY $CALLER $INIT_CODE_HASH
You should see rows like
0xbeef63ae5a2102506e8a352a5bb32aa8b30b3112f9d02aa0154b2000061fb0dd => 0x00006C2eEC8d3AC8720D65e400fe0079C32eee5A => 2
0xbeef63ae5a2102506e8a352a5bb32aa8b30b3112f9d02aa0154b6000064122f4 => 0x0000000054D52974711c14aB458780886579167F => 256
being generated. The bytes starting with "0xbeef" are salts, and the corresponding contract addresses are shown to their right. When a desired address has been mined, stop the create2crunch script and update script/DeployUniV3Automan.s.sol
with the mined salt.
Re-simulate DeployUniV3Automan
with a dry-run to verify that the deployment address matches expectation, and broadcast the transaction on-chain.
Generate the standard JSON input and verify the contract on Etherscan with it:
forge verify-contract 0x00000000Ede6d8D217c60f93191C060747324bca UniV3Automan --optimizer-runs 4194304 --constructor-args 0x000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88000000000000000000000000beef63ae5a2102506e8a352a5bb32aa8b30b3112 --show-standard-json-input > etherscan.json
Constructor args can be encoded easily using an online ABI tool like https://abi.hashex.org. The above example shows UniV3Automan
constructor args consisting of the nonfungible position manager contract address followed by the deployer address as the temporary Automan owner during deployment.
Deployed Contracts
See example here.
forge update lib/<deps package> # e.g. forge update lib/forge-std
Narya.ai has performed a security audit of the UniV3Automan
contract on May 8, 2023, at
commit 2a8975e9.
The audit report can be
found here.
The primary license for Aperture UniV3 Automan contract is the Business Source License 1.1 (BUSL-1.1
),
see LICENSE
. However, some files are dual-licensed under GPL-2.0-or-later
or MIT
:
- Several files in
src/base/
may also be licensed underGPL-2.0-or-later
(as indicated in their SPDX headers). - All files in
src/interfaces/
may also be licensed underMIT
(as indicated in their SPDX headers). - Several files in
src/libraries/
may also be licensed underMIT
(as indicated in their SPDX headers).
- All files in
test/
are licensed underMIT
.