Skip to content

Commit

Permalink
added ability to set min amount for OFT and NativeOFT
Browse files Browse the repository at this point in the history
  • Loading branch information
0xIryna committed Dec 23, 2022
1 parent 5d11c0f commit 0d9c77c
Show file tree
Hide file tree
Showing 24 changed files with 576 additions and 291 deletions.
15 changes: 15 additions & 0 deletions constants/nativeOftArgs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"goerli": {
"name": "Native OFT",
"symbol": "NOFT",
"minAmount": "0.001",
"useMinAmount": true,
"contractName": "MinSendAmountNativeOFT"
},
"bsc-testnet": {
"name": "Native OFT",
"symbol": "NOFT",
"useMinAmount": false,
"contractName": "NativeOFT"
}
}
15 changes: 15 additions & 0 deletions constants/oftArgs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"goerli": {
"name": "OFT",
"symbol": "OFT",
"minAmount": "0.001",
"useMinAmount": true,
"contractName": "MinSendAmountOFT"
},
"bsc-testnet": {
"name": "OFT",
"symbol": "OFT",
"useMinAmount": false,
"contractName": "OFT"
}
}
4 changes: 2 additions & 2 deletions constants/pools.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"goerli": "0xeBBEa1682C59D9cfBd0142783B47AA934cB3137d",
"bsc-testnet": "0xd336c031701debb988f9780c7b5c606b9348504d"
"goerli": "0x1D146E9f8b3196e207F8e9f052e1C12B4a02716F",
"bsc-testnet": "0x14f20d80cfe1c1334e4abcb07c0f9c7a95232159"
}
4 changes: 2 additions & 2 deletions contracts/INativeOFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ pragma solidity ^0.8.0;

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

