Skip to content

Commit

Permalink
add ole v2 contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul-D-Ant committed Oct 13, 2023
1 parent befd566 commit b3388db
Show file tree
Hide file tree
Showing 17 changed files with 794 additions and 1 deletion.
36 changes: 36 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npx hardhat test

coverage:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npx hardhat coverage

- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
files: ./coverage/lcov.info
flags: production


9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/.idea
/build
/node_modules
/package-lock.json
/coverage.json
.DS_Store
/artifacts
/coverage
/cache
52 changes: 51 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
# ole-v2-contracts
# OpenLeverage OLE V2

This repository contains the Solidity project for upgrading the OLEV1 Token to the OLEV2 Token, which implements LayerZero's OFT token standard. This upgrade allows users to perform cross-chain operations seamlessly.

## Overview

The OpenLeverage OLE Token V2 project is designed to transition from the OLEV1 Token to the OLEV2 Token, which adheres to the OFT token standard. This new standard enhances the token's functionality and interoperability with other blockchain platforms.

### OpenLeverageOFT Features

- **OFT Token Standard**: The OpenLeverage OLE Token adheres to LayerZero's OFT token standard, ensuring compatibility with various LayerZero-based projects and cross-chain operations.

- **Pausable**: The contract inherits the pausable feature from LayerZero's PausableOFT, allowing the owner to pause and unpause token transfers when needed, enhancing security and compliance.

- **Burn Function**: Users can burn (destroy) their tokens using the `burn` function, reducing their token balance.

### OLEV1Lock Contract

The `OLEV1Lock` contract plays a crucial role in this project. It was developed to address the lack of LayerZero support on KCC chains, allowing users on KCC chains to lock their OLEV1 Tokens. In return, the OLEV2 Tokens will be issued on the Arbitrum chain, ensuring a smooth transition. Here's an accurate description of the contract:

- **OLEV1Lock Contract**: This contract is specifically designed to assist users on KCC chains in locking their OLEV1 Tokens. The OLEV2 Tokens will be issued on the Arbitrum chain as part of the upgrade process.

- **Functionality**: Users can lock a specified amount of their OLEV1 Tokens using the `lock` function within this contract. This action is vital for the upgrade process, especially for those operating on KCC chains.

- **Expiration**: The contract includes an expiration time (as set during deployment) to ensure that only active transitions are allowed.

- **Events**: The contract emits a `Locked` event whenever a user locks their tokens, providing transparency and traceability during the upgrade.


### OLEV2Swap Contract

The `OLEV2Swap` contract is a key component of the OLE Token upgrade project. It facilitates the swapping of OLEV1 Tokens to the OLEV2 Tokens. Here's a brief description of the contract:

- **OLEV2Swap Contract**: This contract is responsible for the seamless transition of OLEV1 Tokens to the OLEV2 Tokens during the upgrade process.

- **Functionality**: Users can initiate the swap using the `swap` function, converting their OLEV1 Tokens to the OLEV2 Tokens. The contract ensures the proper handling of tokens and checks for the expiration time.

- **Expiration Time**: The contract includes an expiration time (as set during deployment) to prevent swaps after the specified date.

- **Events**: The contract emits a `Swapped` event when a user successfully swaps their tokens, providing transparency and traceability.


## Getting Started
get started with the OLE Token upgrade project:
git clone https://github.com/OpenLeverageDev/ole-v2-contracts.git


## Build and Test
We use Hardhat as the development environment for compiling, deploying, and testing.

`npx hardhat test`
29 changes: 29 additions & 0 deletions contracts/OLEV1Lock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./libraries/TransferHelper.sol";

contract OLEV1Lock {
using TransferHelper for IERC20;

IERC20 public ole;
uint64 public expireTime;

event Locked (address account, uint amount);

constructor (IERC20 _ole, uint64 _expireTime){
ole = _ole;
expireTime = _expireTime;
}

function lock(uint256 _amount) external {
require(expireTime > block.timestamp, 'Expired');
uint v1BalanceBefore = ole.balanceOf(address(this));
ole.safeTransferFrom(msg.sender, address(this), _amount);
uint v1BalanceAfter = ole.balanceOf(address(this));
require(v1BalanceAfter - v1BalanceBefore == _amount, "ERR");
emit Locked(msg.sender, _amount);
}

}
46 changes: 46 additions & 0 deletions contracts/OLEV2Swap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./common/Adminable.sol";
import "./common/ReentrancyGuard.sol";
import "./libraries/TransferHelper.sol";

contract OLEV2Swap is Adminable, ReentrancyGuard {
using TransferHelper for IERC20;

IERC20 public oleV1;
IERC20 public oleV2;
uint64 public expireTime;

event Swapped (address account, uint amount);

constructor (IERC20 _oleV1, IERC20 _oleV2, uint64 _expireTime){
admin = payable(msg.sender);
oleV1 = _oleV1;
oleV2 = _oleV2;
expireTime = _expireTime;
}

function swap(uint256 _amount) external nonReentrant(){
require(expireTime > block.timestamp, 'Expired');
uint oleV2BalanceBefore = oleV2.balanceOf(address(this));
require(oleV2BalanceBefore >= _amount, 'NE');

uint oleV1BalanceBefore = oleV1.balanceOf(address(this));
oleV1.safeTransferFrom(msg.sender, address(this), _amount);
uint oleV1BalanceAfter = oleV1.balanceOf(address(this));
require(oleV1BalanceAfter - oleV1BalanceBefore == _amount, "CKP1");

oleV2.safeTransfer(msg.sender, _amount);
uint oleV2BalanceAfter = oleV2.balanceOf(address(this));
require(oleV2BalanceBefore - oleV2BalanceAfter == _amount, "CKP2");
emit Swapped(msg.sender, _amount);
}

function recycle(address _account, uint256 _amount) external onlyAdmin {
require(oleV2.balanceOf(address(this)) >= _amount, "NE");
oleV2.safeTransfer(_account, _amount);
}

}
16 changes: 16 additions & 0 deletions contracts/OpenleverageOFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0 <0.9.0;

