Code Guide: Automating liquidity locking on UniCrypt using Gelato

In this tutorial, you will learn how to automate liquidity locking on UniCrypt using Gelato Network.

What is liquidity locking?

What is a liquidity tax?

What does liquidity tax mean for the locked liquidity?

Prerequisites

Enter Gelato

How will we build our contract?

Creating test LP tokens

Creating a Lock

The Contract Code

pragma solidity ^0.8.14;

import "@openzeppelin/contracts/access/Ownable.sol";
import "./OpsTaskCreator.sol";
interface IUniswapV2Locker {
function incrementLock(uint256 _lockID, uint256 _amount) external;
}
contract UncxAutoLocker is OpsTaskCreator, Ownable {

// Gas threshold above which executions should stop
uint256 public gasThreshold = 80 gwei;
// timestamp of the last Gelato execution
uint256 public lastExecuted;
// task ID to track Gelato executions
bytes32 public taskId;

// Unicrypt Locker Address.
address public lockerAddress;
// Address of the liquidity token to be incremented.
address public lpToken;
// Unicrypt liquidity lock nonce (lock ID).
uint256 public lockID;
// threshold token amount required for a Gelato execution.
uint256 public amount;
// minimum interval between code executions.
uint256 public interval = 5 minutes;
constructor(
address _lockerAddress,
address _lpToken,
uint256 _lockID,
uint256 _amount,
address payable _ops,
address _fundsOwner
) OpsTaskCreator(_ops, _fundsOwner) {
lockerAddress = _lockerAddress;
lpToken = _lpToken;
lockID = _lockID;
amount = _amount;
lastExecuted = block.timestamp;
}
function incrementLpLock(uint256 _amount) external onlyDedicatedMsgSender {
SafeERC20.safeApprove(IERC20(lpToken), lockerAddress, _amount);
IUniswapV2Locker(lockerAddress).incrementLock(lockID, _amount);
(uint256 fee, address feeToken) = _getFeeDetails();
_transfer(fee, feeToken);
lastExecuted = block.timestamp;
}
receive() external payable {}

function createTask() external onlyOwner {
require(taskId == bytes32(""), "Already started task");
ModuleData memory moduleData = ModuleData({
modules: new Module[](2),
args: new bytes[](2)
});
moduleData.modules[0] = Module.RESOLVER;
moduleData.modules[1] = Module.PROXY;
moduleData.args[0] = _resolverModuleArg(
address(this),
abi.encodeCall(this.checker, ())
);
moduleData.args[1] = _proxyModuleArg();
bytes32 id = _createTask(
address(this),
abi.encode(this.incrementLpLock.selector),
moduleData,
ETH
);
taskId = id;
emit CounterTaskCreated(id);
}
function cancelTask() external onlyOwner {
_cancelTask(taskId);
taskId = bytes32("");
}
function checker()
external
view
returns (bool canExec, bytes memory execPayload)
{
if (tx.gasprice > gasThreshold) {
return (false, bytes("Gas above threshold"));
}

if (IERC20(lpToken).balanceOf(address(this)) < amount) {
return (false, bytes("Amount threshold not met"));
}

canExec = (block.timestamp - lastExecuted) >= interval;
execPayload = abi.encodeWithSelector(this.incrementLpLock.selector, amount);
}

Deployment Code

import { ethers } from "hardhat";

async function main() {

// Goerli Unicrypt locker v2 address
let lockerAddress = "0x95cbf2267ddD3448a1a1Ed5dF9DA2761af02202e"

// Replace with the LP token address you want to increment (matching the lock)
let lpToken = "0x"

// Replace with Lock ID retrieved after creating the lock (matching the lock)
let testLockID = "0"

// Amount of tokens required to trigger the Gelato execution
let thresholdAmount = ethers.utils.parseUnits('5', 2).toString()

// Gelato Goerli ops address. For other chains see
// https://docs.gelato.network/developer-services/automate/contract-addresses
let gelatoOps = "0xc1C6805B857Bef1f412519C4A842522431aFed39"
// Replace with an address of the funds over
let fundsOwner = "0x"

// Deploy the contract
const AutoLocker = await ethers.getContractFactory("UncxAutoLocker");
const autoLocker = await AutoLocker.deploy(lockerAddress, lpToken, testLockID, thresholdAmount, gelatoOps, fundsOwner);
await autoLocker.deployed()
console.log(`autolocker deployed to ${autoLocker.address}`);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

Usage

Going Forward

Disclaimer

What is UniCrypt?

--

--

Multi-chain decentralized services provider — Built from the ground-up, permanently ignoring market conditions and delivering disruption.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
UNCX Network

Multi-chain decentralized services provider — Built from the ground-up, permanently ignoring market conditions and delivering disruption.