• Stars
    star
    28
  • Rank 852,540 (Top 18 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 3 years ago
  • Updated 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Ethereum Smart Contracts for locking Ether, ERC20 and ERC721 tokens based on time and price conditions

Locker - provides a way to lock and hold your ETH or ERC20 in a smart contract CircleCI

This is a BETA software that has not been audited for security. Incorrectly using these smart contracts can result in irreversible loss of your funds. USE AT YOUR OWN RISK!

Disclaimer: The information provided in the readme is for educational purposes only and should not be treated as investment advice.

Story of the project

Locker.sol

This smart contract allows users to deposit ERC20 tokens and lock them for a certain period of time. Optionally, you can configure a minimum USD price that will release tokens before the time has passed.

Do not send any ERC20 tokens directly to this contract or they will be lost!! You have to use a dedicated deposit method.

Do not use this contract for storing rebasing tokens like stETH!! Stored balance is determined once when depositing the token. It means that rebased reward will get stuck in the contract forever.

API

Each user account can configure any number of distinct ERC20 tokens. But, you cannot configure different time/price conditions for the same ERC20 token and account. To do it you have to use a different account.

configureDeposit

function configureDeposit(
    address _token,
    uint256 _lockForDays
)

This function is used to configure a deposit without a minimum expected price for a specific token. It means that token will can released only after the configured time period has passed.

Arguments:

  • _token: Address of ERC20 token to be configured.
  • _lockForDays: The number of days the tokens will be locked.

After configuring the ERC20 token release conditions you have to approve Locker contract to transfer it from your account. To do it you have to make the following method call:

  ERC20(tokenAddress).approve(lockerAddress, amount);

If you're not sure how to do it, then better don't. You can lose your tokens by incorrectly transferring them into the Locker smart contract.

configureDepositWithPrice

function configureDepositWithPrice(
    address _token,
    uint256 _lockForDays,
    address _priceFeed,
    int256 _minExpectedPrice,
    int256 _pricePrecision
)

This function is used to configure a deposit with a minimum expected price for a specific token.

Arguments:

  • _token: Address of ERC20 token to be configured.
  • _lockForDays: The number of days the tokens will be locked.
  • _priceFeed: The address of the price feed smart contract.
  • _minExpectedPrice: The minimum expected price for the token.
  • _pricePrecision: The oracel price precision for the token. Most ChainLink oracles use 10e7. You can use checkPriceFeed method to confirm price precision used by your choosen oracle.

deposit

function configureDepositWithPrice(
    address _token,
    uint256 _amount
)

Transfers and locks the _amount of tokens to the ERC20 _token address into the contract. Token must be configured and correct amount approved before calling this method.

Arguments:

  • _token: Address of ERC20 token to be deposited.
  • _amount: amount of tokens to deposit.

canWithdraw

function canWithdraw(
    address _account,
    address _token
) returns (bool)

Returns true if the specified _account is eligible to withdraw deposit of their ERC20 _token otherwise false. The withdrawal is allowed if the lock period is over, or if the expected price is reached.

Arguments:

  • _account: Owner account of the deposit.
  • _token: Address of ERC20 token to be withdrawn.

increaseMinExpectedPrice

function increaseMinExpectedPrice(
  address _token,
  int256 _newMinExpectedPrice
)

Increases the minimum expected price for the specified ERC20 _token for the caller to _newMinExpectedPrice, if it is greater than the current minimum expected price.

Arguments:

  • _token: Address of ERC20 token to be reconfigured.
  • _newMinExpectedPrice: New value of minimum expected price that will release the token.

increaseLockForDays

function increaseLockForDays(
  address _token,
  int256 _newLockForDays
)

Increases the lock period for the specified ERC20 _token for the caller to _newLockForDays, if it is greater than the current lock period.

Arguments:

  • _token: Address of ERC20 token to be reconfigured.
  • _newMinExpectedPrice: New number of days for how long the token should be locked.

checkPriceFeed

function checkPriceFeed(
  address _feedAddress,
  int256 _precision
) returns (int256)

Checks the price feed at the specified _feedAddress and returns the latest price divided by the specified _precision. You should use it to verify price oracle smart contract and necessary price precision before using it in configureDepositWithPrice method.

Arguments:

  • _feedAddress: Address of the price oracle smart contract.
  • _precision: Number by which a raw price value should be divided.

getPrice

function getPrice(
  address _account,
  address _token
) returns (int256)

Returns the latest price of the specified ERC20 _token for the specified _account. If the price feed is not set, then 0 is returned.

Arguments:

  • _account: Address of the account depositing target token.
  • _token: Address of ERC20 token for which to check the price.

getDepositors

function getDepositors() returns address[]

Returns an array of addresses representing all the depositors.

getConfiguredTokens

function getConfiguredTokens(
  address _account
) returns (address[])

Returns an array of ERC20 tokens that have been configured for the specified _account.

Arguments:

  • _account: Address of the account.

deposits

mapping(address => mapping(address => DepositData)) deposits;

A nested hash representing configuration of all stored tokens. You can use it to read ERC20 token configuration based on account and token address.

LockerETH.sol

The LockerETH contract can be used to lock your Ether for a predefined period of time. Optionally, you can configure an ETH/USD price value that will release the Ether. You need to deploy the contract with the following arguments:

const deposit = await LockerETH.new(
  0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419,
  750,
  10000
)

API

constructor(address _priceFeed, uint256 _lockForDays, int256 _minimumPrice)

  • _priceFeedAddress - [address] address of the price feed oracle contract
  • _lockForDays - [uint256] number of days that you want to lock your funds for (max 4000)
  • _minimumPrice - [int256] minimum price (in USD) that would release the funds (setting it to 0 disables this condition)

canWithdraw() returns (bool) - check if funds can be withdrawn

withdraw() - withdraw funds to the contract maker address

You can send more Ether to the contract after it has been initialized. Only maker of the contract can withdraw the funds. Don't send ERC20 tokens to this contract because they will be stuck forever.

LockerPriv.sol

This contract can hold ERC20 tokens but is accessible only by an account that deployed it. You can use it to store rebasing tokens like stETH because total token balance is released when withdrawing the deposit.

You can use the contract in the following way:

const locker = await LockerPriv.new()
await locker.configureToken(
  0x0d8775f648430679a709e98d2b0cb6250d2887ef,
  750,
  0x9441D7556e7820B5ca42082cfa99487D56AcA958,
  5,
  10e7
)

API

configureToken(address _tokenAddress, uint256 _lockForDays, address _feedAddress, int256 _minExpectedPrice, int256 _pricePrecision)

  • _tokenAddress - [address] address of an ERC20 or ETH token, i.e. BAT or ETH
  • _lockForDays - [uint256] how many days you want to lock the token for, counted since contract creation
  • _priceFeedAddress - [address] address of a ChainLink price feed contract, e.g., ETH/USD on Mainnet. Provide a zero address if you don't want to withdraw based on price conditions
  • _minExpectedPrice - [int256] minimum price (in units corresponding to configured _pricePrecision) that would release the funds (setting it to 0 disables this condition)
  • _pricePrecision - [int256] inversed precision of price returned by a price feed, i.e. 10e7 for dollars and 10e5 for cents

Before configuring the token you can validate the price feed address and precision using the following method:

checkPriceFeed(address _feedAddress, int256 _precision) returns (int256)

  • _feedAddress -[address] address of a ChainLink price feed oracle
  • _precision - [int256] precision of returned price values, e.g., 10e7for dollars and10e5` for cents

You can only configure each token once. After it is configured, you can increase the expected minimum price and lock for days duration. Using the following methods:

increaseMinExpectedPrice(address _tokenAddress, int256 _newMinExpectedPrice)

  • _tokenAddress - [address] address of a token
  • _newMinExpectedPrice - [int256] new value of a minimum expected price

increaseLockForDays(address _tokenAddress, uint256 _newLockForDays)

  • _tokenAddress - [address] address of a token
  • _newLockForDays - [uint256] new number of days that you want to lock the funds for

You can check if a given token can be withdrawn by using:

canWithdraw(address _tokenAddress) returns (bool)

  • _tokenAddress - [address] address of a token

If the above method returns true, you can withdraw a selected token using:

withdraw(address _tokenAddress)

  • _tokenAddress - [address] address of a token

Tokens will be returned to the address of a contract maker.

LockerETHPriv.sol

LockerETHPriv is a smart contract that allows users to lock their Ethereum (ETH) for a specific period of time. The smart contract supports two withdrawal conditions:

  • The lockup period has expired.
  • The current ETH price is greater than or equal to a specified minimum price.

The smart contract constructor takes in three parameters:

  • _priceFeed: The address of an external smart contract that provides ETH price feed.
  • _lockForDays: The number of days to lock the deposited ETH.
  • _minimumPrice: The minimum ETH price required to withdraw.

API

withdraw() - Withdraws the deposited ETH if the withdrawal conditions are met. canWithdraw() returns (bool) - Checks if the withdrawal conditions are met. Returns true if the withdrawal conditions are met; otherwise, false.

Price feeds

ETH/USD price oracles powered by ChainLink:

More price feeds.

Please be aware that ChainLink price feeds are not guaranteed always to return the correct data. In case they stop responding, you'll only be able to withdraw your funds once the lock period has expired.

Setup

asdf install
npm install
npx hardhat node
npx hardhat test

Security scan

docker pull trailofbits/eth-security-toolbox
docker run -it -v ~/Locker/:/share trailofbits/eth-security-toolbox
cd /share/Locker
slither .

More Repositories

1

rails-pg-extras

Rails PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
Ruby
1,072
star
2

termit

Translations with speech synthesis in your terminal as a ruby gem
Ruby
507
star
3

ecto_psql_extras

Ecto PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
Elixir
351
star
4

rails-brotli-cache

Drop-in enhancement for Rails cache, offering better performance and compression with Brotli algorithm
Ruby
252
star
5

normit

Translations with speech synthesis in your terminal as a node package
JavaScript
239
star
6

activerecord-analyze

Add EXPLAIN ANALYZE to Rails Active Record query objects
Ruby
209
star
7

smart_init

A simple gem for eliminating Ruby initializers boilerplate code, and providing unified service objects API
Ruby
177
star
8

ruby-pg-extras

Ruby PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
Ruby
123
star
9

node-postgres-extras

NodeJS PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
JavaScript
70
star
10

ecto_extras

Ecto helper functions.
Elixir
36
star
11

devloop

An automated test runner for Rails that instantly executes specs based on a recent git diff output.
Ruby
36
star
12

lazyme

A simple gem to help you optimize your shell workflow
Ruby
35
star
13

python-pg-extras

Python PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
Python
35
star
14

WaitForIt

Events and time based iOS app scenarios made easy.
Swift
26
star
15

.dotfiles

My development environment settings.
Shell
13
star
16

haskell-pg-extras

Haskell PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
Haskell
9
star
17

ruby-jemalloc-node-yarn

Docker image of Ruby with Jemalloc Node 16 LTS and Yarn
Dockerfile
9
star
18

railsSearchKit

This Chrome extension provides easy access to the search bars every Rails developer needs.
JavaScript
8
star
19

dont_you_count

Disable count queries for selected Active Admin tables.
Ruby
7
star
20

pi-hole-docker-compose

pi-hole-docker-compose
6
star
21

activerecord-implicit-order

Ruby
5
star
22

delegate_it

A drop in replacement for ActiveSupport delegate method in non Rails projects.
Ruby
4
star
23

active-admin-tips

Active Admin tips and performance optimizations in action
Ruby
4
star
24

rust-pg-extras

Rust PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.
Rust
3
star
25

Siorbackend

Ruby
1
star
26

abstract_base

Abstract Class pattern Ruby gem
Ruby
1
star
27

FRP_introduction

Comparison between observer and reactive approach to login form validations.
JavaScript
1
star
28

focus.apki.io

Landing page for Focus app
HTML
1
star