import "@layerzerolabs/solidity-examples/contracts/token/oft/extension/PausableOFT.sol";

contract OpenleverageOFT is PausableOFT {
constructor(string memory _name, string memory _symbol, address _lzEndpoint, uint256 _mintAmount) PausableOFT(_name, _symbol, _lzEndpoint) {
if (_mintAmount > 0) {
_mint(msg.sender, _mintAmount);
}
}

function burn(uint256 _amount) external {
_burn(_msgSender(), _amount);
}
}
52 changes: 52 additions & 0 deletions contracts/common/Adminable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.17;

abstract contract Adminable {
address payable public admin;
address payable public pendingAdmin;
address payable public developer;

event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

event NewAdmin(address oldAdmin, address newAdmin);

constructor() {
developer = payable(msg.sender);
}

modifier onlyAdmin() {
checkAdmin();
_;
}
modifier onlyAdminOrDeveloper() {
require(msg.sender == admin || msg.sender == developer, "Only admin or dev");
_;
}

function setPendingAdmin(address payable newPendingAdmin) external virtual onlyAdmin {
// Save current value, if any, for inclusion in log
address oldPendingAdmin = pendingAdmin;
// Store pendingAdmin with value newPendingAdmin
pendingAdmin = newPendingAdmin;
// Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);
}

function acceptAdmin() external virtual {
require(msg.sender == pendingAdmin, "Only pendingAdmin");
// Save current values for inclusion in log
address oldAdmin = admin;
address oldPendingAdmin = pendingAdmin;
// Store admin with value pendingAdmin
admin = pendingAdmin;
// Clear the pending value
pendingAdmin = payable(0);
emit NewAdmin(oldAdmin, admin);
emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);
}

function checkAdmin() private view {
require(msg.sender == admin, "caller must be admin");
}
}
27 changes: 27 additions & 0 deletions contracts/common/ReentrancyGuard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.17;

contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;

uint256 private _status;

constructor() {
_status = _NOT_ENTERED;
}

modifier nonReentrant() {
check();
_status = _ENTERED;

_;

_status = _NOT_ENTERED;
}

function check() private view {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
}
}
61 changes: 61 additions & 0 deletions contracts/libraries/TransferHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
* @title TransferHelper
* @dev Wrappers around ERC20 operations that returns the value received by recipent and the actual allowance of approval.
* To use this library you can add a `using TransferHelper for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library TransferHelper {
function safeTransfer(
IERC20 _token,
address _to,
uint256 _amount
) internal returns (uint256 amountReceived) {
if (_amount > 0) {
bool success;
uint256 balanceBefore = _token.balanceOf(_to);
(success, ) = address(_token).call(abi.encodeWithSelector(_token.transfer.selector, _to, _amount));
require(success, "TF");
uint256 balanceAfter = _token.balanceOf(_to);
require(balanceAfter > balanceBefore, "TF");
amountReceived = balanceAfter - balanceBefore;
}
}

function safeTransferFrom(
IERC20 _token,
address _from,
address _to,
uint256 _amount
) internal returns (uint256 amountReceived) {
if (_amount > 0) {
bool success;
uint256 balanceBefore = _token.balanceOf(_to);
(success, ) = address(_token).call(abi.encodeWithSelector(_token.transferFrom.selector, _from, _to, _amount));
require(success, "TFF");
uint256 balanceAfter = _token.balanceOf(_to);
require(balanceAfter > balanceBefore, "TFF");
amountReceived = balanceAfter - balanceBefore;
}
}

function safeApprove(
IERC20 _token,
address _spender,
uint256 _amount
) internal returns (uint256) {
bool success;
if (_token.allowance(address(this), _spender) != 0) {
(success, ) = address(_token).call(abi.encodeWithSelector(_token.approve.selector, _spender, 0));
require(success, "AF");
}
(success, ) = address(_token).call(abi.encodeWithSelector(_token.approve.selector, _spender, _amount));
require(success, "AF");

return _token.allowance(address(this), _spender);
}
}
22 changes: 22 additions & 0 deletions contracts/mocks/MockToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MockToken is ERC20 {
constructor(
string memory name_,
string memory symbol_,
uint256 amount
) ERC20(name_, symbol_) {
mint(msg.sender, amount);
}

function mint(address to, uint256 amount) public {
_mint(to, amount);
}

function getChainId() external view returns (uint256) {
return block.chainid;
}
}
19 changes: 19 additions & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @type import('hardhat/config').HardhatUserConfig */
require('@nomiclabs/hardhat-truffle5');
require('solidity-coverage')
require("hardhat-gas-reporter");

module.exports = {
solidity: {
version: "0.8.17",
settings: {
optimizer: {
enabled: true
},
},
},
gasReporter: {
enabled: true
},

};
Loading

0 comments on commit b3388db

Please sign in to comment.