{"id":19176454,"url":"https://github.com/pawurb/locker","last_synced_at":"2025-05-07T19:23:23.499Z","repository":{"id":49564459,"uuid":"373336389","full_name":"pawurb/Locker","owner":"pawurb","description":"Ethereum Smart Contracts for locking Ether, ERC20 and ERC721 tokens based on time and price conditions","archived":false,"fork":false,"pushed_at":"2024-02-25T21:21:02.000Z","size":12027,"stargazers_count":31,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-31T13:18:40.877Z","etag":null,"topics":["blockchain","erc20","ether","ethereum"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pawurb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-03T00:23:08.000Z","updated_at":"2024-07-10T02:35:25.000Z","dependencies_parsed_at":"2024-02-25T22:28:44.963Z","dependency_job_id":"deb4ca34-fbc0-4fce-8534-d7a51caa68b6","html_url":"https://github.com/pawurb/Locker","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pawurb%2FLocker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pawurb%2FLocker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pawurb%2FLocker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pawurb%2FLocker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pawurb","download_url":"https://codeload.github.com/pawurb/Locker/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252941862,"owners_count":21828950,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","erc20","ether","ethereum"],"created_at":"2024-11-09T10:28:38.894Z","updated_at":"2025-05-07T19:23:23.471Z","avatar_url":"https://github.com/pawurb.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Locker - provides a way to lock and hold your ETH, ERC20 or ERC721 in a smart contract [![GH Actions](https://github.com/pawurb/Locker/actions/workflows/ci.yml/badge.svg)](https://github.com/pawurb/Locker/actions)\n\n**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!**\n\n**Disclaimer: The information provided in the readme is for educational purposes only and should not be treated as investment advice.**\n\n[Story of the project](https://pawelurbanek.com/smart-contract-development)\n\n## ERC20Locker.sol\n\nThis 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.\n\n**Do not send any ERC20 tokens directly to this contract or they will be lost!!** You have to use a dedicated `deposit` method.\n\n**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.**\n\n### API\n\nEach 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.\n\n#### `configureDeposit`\n\n```solidity\nfunction configureDeposit(\n    address _token,\n    uint256 _lockForDays\n)\n```\n\nThis function is used to configure a deposit without a minimum expected price for a specific token. It means that token will be released only after the configured time period has passed.\n\n**Arguments:**\n\n* `_token`: Address of ERC20 token to be configured.\n* `_lockForDays`: The number of days the tokens will be locked.\n\nAs a result of executing this method a `LockerPass` NFT token will be minted to your account. As long as you're an owner of a target NFT representing your deposit you'll be able to manage and withdraw the deposited ERC20 tokens.\n\nAfter 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:\n\n```solidity\n  ERC20(tokenAddress).approve(lockerAddress, amount);\n```\n\nIf you're not sure how to do it, then better don't. You can lose your tokens by incorrectly transferring them into the `ERC20Locker` smart contract.\n\n#### `configureDepositWithPrice`\n\n```solidity\nfunction configureDepositWithPrice(\n    address _token,\n    uint256 _lockForDays,\n    address _priceFeed,\n    int256 _minExpectedPrice,\n    int256 _pricePrecision\n)\n```\n\nThis function is used to configure a deposit with a minimum expected price for a specific token.\n\n**Arguments:**\n\n* `_token`: Address of ERC20 token to be configured.\n* `_lockForDays`: The number of days the tokens will be locked.\n* `_priceFeed`: The address of the price feed smart contract.\n* `_minExpectedPrice`: The minimum expected price for the token.\n* `_pricePrecision`: The oracle price precision for the token. Most ChainLink oracles use `10e7`. You can use `checkPriceFeed` method to confirm price precision used by your choosen oracle.\n\n#### `deposit`\n\n```solidity\nfunction deposit(\n    address _token,\n    uint256 _amount,\n    uint256 _depositId\n)\n```\n\nTransfers 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.\n\nYou must be owner of a `LockerPass` NFT with a target `_depositId` to execute this method.\n\n**Arguments:**\n\n* `_token`: Address of ERC20 token to be deposited.\n* `_amount`: amount of tokens to deposit.\n* `_depositId`: ID of a target deposit\n\n#### `canWithdraw`\n\n```solidity\nfunction canWithdraw(\n    uint256 _depositId\n) returns (bool)\n```\n\nReturns `true` if the specified `_depositId` be withdrawn by an owner. The withdrawal is allowed if the lock period is over, or if the expected price is reached.\n\n**Arguments:**\n\n* `_depositId`: ID of a target deposit\n\n\n#### `withdraw`\n\n```solidity\nfunction withdraw(\n    uint256 _depositId\n)\n```\n\nThis method withdraws ERC20 tokens deposited in a target `_depositId` and burns associated `LockerPass` NFT token. It can be executed only if `canWithdraw` returns `true` for a target `_depositId`.\n\n#### `increaseMinExpectedPrice`\n\n```solidity\nfunction increaseMinExpectedPrice(\n  int256 _newMinExpectedPrice\n  uint256 _depositId\n)\n```\n\nIncreases the minimum expected price for the specified `_depositId` to `_newMinExpectedPrice`, if it is greater than the current minimum expected price.\n\n**Arguments:**\n\n* `_newMinExpectedPrice`: New value of minimum expected price that will release the token.\n* `_depositId`: ID of a target deposit\n\n#### `increaseLockForDays`\n\n```solidity\nfunction increaseLockForDays(\n  int256 _newLockForDays\n  uint256 _depositId\n)\n```\n\nIncreases the lock period for the specified `_depositId` to `_newLockForDays`, if it is greater than the current lock period.\n\n**Arguments:**\n\n* `_newMinExpectedPrice`: New number of days for how long the token should be locked.\n* `_depositId`: ID of a target deposit\n\n#### `checkPriceFeed`\n\n```solidity\nfunction checkPriceFeed(\n  address _feedAddress,\n  int256 _precision\n) returns (int256)\n```\n\nChecks 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.\n\n**Arguments:**\n\n* `_feedAddress`: Address of the price oracle smart contract.\n* `_precision`: Number by which a raw price value should be divided.\n\n#### `getPrice`\n\n```solidity\nfunction getPrice(\n  uint256 _depositId\n) returns (int256)\n```\n\nReturns the latest price reported for a configured `_depositId`. If the price feed is not set, then 0 is returned.\n\n**Arguments:**\n\n* `_depositId`: ID of a target deposit\n\n#### `deposits`\n\n```solidity\nmapping(uint256 =\u003e DepositData) deposits;\n```\n\nA nested hash representing configuration of all configured deposits. You can use it to read ERC20 token configuration based on a `_depositId`.\n\n## ETHLocker.sol\n\nThe `ETHLocker` 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:\n\n```node\nconst locker = await ETHLocker.new(\n  0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419\n)\n```\n\n### API\n\n#### `configureDeposit`\n\n```solidity\nfunction configureDeposit(\n    uint256 _lockForDays,\n    int256 _minExpectedPrice\n)\n```\n\nThis function is used to configure an ETH deposit for `_lockForDays` duration. Deposit can optionally be released early if configured `_minExpectedPrice` is reported by a price oracle. If `_minExpectedPrice` is set to `0` then this condition is ommited.\n\nAs a result of executing this method a `LockerPass` NFT token will be minted to your account. As long as you're an owner of a target NFT representing your deposit you'll be able to manage and withdraw the deposited Ether.\n\n#### `deposit`\n\n```solidity\nfunction deposit(\n    uint256 _depositId\n)\n```\n\nThis method adds the sent Ether value to the target `_depositId`. You must be owner of a `LockerPass` NFT with a target `_depositId` to execute this method.\n\n**Arguments:**\n\n* `_depositId`: ID of a target deposit\n\n#### `canWithdraw`\n\n```solidity\nfunction canWithdraw(\n    uint256 _depositId\n) returns (bool)\n```\n\nReturns `true` if the specified `_depositId` be withdrawn by an owner. The withdrawal is allowed if the lock period is over, or if the expected price is reached.\n\n**Arguments:**\n\n* `_depositId`: ID of a target deposit\n\n#### `withdraw`\n\n```solidity\nfunction withdraw(\n    uint256 _depositId\n)\n```\n\nThis method withdraws ETH deposited in a target `_depositId` and burns associated `LockerPass` NFT token. It can be executed only if `canWithdraw` returns `true` for a target `_depositId`.\n\n#### `increaseMinExpectedPrice`\n\n```solidity\nfunction increaseMinExpectedPrice(\n  int256 _newMinExpectedPrice\n  uint256 _depositId\n)\n```\n\nIncreases the minimum expected price for the specified `_depositId` to `_newMinExpectedPrice`, if it is greater than the current minimum expected price.\n\n#### `increaseLockForDays`\n\n```solidity\nfunction increaseLockForDays(\n  int256 _newLockForDays\n  uint256 _depositId\n)\n```\n\nIncreases the lock period for the specified `_depositId` to `_newLockForDays`, if it is greater than the current lock period.\n\n#### `deposits`\n\n```solidity\nmapping(uint256 =\u003e DepositData) deposits;\n```\n\nA nested hash representing configuration of all configured deposits. You can use it to read configuration based on a `_depositId`.\n\n## NFTLocker.sol\n\nThe NFTLocker smart contract is designed to allow users to lock and manage their non-fungible tokens (NFTs) for a specified period of time. Users can deposit their NFTs into the contract, set a lock duration, and then withdraw them only after the lock period has expired. This contract provides a way to hold NFTs temporarily and ensure they cannot be withdrawn until the specified time has passed.\n\n### API\n\nEach user account can configure any number of distinct ERC721 token instances.\n\n#### `deposit`\n\n```solidity\nfunction deposit(\n    address _token,\n    uint256 _depositId,\n    uint256 _lockForDays\n)\n```\n\nAllows users to deposit an NFT into the contract. Target token will be released only after the configured time period has passed.\n\n**Arguments:**\n\n* `_token`: Address of ERC721 token to be configured.\n* `_depositId`: ID of target NFT instance to be configured.\n* `_lockForDays`: The number of days the tokens will be locked.\n\nBefore configuring the ERC721 token instance conditions you have to approve `Locker` contract to transfer it from your account. To do it you have to make the following method call:\n\n```solidity\n  ERC721(tokenAddress).approve(lockerAddress, tokenId);\n```\n\n#### `canWithdraw`\n\n```solidity\nfunction canWithdraw(\n    address _account,\n    address _token,\n    uint256 _tokenId\n) returns (bool)\n```\n\nChecks if a user can withdraw a specific NFT.\n\n#### `withdraw`\n\n```solidity\nfunction withdraw(\n    address _token,\n    uint256 _tokenId\n)\n```\n\nAllows users to withdraw an NFT that has reached its lock duration and transfers the NFT back to the user.\n\n#### `increaseLockForDays`\n\n```solidity\nfunction increaseLockForDays(\n  address _token,\n  uint256 _tokenId,\n  int256 _newLockForDays\n)\n```\n\nAllows users to increase the lock duration for a previously deposited NFT.\n\n## ERC20LockerPriv.sol\n\nThis 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.\n\nYou can use the contract in the following way:\n\n```node\nconst locker = await ERC20LockerPriv.new()\nawait locker.configureToken(\n  0x0d8775f648430679a709e98d2b0cb6250d2887ef,\n  750,\n  0x9441D7556e7820B5ca42082cfa99487D56AcA958,\n  5,\n  10e7\n)\n```\n\n### API\n\n`configureToken(address _tokenAddress, uint256 _lockForDays, address _feedAddress, int256 _minExpectedPrice, int256 _pricePrecision)`\n\n* `_tokenAddress` - `[address]` address of an ERC20 or ETH token, i.e. [`BAT`](https://etherscan.io/token/0x0d8775f648430679a709e98d2b0cb6250d2887ef) or [`ETH`](https://etherscan.io/token/0x0000000000000000000000000000000000000000)\n* `_lockForDays` - `[uint256]` how many days you want to lock the token for, counted since contract creation\n* `_priceFeedAddress` - `[address]` address of a ChainLink price feed contract, e.g., [ETH/USD on Mainnet](https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419). Provide a [zero address](https://etherscan.io/address/0x0000000000000000000000000000000000000000) if you don't want to withdraw based on price conditions\n* `_minExpectedPrice` - `[int256]` minimum price (in units corresponding to configured `_pricePrecision`) that would release the funds (setting it to 0 disables this condition)\n* `_pricePrecision` - `[int256]` inversed precision of price returned by a price feed, i.e. `10e7` for dollars and `10e5` for cents\n\nBefore configuring the token you can validate the price feed address and precision using the following method:\n\n`checkPriceFeed(address _feedAddress, int256 _precision) returns (int256)`\n* `_feedAddress` -`[address]` address of a ChainLink price feed oracle\n* `_precision` - `[int256] precision of returned price values, e.g., `10e7` for dollars and `10e5` for cents\n\nYou 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:\n\n`increaseMinExpectedPrice(address _tokenAddress, int256 _newMinExpectedPrice)`\n* `_tokenAddress` - `[address]` address of a token\n* `_newMinExpectedPrice` - `[int256]` new value of a minimum expected price\n\n`increaseLockForDays(address _tokenAddress, uint256 _newLockForDays)`\n* `_tokenAddress` - `[address]` address of a token\n* `_newLockForDays` - `[uint256]` new number of days that you want to lock the funds for\n\nYou can check if a given token can be withdrawn by using:\n\n`canWithdraw(address _tokenAddress) returns (bool)`\n* `_tokenAddress` - `[address]` address of a token\n\nIf the above method returns `true`, you can withdraw a selected token using:\n\n`withdraw(address _tokenAddress)`\n* `_tokenAddress` - `[address]` address of a token\n\nTokens will be returned to the address of a contract maker.\n\n## ETHLockerPriv.sol\n\nETHLockerPriv 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:\n\n- The lockup period has expired.\n- The current ETH price is greater than or equal to a specified minimum price.\n\nThe smart contract constructor takes in three parameters:\n\n* `_priceFeed`: The address of an external smart contract that provides ETH price feed.\n* `_lockForDays`: The number of days to lock the deposited ETH.\n* `_minimumPrice`: The minimum ETH price required to withdraw.\n\n### API\n\n`withdraw()` - Withdraws the deposited ETH if the withdrawal conditions are met.\n`canWithdraw() returns (bool)` - Checks if the withdrawal conditions are met. Returns `true` if the withdrawal conditions are met; otherwise, `false`.\n\n## Price feeds\n\nETH/USD price oracles powered by [ChainLink](https://docs.chain.link/docs/get-the-latest-price/):\n\n* [Mainnet](https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419)\n* [Goerli](https://goerli.etherscan.io/address/0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e)\n* [Arbitrum Mainnet](https://arbiscan.io/address/0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612)\n* [Optimism Mainnet](https://optimistic.etherscan.io/address/0x13e3Ee699D1909E989722E753853AE30b17e08c5)\n\n[More price feeds](https://docs.chain.link/data-feeds/price-feeds/addresses/).\n\nPlease 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.\n\n## Setup\n\n```bash\nasdf install\nnpm install\nnpx hardhat node\nnpx hardhat test\n```\n\n### Security scan\n\n```bash\ndocker pull trailofbits/eth-security-toolbox\ndocker run -it -v ./:/share/Locker trailofbits/eth-security-toolbox\ncd /share/Locker\nslither .\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpawurb%2Flocker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpawurb%2Flocker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpawurb%2Flocker/lists"}