interface INativeOFT is IOFTCore {
function deposit() external payable;
interface INativeOFT is IOFTCore {
function deposit() external payable;
}
22 changes: 22 additions & 0 deletions contracts/MinSendAmountNativeOFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

contract MinSendAmountNativeOFT is NativeOFT {
uint public minSendAmount;

constructor(string memory _name, string memory _symbol, address _lzEndpoint, uint _minSendAmount) NativeOFT(_name, _symbol, _lzEndpoint) {
minSendAmount = _minSendAmount;
}

function setMinSendAmount(uint _minSendAmount) external onlyOwner {
minSendAmount = _minSendAmount;
}

function _send(address _from, uint16 _dstChainId, bytes memory _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams) internal virtual override {
require(_amount >= minSendAmount, "MinSendAmountNativeOFT: amount is less than minimum");
super._send(_from, _dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);
}
}
22 changes: 22 additions & 0 deletions contracts/MinSendAmountOFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

contract MinSendAmountOFT is OFT {
uint public minSendAmount;

constructor(string memory _name, string memory _symbol, address _lzEndpoint, uint _minSendAmount) OFT(_name, _symbol, _lzEndpoint) {
minSendAmount = _minSendAmount;
}

function setMinSendAmount(uint _minSendAmount) external onlyOwner {
minSendAmount = _minSendAmount;
}

function _send(address _from, uint16 _dstChainId, bytes memory _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams) internal virtual override {
require(_amount >= minSendAmount, "MinSendAmountOFT: amount is less than minimum");
super._send(_from, _dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);
}
}
62 changes: 31 additions & 31 deletions contracts/SwappableBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ import "@layerzerolabs/solidity-examples/contracts/token/oft/IOFTCore.sol";
import "./INativeOFT.sol";

contract SwappableBridge {
IOFTCore public oft;
INativeOFT public nativeOft;
IUniswapV2Router02 public uniswapRouter;

constructor(address _oft, address _nativeOft, address _uniswapRouter) {
require(_oft != address(0), "SwappableBridge: invalid OFT address");
require(_nativeOft != address(0), "SwappableBridge: invalid Native OFT address");
require(_uniswapRouter != address(0), "SwappableBridge: invalid Uniswap Router address");

oft = IOFTCore(_oft);
nativeOft = INativeOFT(_nativeOft);
uniswapRouter = IUniswapV2Router02(_uniswapRouter);
}

function swapAndBridge(uint amountIn, uint amountOutMin, uint16 dstChainId, address payable refundAddress, address zroPaymentAddress, bytes calldata adapterParams) external payable {
require(msg.value > amountIn, "SwappableBridge: not enough value sent");
address[] memory path = new address[](2);
path[0] = uniswapRouter.WETH();
path[1] = address(oft);
uint[] memory amounts = uniswapRouter.swapExactETHForTokens{value: amountIn}(amountOutMin, path, address(this), block.timestamp);
oft.sendFrom{value: msg.value - amountIn}(address(this), dstChainId, abi.encodePacked(msg.sender), amounts[1], refundAddress, zroPaymentAddress, adapterParams);
}

function bridge(uint amountIn, uint16 dstChainId, address payable refundAddress, address zroPaymentAddress, bytes calldata adapterParams) external payable {
require(msg.value > amountIn, "SwappableBridge: not enough value sent");

nativeOft.deposit{value: amountIn}();
nativeOft.sendFrom{value: msg.value - amountIn}(address(this), dstChainId, abi.encodePacked(msg.sender), amountIn, refundAddress, zroPaymentAddress, adapterParams);
}
IOFTCore public oft;
INativeOFT public nativeOft;
IUniswapV2Router02 public uniswapRouter;

constructor(address _oft, address _nativeOft, address _uniswapRouter) {
require(_oft != address(0), "SwappableBridge: invalid OFT address");
require(_nativeOft != address(0), "SwappableBridge: invalid Native OFT address");
require(_uniswapRouter != address(0), "SwappableBridge: invalid Uniswap Router address");

oft = IOFTCore(_oft);
nativeOft = INativeOFT(_nativeOft);
uniswapRouter = IUniswapV2Router02(_uniswapRouter);
}

function swapAndBridge(uint amountIn, uint amountOutMin, uint16 dstChainId, address payable refundAddress, address zroPaymentAddress, bytes calldata adapterParams) external payable {
require(msg.value > amountIn, "SwappableBridge: not enough value sent");

address[] memory path = new address[](2);
path[0] = uniswapRouter.WETH();
path[1] = address(oft);

uint[] memory amounts = uniswapRouter.swapExactETHForTokens{value: amountIn}(amountOutMin, path, address(this), block.timestamp);
oft.sendFrom{value: msg.value - amountIn}(address(this), dstChainId, abi.encodePacked(msg.sender), amounts[1], refundAddress, zroPaymentAddress, adapterParams);
}

function bridge(uint amountIn, uint16 dstChainId, address payable refundAddress, address zroPaymentAddress, bytes calldata adapterParams) external payable {
require(msg.value > amountIn, "SwappableBridge: not enough value sent");

nativeOft.deposit{value: amountIn}();
nativeOft.sendFrom{value: msg.value - amountIn}(address(this), dstChainId, abi.encodePacked(msg.sender), amountIn, refundAddress, zroPaymentAddress, adapterParams);
}
}
4 changes: 1 addition & 3 deletions contracts/mocks/LayerZeroEndpoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
pragma solidity ^0.8.0;

import "@layerzerolabs/solidity-examples/contracts/mocks/LZEndpointMock.sol";
import "@layerzerolabs/solidity-examples/contracts/token/oft/OFT.sol";
import "@layerzerolabs/solidity-examples/contracts/token/oft/extension/NativeOFT.sol";

contract LayerZeroEndpoint is LZEndpointMock {
constructor(uint16 _chainId) LZEndpointMock(_chainId) {}
constructor(uint16 _chainId) LZEndpointMock(_chainId) {}
}
13 changes: 13 additions & 0 deletions contracts/mocks/MintableMinSendAmountOFTMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../MinSendAmountOFT.sol";

contract MintableMinSendAmountOFTMock is MinSendAmountOFT {
constructor(string memory _name, string memory _symbol, address _layerZeroEndpoint, uint _minSendAmount) MinSendAmountOFT(_name, _symbol, _layerZeroEndpoint, _minSendAmount) {}

function mint(address _to, uint _amount) public {
_mint(_to, _amount);
}
}
19 changes: 9 additions & 10 deletions contracts/mocks/WETH9.sol
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract WETH9 {
string public name = "Wrapped Ether";
string public symbol = "WETH";
uint8 public decimals = 18;
uint8 public decimals = 18;

mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;

event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event Deposit(address indexed from, uint256 amount);
event Withdrawal(address indexed to, uint256 amount);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
event Deposit(address indexed from, uint amount);
event Withdrawal(address indexed to, uint amount);

receive() external payable {
deposit();
}

function deposit() public payable {
balanceOf[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
Expand Down Expand Up @@ -48,7 +47,7 @@ contract WETH9 {
function transferFrom(address src, address dst, uint wad) public returns (bool) {
require(balanceOf[src] >= wad, "transferFrom: not enough balance");

if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) {
if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) {
require(allowance[src][msg.sender] >= wad, "transferFrom: not enough allowance");
allowance[src][msg.sender] -= wad;
}
Expand Down
27 changes: 16 additions & 11 deletions deploy/NativeOFT.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
const LZ_ENDPOINTS = require("../constants/layerzeroEndpoints.json")
const NATIVE_OFT_ARGS = require("../constants/nativeOftArgs.json")

module.exports = async function ({ deployments, getNamedAccounts }) {
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
console.log(`>>> your address: ${deployer}`)
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
console.log(`>>> your address: ${deployer}`)

const lzEndpointAddress = LZ_ENDPOINTS[hre.network.name]
console.log(`[${hre.network.name}] Endpoint Address: ${lzEndpointAddress}`)
const lzEndpointAddress = LZ_ENDPOINTS[hre.network.name]
console.log(`[${hre.network.name}] Endpoint Address: ${lzEndpointAddress}`)
const nativeOftArgs = NATIVE_OFT_ARGS[hre.network.name]
const constructorArgs = nativeOftArgs.useMinAmount
? [nativeOftArgs.name, nativeOftArgs.symbol, lzEndpointAddress, ethers.utils.parseEther(nativeOftArgs.minAmount)]
: [nativeOftArgs.name, nativeOftArgs.symbol, lzEndpointAddress]

await deploy("NativeOFT", {
from: deployer,
args: ["Native OFT", "NOFT", lzEndpointAddress],
log: true,
waitConfirmations: 1,
})
await deploy(nativeOftArgs.contractName, {
from: deployer,
args: constructorArgs,
log: true,
waitConfirmations: 1,
})
}

module.exports.tags = ["NativeOFT"]
27 changes: 16 additions & 11 deletions deploy/OFT.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
const LZ_ENDPOINTS = require("../constants/layerzeroEndpoints.json")
const OFT_ARGS = require("../constants/oftArgs.json")

module.exports = async function ({ deployments, getNamedAccounts }) {
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
console.log(`>>> your address: ${deployer}`)
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
console.log(`>>> your address: ${deployer}`)

const lzEndpointAddress = LZ_ENDPOINTS[hre.network.name]
console.log(`[${hre.network.name}] Endpoint Address: ${lzEndpointAddress}`)
const lzEndpointAddress = LZ_ENDPOINTS[hre.network.name]
console.log(`[${hre.network.name}] Endpoint Address: ${lzEndpointAddress}`)
const oftArgs = OFT_ARGS[hre.network.name]
const constructorArgs = oftArgs.useMinAmount
? [oftArgs.name, oftArgs.symbol, lzEndpointAddress, ethers.utils.parseEther(oftArgs.minAmount)]
: [oftArgs.name, oftArgs.symbol, lzEndpointAddress]

await deploy("OFT", {
from: deployer,
args: ["OFT", "OFT", lzEndpointAddress],
log: true,
waitConfirmations: 1,
})
await deploy(oftArgs.contractName, {
from: deployer,
args: constructorArgs,
log: true,
waitConfirmations: 1,
})
}

module.exports.tags = ["OFT"]
32 changes: 17 additions & 15 deletions deploy/SwappableBridge.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
const ROUTERS = require("../constants/uniswapRoutes.json")
const OFT_ARGS = require("../constants/oftArgs.json")
const NATIVE_OFT_ARGS = require("../constants/nativeOftArgs.json")

module.exports = async function ({ deployments, getNamedAccounts }) {
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
console.log(`>>> your address: ${deployer}`)
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
console.log(`>>> your address: ${deployer}`)

const routerAddress = ROUTERS[hre.network.name]
console.log(`[${hre.network.name}] Uniswap Router Address: ${routerAddress}`)
const routerAddress = ROUTERS[hre.network.name]
console.log(`[${hre.network.name}] Uniswap Router Address: ${routerAddress}`)

const oft = await ethers.getContract("OFT");
console.log(`[${hre.network.name}] OFT Address: ${oft.address}`)
const oft = await ethers.getContract(OFT_ARGS[hre.network.name].contractName)
console.log(`[${hre.network.name}] OFT Address: ${oft.address}`)

const nativeOft = await ethers.getContract("NativeOFT");
console.log(`[${hre.network.name}] OFT Address: ${nativeOft.address}`)
const nativeOft = await ethers.getContract(NATIVE_OFT_ARGS[hre.network.name].contractName)
console.log(`[${hre.network.name}] Native OFT Address: ${nativeOft.address}`)

await deploy("SwappableBridge", {
from: deployer,
args: [oft.address, nativeOft.address, routerAddress],
log: true,
waitConfirmations: 1,
})
await deploy("SwappableBridge", {
from: deployer,
args: [oft.address, nativeOft.address, routerAddress],
log: true,
waitConfirmations: 1,
})
}

module.exports.tags = ["SwappableBridge"]
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"compile": "hardhat compile",
"test": "hardhat test",
"coverage": "hardhat coverage",
"prettier": "prettier --write test/**/*.js && prettier --write test/*/*/*.js && prettier --write deploy/*.js && prettier --write tasks/*.js && prettier --write contracts/**/*.sol && prettier --write contracts/**/**/*.sol && prettier --write contracts/**/**/**/*.sol",
"prettier": "prettier --write test/**/*.js && prettier --write deploy/*.js && prettier --write tasks/*.js && prettier --write contracts/**/*.sol && prettier --write contracts/**/**/*.sol && prettier --write contracts/**/**/**/*.sol",
"lint": "yarn prettier && solhint 'contracts/*.sol' && solhint 'contracts/**/*.sol' && solhint 'contracts/**/**/*.sol' && solhint 'contracts/**/**/**/*.sol'"
},
"dependencies": {
Expand Down
Loading

0 comments on commit 0d9c77c

Please sign in to comment.