From e49ebdbc681bf27ce720ff6aa0e2c8c73e3c7555 Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Sun, 20 Jun 2021 22:58:38 +0300 Subject: [PATCH 01/24] Updated full EmiPrice2 --- flat/EmiPrice2.Full.sol | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/flat/EmiPrice2.Full.sol b/flat/EmiPrice2.Full.sol index eb7ef04..42b5b59 100644 --- a/flat/EmiPrice2.Full.sol +++ b/flat/EmiPrice2.Full.sol @@ -190,10 +190,6 @@ library Address { } } -// File: @openzeppelin/contracts/proxy/Initializable.sol - -// SPDX-License-Identifier: MIT - // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; @@ -247,9 +243,6 @@ abstract contract Initializable { } } -// File: @openzeppelin/contracts/math/SafeMath.sol - -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -464,10 +457,6 @@ library SafeMath { } } -// File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol - -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.0; interface IUniswapV2Factory { @@ -500,10 +489,6 @@ interface IUniswapV2Factory { function setFeeToSetter(address) external; } -// File: contracts/uniswapv2/interfaces/IUniswapV2Pair.sol - -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.0; interface IUniswapV2Pair { @@ -759,9 +744,6 @@ interface IUniswapV2Router02 is IUniswapV2Router01 { ) external; } -// File: contracts/libraries/Priviledgeable.sol - -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -812,9 +794,6 @@ abstract contract Priviledgeable { } } -// File: contracts/interfaces/IEmiERC20.sol - -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.0; @@ -852,9 +831,6 @@ interface IEmiERC20 { ) external returns (bool); } -// File: @openzeppelin/contracts/token/ERC20/IERC20.sol - -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -932,9 +908,6 @@ interface IERC20 { event Approval(address indexed owner, address indexed spender, uint256 value); } -// File: contracts/interfaces/IEmiRouter.sol - -// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.6.2; @@ -1053,9 +1026,6 @@ interface IEmiRouter { ) external; } -// File: contracts/interfaces/IEmiswap.sol - -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.0; @@ -1110,9 +1080,6 @@ interface IEmiswap { function initialize(IERC20[] calldata assets) external; } -// File: contracts/interfaces/IOneSplit.sol - -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.0; @@ -1130,9 +1097,6 @@ interface IOneSplit { returns (uint256 returnAmount, uint256[] memory distribution); } -// File: contracts/EmiPrice2.sol - -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; pragma experimental ABIEncoderV2; From c2a6eb3d553484f0d9d36a2e1e507557a0d55785 Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Mon, 21 Jun 2021 00:28:49 +0300 Subject: [PATCH 02/24] Initial version of EmiList --- contracts/ESW.sol | 22 +++- contracts/EmiList.sol | 169 ++++++++++++++++++++++++++++++ contracts/interfaces/IEmiList.sol | 11 ++ 3 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 contracts/EmiList.sol create mode 100644 contracts/interfaces/IEmiList.sol diff --git a/contracts/ESW.sol b/contracts/ESW.sol index de79872..5cabbff 100644 --- a/contracts/ESW.sol +++ b/contracts/ESW.sol @@ -3,6 +3,7 @@ pragma solidity ^0.6.2; import "@openzeppelin/contracts/proxy/Initializable.sol"; import "./interfaces/IEmiVesting.sol"; +import "./interfaces/IEmiList.sol"; import "./libraries/Priviledgeable.sol"; import "./libraries/ProxiedERC20.sol"; import "./libraries/OracleSign.sol"; @@ -17,7 +18,7 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - string public codeVersion = "ESW v1.0-145-gf234c9e"; + string public codeVersion = "ESW v1.1-145-gf234c9e"; uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; bool public isFirstMinter = true; @@ -31,6 +32,8 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { mapping(address => uint256) public walletNonce; + address private emiList; + function initialize() public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); _addAdmin(msg.sender); @@ -79,6 +82,13 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { return true; } + function setListAddress(address _emiList) + public + onlyAdmin + { + emiList = _emiList; // can be NULL also to remove emiList functionality totally + } + /*********************** public functions *****************************/ function transferFrom( @@ -177,6 +187,16 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { ); } + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal override { + if (emiList != address(0)) { + require(IEmiList(emiList).approveTransfer(from, to, amount), "Transfer declined by blacklist"); + } + } + /*********************** internal functions *****************************/ function _mintAllowed( diff --git a/contracts/EmiList.sol b/contracts/EmiList.sol new file mode 100644 index 0000000..11bc05b --- /dev/null +++ b/contracts/EmiList.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "./interfaces/IEmiList.sol"; + +contract EmiList is Ownable, IEmiList { + using SafeMath for uint256; + + //----------------------------------------------------------------------------------- + // Data Structures + //----------------------------------------------------------------------------------- + + event ActionModeChanged(uint256 oldMode, uint256 newMode); + //----------------------------------------------------------------------------------- + // Variables, Instances, Mappings + //----------------------------------------------------------------------------------- + mapping(address => bool) private blackList; + mapping(address => bool) private whiteList; + + address[] private blackListSet; + address[] private whiteListSet; + + uint256 public actionMode; // 0: off, 1: blacklist, 2: whitelist + + //----------------------------------------------------------------------------------- + string public codeVersion = "EmiList v1.0-145-gf234c9e"; + + //----------------------------------------------------------------------------------- + // Smart contract Constructor + //----------------------------------------------------------------------------------- + + //----------------------------------------------------------------------------------- + // Observers + //----------------------------------------------------------------------------------- + function approveTransfer(address from, address to, uint256 amount) external view override returns (bool) + { + if (actionMode==1) { + return checkBlacklist(from, to, amount); + } + if (actionMode==2) { + return checkWhitelist(from, to, amount); + } + return true; // default case + } + + // Return unlock date and amount of given lock + function getWhitelistLen() + external + view + onlyOwner + returns (uint256) + { + return whiteListSet.length; + } + + function getBlacklistLen() + external + view + onlyOwner + returns (uint256) + { + return blackListSet.length; + } + + function getWhitelistItem(uint256 idx) + external + view + onlyOwner + returns (address) + { + require(idx < whiteListSet.length, "Wrong list idx"); + return whiteListSet[idx]; + } + + function getBlacklistItem(uint256 idx) + external + view + onlyOwner + returns (address) + { + require(idx < blackListSet.length, "Wrong list idx"); + return blackListSet[idx]; + } + + function setActionMode(uint256 mode) external onlyOwner + { + require(mode < 3 && mode != actionMode, "Wrong action mode"); + emit ActionModeChanged(actionMode, mode); + actionMode = mode; + } + + function addBlackListItems(address[] memory items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (!blackList[t]) { // item not in the list, add + blackList[t] = true; + blackListSet.push(t); + } + } + } + + function addWhiteListItems(address[] memory items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (!whiteList[t]) { // item not in the list, add + whiteList[t] = true; + whiteListSet.push(t); + } + } + } + + function removeBlackListItems(address[] memory items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (blackList[t]) { // item is in the list, remove + blackList[t] = false; + for (uint256 j = 0; j < blackListSet.length; j++) { + if (blackListSet[j]==t) { + delete blackListSet[j]; + break; + } + } + } + } + } + + function removeWhiteListItems(address[] memory items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (whiteList[t]) { // item is in the list, remove + whiteList[t] = false; + for (uint256 j = 0; j < whiteListSet.length; j++) { + if (whiteListSet[j]==t) { + delete whiteListSet[j]; + break; + } + } + } + } + } + + //----------------------------------------------------------------------------------- + // Observers + //----------------------------------------------------------------------------------- + function checkWhitelist(address from, address to, uint256 amount) internal view returns (bool) + { + return whiteList[from]; + } + + function checkBlacklist(address from, address to, uint256 amount) internal view returns (bool) + { + return !blackList[from]; + } + +} diff --git a/contracts/interfaces/IEmiList.sol b/contracts/interfaces/IEmiList.sol new file mode 100644 index 0000000..53f07f3 --- /dev/null +++ b/contracts/interfaces/IEmiList.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +/************************************************************************* + * EmiList inerface + * + ************************************************************************/ +interface IEmiList { + function approveTransfer(address from, address to, uint256 amount) external view returns (bool); +} From dcdcbbd9a2d67acb6b917892dfdcbefe6e3e5520 Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Mon, 21 Jun 2021 02:37:20 +0300 Subject: [PATCH 03/24] Updated emiList --- contracts/EmiList.sol | 8 +- contracts/mocks/ESWMock.sol | 11 ++ test/EmiList.test.js | 264 ++++++++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 contracts/mocks/ESWMock.sol create mode 100644 test/EmiList.test.js diff --git a/contracts/EmiList.sol b/contracts/EmiList.sol index 11bc05b..a4b14ee 100644 --- a/contracts/EmiList.sol +++ b/contracts/EmiList.sol @@ -46,7 +46,7 @@ contract EmiList is Ownable, IEmiList { } // Return unlock date and amount of given lock - function getWhitelistLen() + function getWhiteListLen() external view onlyOwner @@ -55,7 +55,7 @@ contract EmiList is Ownable, IEmiList { return whiteListSet.length; } - function getBlacklistLen() + function getBlackListLen() external view onlyOwner @@ -64,7 +64,7 @@ contract EmiList is Ownable, IEmiList { return blackListSet.length; } - function getWhitelistItem(uint256 idx) + function getWhiteListItem(uint256 idx) external view onlyOwner @@ -74,7 +74,7 @@ contract EmiList is Ownable, IEmiList { return whiteListSet[idx]; } - function getBlacklistItem(uint256 idx) + function getBlackListItem(uint256 idx) external view onlyOwner diff --git a/contracts/mocks/ESWMock.sol b/contracts/mocks/ESWMock.sol new file mode 100644 index 0000000..2ab5ab1 --- /dev/null +++ b/contracts/mocks/ESWMock.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.2; + +import "../ESW.sol"; + +contract ESWMock is ESW { + function mint(address account, uint256 amount) external { + super._mint(account, amount); + } +} diff --git a/test/EmiList.test.js b/test/EmiList.test.js new file mode 100644 index 0000000..dc97bd1 --- /dev/null +++ b/test/EmiList.test.js @@ -0,0 +1,264 @@ +// eslint-disable-next-line no-unused-vars +const { accounts, defaultSender, web3 } = require('@openzeppelin/test-environment'); +const { ether, time, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { default: BigNumber } = require('bignumber.js'); +const { assert, expect } = require('chai'); +const { contract } = require('./twrapper'); + +// test cases: +// add blacklist, add whitelist, remove bl items, remove wl items, get bl items, get wl items +// check each action modes: emilist address not set, emilist set no mode selected, bl mode chosen, wl mode chosen, emilist address removed + +const ESW = contract.fromArtifact('ESWMock'); +const EmiList = contract.fromArtifact('EmiList'); + +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + +// eslint-disable-next-line import/order +const { BN } = web3.utils; + +let emiList; +let esw; + +describe('EmiList test', function () { + const [TestOwner, alice, bob, clarc, dave, eve, george, henry, ivan] = accounts; + + beforeEach(async function () { + esw = await ESW.new(); + await esw.initialize(); + await esw.setMintLimit(defaultSender, ether('40000000')); + await esw.mint(defaultSender, ether('2000')); + + emiList = await EmiList.new({from: TestOwner}); + await esw.transfer(alice, ether('1')); + await esw.transfer(bob, ether('1')); + await esw.transfer(clarc, ether('1')); + await esw.transfer(dave, ether('1')); + await esw.transfer(ivan, ether('1')); + }); + describe('Check blacklist functions', ()=> { + beforeEach(async function () { + await emiList.addBlackListItems([alice, bob, dave, ivan], {from: TestOwner}); + }); + + describe('When using admin account', ()=> { + it('should add items successfully', async function () { + let b = await emiList.getBlackListLen({from: TestOwner}); + assert.equal(b, 4); + }); + it('should remove items successfully', async function () { + await emiList.removeBlackListItems([bob, ivan], {from: TestOwner}); + let b = await emiList.getBlackListLen({from: TestOwner}); + assert.equal(b, 4); // list length not actually changed! + var c; + // but addresses should not be in list set + for(var i = 0; i < b; i++) { + c = await emiList.getBlackListItem(i, {from: TestOwner}); + assert.notEqual(c, bob); + assert.notEqual(c, ivan); + } + }); + it('should get items successfully', async function () { + let b = await emiList.getBlackListItem(0, {from: TestOwner}); + assert.equal(b, alice); + b = await emiList.getBlackListItem(1, {from: TestOwner}); + assert.equal(b, bob); + b = await emiList.getBlackListItem(2, {from: TestOwner}); + assert.equal(b, dave); + b = await emiList.getBlackListItem(3, {from: TestOwner}); + assert.equal(b, ivan); + }); + }); + describe('When using non-admin account', ()=> { + it('should fail to add items', async function () { + expectRevert.unspecified(emiList.getBlackListLen()); + }); + it('should fail to remove items', async function () { + expectRevert.unspecified(emiList.removeBlackListItems([bob, ivan])); + }); + it('should fail to get items', async function () { + expectRevert.unspecified(emiList.getBlackListItem(0)); + }); + }); + }); + describe('Check whitelist functions', ()=> { + beforeEach(async function () { + await emiList.addWhiteListItems([alice, bob, dave, ivan], {from: TestOwner}); + }); + + describe('When using admin account', ()=> { + it('should add items successfully', async function () { + let b = await emiList.getWhiteListLen({from: TestOwner}); + assert.equal(b, 4); + }); + it('should remove items successfully', async function () { + await emiList.removeWhiteListItems([bob, ivan], {from: TestOwner}); + let b = await emiList.getWhiteListLen({from: TestOwner}); + assert.equal(b, 4); // list length not actually changed! + var c; + // but addresses should not be in list set + for(var i = 0; i < b; i++) { + c = await emiList.getWhiteListItem(i, {from: TestOwner}); + assert.notEqual(c, bob); + assert.notEqual(c, ivan); + } + }); + it('should get items successfully', async function () { + let b = await emiList.getWhiteListItem(0, {from: TestOwner}); + assert.equal(b, alice); + b = await emiList.getWhiteListItem(1, {from: TestOwner}); + assert.equal(b, bob); + b = await emiList.getWhiteListItem(2, {from: TestOwner}); + assert.equal(b, dave); + b = await emiList.getWhiteListItem(3, {from: TestOwner}); + assert.equal(b, ivan); + }); + }); + describe('When using non-admin account', ()=> { + it('should fail to add items', async function () { + expectRevert(emiList.getWhiteListLen(), 'Ownable'); + }); + it('should fail to remove items', async function () { + expectRevert(emiList.removeWhiteListItems([bob, ivan]), 'Ownable'); + }); + it('should fail to get items', async function () { + expectRevert(emiList.getWhiteListItem(0), 'Ownable'); + }); + }); + }); + describe('Check admin functions', ()=> { + it('can set active mode under admin', async function () { + await emiList.setActionMode(1, {from: TestOwner}); + let b = await emiList.actionMode(); + assert.equal(b, 1); + }); + it('cannot set active mode under non-admin', async function () { + expectRevert(emiList.setActionMode(1), 'Ownable'); + }); + }); + describe('Check ESW transfers', () => { + beforeEach(async function () { + await emiList.addBlackListItems([alice, bob, dave, ivan], {from: TestOwner}); + await emiList.addWhiteListItems([clarc, henry], {from: TestOwner}); + }); + + describe('When emiList is not set', ()=> { + it('should transfer funds with transfer successfully', async function () { + await esw.transfer(henry, ether('0.03'), {from: dave}); + let b = await esw.balanceOf(henry); + expect(b).to.be.bignumber.equal(ether('0.03')); + }); + it('should transfer funds with transferFrom successfully', async function () { + await esw.approve(clarc, ether('0.1'), {from: dave}); + await esw.transferFrom(dave, henry, ether('0.02'), {from: clarc}); + let b = await esw.balanceOf(henry); + + expect(b).to.be.bignumber.equal(ether('0.02')); + }); + }); + describe('When emiList is set but not active', ()=> { + beforeEach(async function () { + await esw.setListAddress(emiList.address); + }); + it('should have mode=0', async function () { + let b = await emiList.actionMode(); + assert.equal(b, 0); + }); + it('should transfer funds with transfer successfully', async function () { + await esw.transfer(henry, ether('0.03'), {from: dave}); + let b = await esw.balanceOf(henry); + expect(b).to.be.bignumber.equal(ether('0.03')); + }); + it('should transfer funds with transferFrom successfully', async function () { + await esw.approve(clarc, ether('0.1'), {from: dave}); + await esw.transferFrom(dave, henry, ether('0.02'), {from: clarc}); + let b = await esw.balanceOf(henry); + + expect(b).to.be.bignumber.equal(ether('0.02')); + }); + }); + describe('When emiList is set to blacklist mode', ()=> { + beforeEach(async function () { + await esw.setListAddress(emiList.address); + await emiList.setActionMode(1, {from: TestOwner}); + }); + it('should have mode=1', async function () { + let b = await emiList.actionMode(); + assert.equal(b, 1); + }); + it('should transfer funds from non-blacklisted persons with transfer successfully', async function () { + await esw.transfer(alice, ether('0.03'), {from: clarc}); + let b = await esw.balanceOf(alice); + expect(b).to.be.bignumber.equal(ether('1.03')); + }); + it('should transfer funds from non-blacklisted persons with transferFrom successfully', async function () { + await esw.approve(henry, ether('0.1'), {from: clarc}); + await esw.transferFrom(clarc, bob, ether('0.02'), {from: henry}); + let b = await esw.balanceOf(bob); + + expect(b).to.be.bignumber.equal(ether('1.02')); + }); + it('should fail to transfer funds from blacklisted persons with transfer', async function () { + expectRevert(esw.transfer(henry, ether('0.03'), {from: alice}), 'blacklist'); + }); + it('should fail to transfer funds from blacklisted persons with transferFrom', async function () { + await esw.approve(alice, ether('0.1'), {from: bob}); + expectRevert(esw.transferFrom(bob, henry, ether('0.02'), {from: alice}), 'blacklist'); + }); + }); + describe('When emiList is set to whitelist mode', ()=> { + beforeEach(async function () { + await esw.setListAddress(emiList.address); + await emiList.setActionMode(2, {from: TestOwner}); + }); + it('should have mode=2', async function () { + let b = await emiList.actionMode(); + assert.equal(b, 2); + }); + it('should transfer funds from whitelisted persons with transfer successfully', async function () { + await esw.transfer(alice, ether('0.03'), {from: clarc}); + let b = await esw.balanceOf(alice); + expect(b).to.be.bignumber.equal(ether('1.03')); + }); + it('should transfer funds from whitelisted persons with transferFrom successfully', async function () { + await esw.approve(alice, ether('0.1'), {from: clarc}); + await esw.transferFrom(clarc, bob, ether('0.02'), {from: alice}); + let b = await esw.balanceOf(bob); + + expect(b).to.be.bignumber.equal(ether('1.02')); + }); + it('should fail to transfer funds from non-whitelisted persons with transfer', async function () { + expectRevert(esw.transfer(henry, ether('0.03'), {from: alice}), 'blacklist'); + expectRevert(esw.transfer(henry, ether('0.03'), {from: ivan}), 'blacklist'); + }); + it('should fail to transfer funds from non-whitelisted persons with transferFrom', async function () { + await esw.approve(ivan, ether('0.1'), {from: alice}); + expectRevert(esw.transferFrom(alice, henry, ether('0.02'), {from: ivan}), 'blacklist'); + }); + }); + describe('When emiList is set back to null address', ()=> { + beforeEach(async function () { + await esw.setListAddress(emiList.address); + await emiList.setActionMode(1, {from: TestOwner}); + await esw.setListAddress(ZERO_ADDRESS); + }); + it('should have mode=1', async function () { + let b = await emiList.actionMode(); + assert.equal(b, 1); + }); + it('should transfer funds from blacklisted persons with transfer successfully', async function () { + await esw.transfer(henry, ether('0.03'), {from: dave}); + let b = await esw.balanceOf(henry); + expect(b).to.be.bignumber.equal(ether('0.03')); + }); + it('should transfer funds from blacklisted persons with transferFrom successfully', async function () { + await esw.approve(clarc, ether('0.1'), {from: dave}); + await esw.transferFrom(dave, henry, ether('0.02'), {from: clarc}); + let b = await esw.balanceOf(henry); + + expect(b).to.be.bignumber.equal(ether('0.02')); + }); + }); + + }); +}); From 603244515ea00527d3e4fd0ccc47391db6f82679 Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 21 Jun 2021 11:22:55 +0200 Subject: [PATCH 04/24] Added getWhiteList, getBlackList --- contracts/ESW.sol | 10 +- contracts/EmiList.sol | 28 +- flat/ESW.full.sol | 38 +- flat/EmiList.full.sol | 519 ++++++++++++++++++++++++ flat/EmiVoting.full.sol | 681 +++++--------------------------- flat/VotableProxyAdmin.Full.sol | 86 ++-- package.json | 1 + test/EmiList.test.js | 20 + 8 files changed, 744 insertions(+), 639 deletions(-) create mode 100644 flat/EmiList.full.sol diff --git a/contracts/ESW.sol b/contracts/ESW.sol index 5cabbff..083c273 100644 --- a/contracts/ESW.sol +++ b/contracts/ESW.sol @@ -32,7 +32,7 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { mapping(address => uint256) public walletNonce; - address private emiList; + address private _emiList; function initialize() public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); @@ -82,11 +82,11 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { return true; } - function setListAddress(address _emiList) + function setListAddress(address emiList) public onlyAdmin { - emiList = _emiList; // can be NULL also to remove emiList functionality totally + _emiList = emiList; // can be NULL also to remove emiList functionality totally } /*********************** public functions *****************************/ @@ -192,8 +192,8 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { address to, uint256 amount ) internal override { - if (emiList != address(0)) { - require(IEmiList(emiList).approveTransfer(from, to, amount), "Transfer declined by blacklist"); + if (_emiList != address(0)) { + require(IEmiList(_emiList).approveTransfer(from, to, amount), "Transfer declined by blacklist"); } } diff --git a/contracts/EmiList.sol b/contracts/EmiList.sol index a4b14ee..17707a6 100644 --- a/contracts/EmiList.sol +++ b/contracts/EmiList.sol @@ -91,7 +91,7 @@ contract EmiList is Ownable, IEmiList { actionMode = mode; } - function addBlackListItems(address[] memory items) external onlyOwner + function addBlackListItems(address[] calldata items) external onlyOwner { address t; @@ -104,7 +104,7 @@ contract EmiList is Ownable, IEmiList { } } - function addWhiteListItems(address[] memory items) external onlyOwner + function addWhiteListItems(address[] calldata items) external onlyOwner { address t; @@ -117,7 +117,7 @@ contract EmiList is Ownable, IEmiList { } } - function removeBlackListItems(address[] memory items) external onlyOwner + function removeBlackListItems(address[] calldata items) external onlyOwner { address t; @@ -135,7 +135,7 @@ contract EmiList is Ownable, IEmiList { } } - function removeWhiteListItems(address[] memory items) external onlyOwner + function removeWhiteListItems(address[] calldata items) external onlyOwner { address t; @@ -166,4 +166,24 @@ contract EmiList is Ownable, IEmiList { return !blackList[from]; } + // Return WhiteList + function getWhiteList() + external + view + onlyOwner + returns (address[] memory) + { + return whiteListSet; + } + + // Return BlackList + function getBlackList() + external + view + onlyOwner + returns (address[] memory) + { + return blackListSet; + } + } diff --git a/flat/ESW.full.sol b/flat/ESW.full.sol index d6bb1f1..f223071 100644 --- a/flat/ESW.full.sol +++ b/flat/ESW.full.sol @@ -263,6 +263,20 @@ interface IEmiVesting { function getCrowdsaleLimit() external view returns (uint256); } +// File: contracts/interfaces/IEmiList.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +/************************************************************************* + * EmiList inerface + * + ************************************************************************/ +interface IEmiList { + function approveTransfer(address from, address to, uint256 amount) external view returns (bool); +} + // File: @openzeppelin/contracts/math/SafeMath.sol // SPDX-License-Identifier: MIT @@ -1096,6 +1110,7 @@ pragma solidity ^0.6.2; + contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { address public dividendToken; address public vesting; @@ -1105,7 +1120,9 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - string public codeVersion = "ESW v1.0-135-g59718c6"; + + string public codeVersion = "ESW v1.1-145-gf234c9e"; + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; bool public isFirstMinter = true; address public constant firstMinter = @@ -1118,6 +1135,8 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { mapping(address => uint256) public walletNonce; + address private _emiList; + function initialize() public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); _addAdmin(msg.sender); @@ -1166,6 +1185,13 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { return true; } + function setListAddress(address emiList) + public + onlyAdmin + { + _emiList = emiList; // can be NULL also to remove emiList functionality totally + } + /*********************** public functions *****************************/ function transferFrom( @@ -1264,6 +1290,16 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { ); } + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal override { + if (_emiList != address(0)) { + require(IEmiList(_emiList).approveTransfer(from, to, amount), "Transfer declined by blacklist"); + } + } + /*********************** internal functions *****************************/ function _mintAllowed( diff --git a/flat/EmiList.full.sol b/flat/EmiList.full.sol new file mode 100644 index 0000000..3e2984b --- /dev/null +++ b/flat/EmiList.full.sol @@ -0,0 +1,519 @@ +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () internal { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/interfaces/IEmiList.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +/************************************************************************* + * EmiList inerface + * + ************************************************************************/ +interface IEmiList { + function approveTransfer(address from, address to, uint256 amount) external view returns (bool); +} + +// File: contracts/EmiList.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + + + + +contract EmiList is Ownable, IEmiList { + using SafeMath for uint256; + + //----------------------------------------------------------------------------------- + // Data Structures + //----------------------------------------------------------------------------------- + + event ActionModeChanged(uint256 oldMode, uint256 newMode); + //----------------------------------------------------------------------------------- + // Variables, Instances, Mappings + //----------------------------------------------------------------------------------- + mapping(address => bool) private blackList; + mapping(address => bool) private whiteList; + + address[] private blackListSet; + address[] private whiteListSet; + + uint256 public actionMode; // 0: off, 1: blacklist, 2: whitelist + + //----------------------------------------------------------------------------------- + string public codeVersion = "EmiList v1.0-145-gf234c9e"; + + //----------------------------------------------------------------------------------- + // Smart contract Constructor + //----------------------------------------------------------------------------------- + + //----------------------------------------------------------------------------------- + // Observers + //----------------------------------------------------------------------------------- + function approveTransfer(address from, address to, uint256 amount) external view override returns (bool) + { + if (actionMode==1) { + return checkBlacklist(from, to, amount); + } + if (actionMode==2) { + return checkWhitelist(from, to, amount); + } + return true; // default case + } + + // Return unlock date and amount of given lock + function getWhiteListLen() + external + view + onlyOwner + returns (uint256) + { + return whiteListSet.length; + } + + function getBlackListLen() + external + view + onlyOwner + returns (uint256) + { + return blackListSet.length; + } + + function getWhiteListItem(uint256 idx) + external + view + onlyOwner + returns (address) + { + require(idx < whiteListSet.length, "Wrong list idx"); + return whiteListSet[idx]; + } + + function getBlackListItem(uint256 idx) + external + view + onlyOwner + returns (address) + { + require(idx < blackListSet.length, "Wrong list idx"); + return blackListSet[idx]; + } + + function setActionMode(uint256 mode) external onlyOwner + { + require(mode < 3 && mode != actionMode, "Wrong action mode"); + emit ActionModeChanged(actionMode, mode); + actionMode = mode; + } + + function addBlackListItems(address[] calldata items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (!blackList[t]) { // item not in the list, add + blackList[t] = true; + blackListSet.push(t); + } + } + } + + function addWhiteListItems(address[] calldata items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (!whiteList[t]) { // item not in the list, add + whiteList[t] = true; + whiteListSet.push(t); + } + } + } + + function removeBlackListItems(address[] calldata items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (blackList[t]) { // item is in the list, remove + blackList[t] = false; + for (uint256 j = 0; j < blackListSet.length; j++) { + if (blackListSet[j]==t) { + delete blackListSet[j]; + break; + } + } + } + } + } + + function removeWhiteListItems(address[] calldata items) external onlyOwner + { + address t; + + for (uint256 i = 0; i < items.length; i++) { + t = items[i]; + if (whiteList[t]) { // item is in the list, remove + whiteList[t] = false; + for (uint256 j = 0; j < whiteListSet.length; j++) { + if (whiteListSet[j]==t) { + delete whiteListSet[j]; + break; + } + } + } + } + } + + //----------------------------------------------------------------------------------- + // Observers + //----------------------------------------------------------------------------------- + function checkWhitelist(address from, address to, uint256 amount) internal view returns (bool) + { + return whiteList[from]; + } + + function checkBlacklist(address from, address to, uint256 amount) internal view returns (bool) + { + return !blackList[from]; + } + + // Return WhiteList + function getWhiteList() + external + view + onlyOwner + returns (address[] memory) + { + return whiteListSet; + } + + // Return BlackList + function getBlackList() + external + view + onlyOwner + returns (address[] memory) + { + return blackListSet; + } + +} diff --git a/flat/EmiVoting.full.sol b/flat/EmiVoting.full.sol index b0a87cb..9182589 100644 --- a/flat/EmiVoting.full.sol +++ b/flat/EmiVoting.full.sol @@ -499,48 +499,49 @@ pragma solidity ^0.6.2; abstract contract Priviledgeable { using SafeMath for uint256; - using SafeMath for uint256; + using SafeMath for uint; event PriviledgeGranted(address indexed admin); event PriviledgeRevoked(address indexed admin); modifier onlyAdmin() { - require( - _priviledgeTable[msg.sender], - "Priviledgeable: caller is not the owner" - ); + require(_priviledgeTable[msg.sender], "Priviledgeable: caller is not the owner"); _; } mapping(address => bool) private _priviledgeTable; - constructor() internal { - _priviledgeTable[msg.sender] = true; + constructor () internal { + _priviledgeTable[msg.sender] = true; } - function addAdmin(address _admin) external onlyAdmin returns (bool) { - require(_admin != address(0), "Admin address cannot be 0"); - return _addAdmin(_admin); + function addAdmin(address _admin) external onlyAdmin returns (bool) + { + require(_admin!=address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); } - function removeAdmin(address _admin) external onlyAdmin returns (bool) { - require(_admin != address(0), "Admin address cannot be 0"); - _priviledgeTable[_admin] = false; - emit PriviledgeRevoked(_admin); + function removeAdmin(address _admin) external onlyAdmin returns (bool) + { + require(_admin!=address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); - return true; + return true; } - function isAdmin(address _who) external view returns (bool) { - return _priviledgeTable[_who]; + function isAdmin(address _who) external view returns (bool) + { + return _priviledgeTable[_who]; } //----------- // internals //----------- - function _addAdmin(address _admin) internal returns (bool) { - _priviledgeTable[_admin] = true; - emit PriviledgeGranted(_admin); + function _addAdmin(address _admin) internal returns (bool) + { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); } } @@ -551,37 +552,13 @@ abstract contract Priviledgeable { pragma solidity ^0.6.2; interface IEmiVoting { - function getVotingResult(uint256 _hash) external view returns (address); -} - -// File: contracts/interfaces/IESW.sol - -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.6.0; - -/** - * @dev Interface of the DAO token. - */ -interface IESW { - function name() external returns (string memory); - - function balanceOf(address account) external view returns (uint256); - - function symbol() external returns (string memory); - - function decimals() external returns (uint8); - - function initialSupply() external returns (uint256); - - function burn(address account, uint256 amount) external; + event VotingCreated(uint indexed hash, uint endTime); + event VotingFinished(uint indexed hash, uint result); - function mintClaimed(address recipient, uint256 amount) external; - - function getPriorVotes(address account, uint256 blockNumber) - external - view - returns (uint96); + function getVoting(uint _hash) external view returns (address, address, uint, uint); + function newUpgradeVoting(address _oldContract, address _newContract, uint _votingEndTime, uint _hash) external returns (uint); + function getVotingResult(uint _hash) external view returns (address); + function calcVotingResult(uint _hash) external; } // File: contracts/EmiVoting.sol @@ -589,8 +566,6 @@ interface IESW { // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; -pragma experimental ABIEncoderV2; - @@ -599,544 +574,88 @@ pragma experimental ABIEncoderV2; contract EmiVoting is IEmiVoting, Initializable, Priviledgeable { - using SafeMath for uint256; - using Address for address; - - string public codeVersion = "EmiVoting v1.0-57-g342d161"; - - /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed - function quorumVotes() public pure returns (uint256) { - return 400000e18; - } // 400,000 - - /// @notice The number of votes required in order for a voter to become a proposer - function proposalThreshold() public pure returns (uint256) { - return 100000e18; - } // 100,000 - - /// @notice The maximum number of actions that can be included in a proposal - function proposalMaxOperations() public pure returns (uint256) { - return 10; - } // 10 actions - - /// @notice The delay before voting on a proposal may take place, once proposed - function votingDelay() public pure returns (uint256) { - return 1; - } // 1 block - - /// @notice The address of the Timelock - TimelockInterface public timelock; - - /// @notice The address of the governance token - IESW public comp; - - /// @notice The address of the Governor Guardian - address public guardian; - - /// @notice The total number of proposals - uint256 public proposalCount; - - struct Proposal { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - uint256 forVotes; - /// @notice Current number of votes in opposition to this proposal - uint256 againstVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice Receipts of ballots for the entire set of voters - mapping(address => Receipt) receipts; - } - - /// @notice Ballot receipt record for a voter - struct Receipt { - /// @notice Whether or not a vote has been cast - bool hasVoted; - /// @notice Whether or not the voter supports the proposal - bool support; - /// @notice The number of votes the voter had, which were cast - uint96 votes; - } - - /// @notice Possible states that a proposal may be in - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed - } - - /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) public proposals; - - /// @notice The latest proposal for each proposer - mapping(address => uint256) public latestProposalIds; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256( - "EIP712Domain(string name,uint256 chainId,address verifyingContract)" - ); - - /// @notice The EIP-712 typehash for the ballot struct used by the contract - bytes32 public constant BALLOT_TYPEHASH = - keccak256("Ballot(uint256 proposalId,bool support)"); - - /// @notice An event emitted when a new proposal is created - event ProposalCreated( - uint256 id, - address proposer, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, - string description - ); - - /// @notice An event emitted when a vote has been cast on a proposal - event VoteCast( - address voter, - uint256 proposalId, - bool support, - uint256 votes - ); - - /// @notice An event emitted when a proposal has been canceled - event ProposalCanceled(uint256 id); - - /// @notice An event emitted when a proposal has been queued in the Timelock - event ProposalQueued(uint256 id, uint256 eta); - - /// @notice An event emitted when a proposal has been executed in the Timelock - event ProposalExecuted(uint256 id); - - constructor( - address timelock_, - address esw_, - address guardian_ - ) public { - timelock = TimelockInterface(timelock_); - comp = IESW(esw_); - guardian = guardian_; - } - - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description, - uint256 votingPeriod - ) public returns (uint256) { - require( - comp.balanceOf(msg.sender) > proposalThreshold(), - "EmiVoting::propose: proposer votes below proposal threshold" - ); - require( - targets.length == values.length && - targets.length == signatures.length && - targets.length == calldatas.length, - "EmiVoting::propose: proposal function information arity mismatch" - ); - require( - targets.length != 0, - "EmiVoting::propose: must provide actions" - ); - require( - targets.length <= proposalMaxOperations(), - "EmiVoting::propose: too many actions" - ); - - uint256 latestProposalId = latestProposalIds[msg.sender]; - if (latestProposalId != 0) { - ProposalState proposersLatestProposalState = - state(latestProposalId); - require( - proposersLatestProposalState != ProposalState.Active, - "EmiVoting::propose: one live proposal per proposer, found an already active proposal" - ); - require( - proposersLatestProposalState != ProposalState.Pending, - "EmiVoting::propose: one live proposal per proposer, found an already pending proposal" - ); - } - - uint256 startBlock = block.number.add(votingDelay()); - uint256 endBlock = startBlock.add(votingPeriod); - - proposalCount++; - Proposal memory newProposal = - Proposal({ - id: proposalCount, - proposer: msg.sender, - eta: 0, - targets: targets, - values: values, - signatures: signatures, - calldatas: calldatas, - startBlock: startBlock, - endBlock: endBlock, - forVotes: 0, - againstVotes: 0, - canceled: false, - executed: false - }); - - proposals[newProposal.id] = newProposal; - latestProposalIds[newProposal.proposer] = newProposal.id; - - emit ProposalCreated( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - startBlock, - endBlock, - description - ); - return newProposal.id; - } - - function queue(uint256 proposalId) public { - require( - state(proposalId) == ProposalState.Succeeded, - "EmiVoting::queue: proposal can only be queued if it is succeeded" - ); - Proposal storage proposal = proposals[proposalId]; - uint256 eta = block.timestamp.add(timelock.delay()); - for (uint256 i = 0; i < proposal.targets.length; i++) { - _queueOrRevert( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - eta - ); - } - proposal.eta = eta; - emit ProposalQueued(proposalId, eta); - } - - function _queueOrRevert( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - require( - !timelock.queuedTransactions( - keccak256(abi.encode(target, value, signature, data, eta)) - ), - "EmiVoting::_queueOrRevert: proposal action already queued at eta" - ); - timelock.queueTransaction(target, value, signature, data, eta); - } + using SafeMath for uint256; + using Address for address; - function execute(uint256 proposalId) public payable { - require( - state(proposalId) == ProposalState.Queued, - "EmiVoting::execute: proposal can only be executed if it is queued" - ); - Proposal storage proposal = proposals[proposalId]; - proposal.executed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.executeTransaction.value(proposal.values[i])( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - emit ProposalExecuted(proposalId); - } - - function cancel(uint256 proposalId) public { - ProposalState state = state(proposalId); - require( - state != ProposalState.Executed, - "EmiVoting::cancel: cannot cancel executed proposal" - ); - - Proposal storage proposal = proposals[proposalId]; - require( - msg.sender == guardian || - comp.getPriorVotes(proposal.proposer, block.number.sub(1)) < - proposalThreshold(), - "EmiVoting::cancel: proposer above threshold" - ); - - proposal.canceled = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } + struct VotingRecord { + address oldContract; + address newContract; + uint endTime; + uint voteResult; + } - emit ProposalCanceled(proposalId); - } + mapping(uint => VotingRecord) private _votingList; + uint[] private _votingHash; + string public codeVersion = "EmiVoting v1.0-39-g38801b0"; - function getActions(uint256 proposalId) - public - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) + function initialize(address _admin) public initializer { - Proposal storage p = proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); + _addAdmin(msg.sender); + _addAdmin(_admin); } - function getReceipt(uint256 proposalId, address voter) - public - view - returns (Receipt memory) + //----------------------------------------------------------------------------------- + // Observers + //----------------------------------------------------------------------------------- + // Return unlock date and amount of given lock + function getVoting(uint _hash) external override view returns (address, address, uint, uint) { - return proposals[proposalId].receipts[voter]; - } - - function state(uint256 proposalId) public view returns (ProposalState) { - require( - proposalCount >= proposalId && proposalId > 0, - "EmiVoting::state: invalid proposal id" - ); - Proposal storage proposal = proposals[proposalId]; - if (proposal.canceled) { - return ProposalState.Canceled; - } else if (block.number <= proposal.startBlock) { - return ProposalState.Pending; - } else if (block.number <= proposal.endBlock) { - return ProposalState.Active; - } else if ( - proposal.forVotes <= proposal.againstVotes || - proposal.forVotes < quorumVotes() - ) { - return ProposalState.Defeated; - } else if (proposal.eta == 0) { - return ProposalState.Succeeded; - } else if (proposal.executed) { - return ProposalState.Executed; - } else if ( - block.timestamp >= proposal.eta.add(timelock.GRACE_PERIOD()) - ) { - return ProposalState.Expired; - } else { - return ProposalState.Queued; - } + return (_votingList[_hash].oldContract, _votingList[_hash].newContract, _votingList[_hash].endTime, _votingList[_hash].voteResult); } - function castVote(uint256 proposalId, bool support) public { - return - _castVote( - msg.sender, - uint96(comp.balanceOf(msg.sender)), - proposalId, - support - ); - } - - function castVoteBySig( - uint256 proposalId, - bool support, - uint96 voterAmount, - uint8 v, - bytes32 r, - bytes32 s - ) public { - bytes32 domainSeparator = - keccak256( - abi.encode( - DOMAIN_TYPEHASH, - keccak256(bytes("EmiVoting")), - getChainId(), - address(this) - ) - ); - bytes32 structHash = - keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support)); - bytes32 digest = - keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - address signatory = ecrecover(digest, v, r, s); - require( - signatory != address(0), - "EmiVoting::castVoteBySig: invalid signature" - ); - return _castVote(signatory, voterAmount, proposalId, support); - } - - function _castVote( - address voter, - uint96 voterAmount, - uint256 proposalId, - bool support - ) internal { - require( - state(proposalId) == ProposalState.Active, - "EmiVoting::_castVote: voting is closed" - ); - Proposal storage proposal = proposals[proposalId]; - Receipt storage receipt = proposal.receipts[voter]; - require( - receipt.hasVoted == false, - "EmiVoting::_castVote: voter already voted" - ); - - if (support) { - proposal.forVotes = proposal.forVotes.add(voterAmount); - } else { - proposal.againstVotes = proposal.againstVotes.add(voterAmount); - } - - receipt.hasVoted = true; - receipt.support = support; - receipt.votes = voterAmount; - - emit VoteCast(voter, proposalId, support, voterAmount); - } - - function __acceptAdmin() public { - require( - msg.sender == guardian, - "EmiVoting::__acceptAdmin: sender must be gov guardian" - ); - timelock.acceptAdmin(); - } - - function __abdicate() public { - require( - msg.sender == guardian, - "EmiVoting::__abdicate: sender must be gov guardian" - ); - guardian = address(0); - } - - function __queueSetTimelockPendingAdmin( - address newPendingAdmin, - uint256 eta - ) public { - require( - msg.sender == guardian, - "EmiVoting::__queueSetTimelockPendingAdmin: sender must be gov guardian" - ); - timelock.queueTransaction( - address(timelock), - 0, - "setPendingAdmin(address)", - abi.encode(newPendingAdmin), - eta - ); - } - - function __executeSetTimelockPendingAdmin( - address newPendingAdmin, - uint256 eta - ) public { - require( - msg.sender == guardian, - "EmiVoting::__executeSetTimelockPendingAdmin: sender must be gov guardian" - ); - timelock.executeTransaction( - address(timelock), - 0, - "setPendingAdmin(address)", - abi.encode(newPendingAdmin), - eta - ); - } - - function getChainId() internal pure returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } - - // returns address if voting succeeded or 0 othervise - function getVotingResult(uint256 _hash) - external - view - override - returns (address) + function getVotingHash(uint8 idx) external onlyAdmin view returns (uint) { - ProposalState ps = state(_hash); - - if (ps == ProposalState.Succeeded || ps == ProposalState.Queued) { - (address[] memory t, , , ) = getActions(_hash); - return t[0]; - } else { - return address(0); - } + require(idx < _votingHash.length, "Voting index is out of range"); + return _votingHash[idx]; } -} -interface TimelockInterface { - function delay() external view returns (uint256); - - function GRACE_PERIOD() external view returns (uint256); - - function acceptAdmin() external; - - function queuedTransactions(bytes32 hash) external view returns (bool); - - function queueTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external returns (bytes32); - - function cancelTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external; - - function executeTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external payable returns (bytes memory); -} + function getVotingLen() external onlyAdmin view returns (uint) + { + return _votingHash.length; + } + + // starts new voting for upgrading contract + // return + function newUpgradeVoting(address _oldContract, address _newContract, uint _votingEndTime, uint _hash) external override onlyAdmin returns (uint) { + require(_oldContract!=address(0), "Old contract cannot be null"); + require(_newContract!=address(0), "New contract cannot be null"); + require(_votingEndTime > block.timestamp, "Voting end time is in the past"); + require(_hash!=0, "Hash cannot be 0"); + + _votingList[_hash].oldContract = _oldContract; + _votingList[_hash].newContract = _newContract; + _votingList[_hash].endTime = _votingEndTime; + _votingList[_hash].voteResult = 0; + _votingHash.push(_hash); + + emit VotingCreated(_hash, _votingEndTime); + + return _hash; + } + + // returns address if voting succeeded or 0 othervise + function getVotingResult(uint _hash) external view override returns (address) { + VotingRecord memory v = _votingList[_hash]; + + if (v.endTime > block.timestamp) { // voting is not finished yet + return address(0); + } else { + if (v.voteResult == 2) { // voting succeeded + return v.newContract; + } else { + return address(0); + } + } + } + + // calculates and returns 0 if no results, 1 if voting negative, 2 if voting positive + function calcVotingResult(uint _hash) external override { + require(_votingList[_hash].endTime != 0, "Wrong hash value"); + VotingRecord memory vr = _votingList[_hash]; + + if (vr.voteResult == 0 && vr.endTime <= block.timestamp) { + _votingList[_hash].voteResult = 2; // always positive + emit VotingFinished(_hash, 2); + } + } +} \ No newline at end of file diff --git a/flat/VotableProxyAdmin.Full.sol b/flat/VotableProxyAdmin.Full.sol index 195a892..9708f45 100644 --- a/flat/VotableProxyAdmin.Full.sol +++ b/flat/VotableProxyAdmin.Full.sol @@ -834,7 +834,13 @@ library SafeMath { pragma solidity ^0.6.2; interface IEmiVoting { - function getVotingResult(uint256 _hash) external view returns (address); + event VotingCreated(uint indexed hash, uint endTime); + event VotingFinished(uint indexed hash, uint result); + + function getVoting(uint _hash) external view returns (address, address, uint, uint); + function newUpgradeVoting(address _oldContract, address _newContract, uint _votingEndTime, uint _hash) external returns (uint); + function getVotingResult(uint _hash) external view returns (address); + function calcVotingResult(uint _hash) external; } // File: contracts/VotableProxyAdmin.sol @@ -848,76 +854,63 @@ pragma solidity ^0.6.2; + /** - * @dev Returns the current implementation of `proxy`. - * - * Requirements: - * - * - This contract must be the admin of `proxy`. + * @dev Returns the current implementation of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. */ contract EmiVotableProxyAdmin is Ownable { - using SafeMath for uint256; + using SafeMath for uint256; - IEmiVoting private _votingContract; + IEmiVoting private _votingContract; + string public codeVersion = "VotableProxyAdmin v1.0-39-g38801b0"; - string public codeVersion = "VotableProxyAdmin v1.0-58-gd991927"; - - constructor(address _vc) public { - require(_vc != address(0), "Voting contract address cannot be 0"); - _votingContract = IEmiVoting(_vc); - } + constructor (address _vc) public { + require(_vc!=address(0), "Voting contract address cannot be 0"); + _votingContract = IEmiVoting(_vc); + } /** * @dev Returns the current implementation of `proxy`. - * + * * Requirements: - * + * * - This contract must be the admin of `proxy`. */ - function getProxyImplementation(TransparentUpgradeableProxy proxy) - public - view - returns (address) - { + function getProxyImplementation(TransparentUpgradeableProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b - (bool success, bytes memory returndata) = - address(proxy).staticcall(hex"5c60da1b"); + (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); } /** * @dev Returns the current admin of `proxy`. - * + * * Requirements: - * + * * - This contract must be the admin of `proxy`. */ - function getProxyAdmin(TransparentUpgradeableProxy proxy) - public - view - returns (address) - { + function getProxyAdmin(TransparentUpgradeableProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 - (bool success, bytes memory returndata) = - address(proxy).staticcall(hex"f851a440"); + (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); } /** * @dev Changes the admin of `proxy` to `newAdmin`. - * + * * Requirements: - * + * * - This contract must be the current admin of `proxy`. */ - function changeProxyAdmin( - TransparentUpgradeableProxy proxy, - address newAdmin - ) public onlyOwner { + function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public onlyOwner { proxy.changeAdmin(newAdmin); } @@ -926,15 +919,12 @@ contract EmiVotableProxyAdmin is Ownable { _votingContract = IEmiVoting(_newVoting); } - function upgrade(TransparentUpgradeableProxy proxy, uint256 votingHash) - public - onlyOwner - { - address impl; + function upgrade(TransparentUpgradeableProxy proxy, uint votingHash) public onlyOwner { + address impl; - impl = _votingContract.getVotingResult(votingHash); - require(impl != address(0), "Voting has wrong implementation address"); + impl = _votingContract.getVotingResult(votingHash); + require(impl != address(0), "Voting has wrong implementation address"); - proxy.upgradeTo(impl); - } -} + proxy.upgradeTo(impl); + } +} \ No newline at end of file diff --git a/package.json b/package.json index 35abf9c..bd6a296 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "dist:emivoting": "truffle-flattener ./contracts/EmiVoting.sol > ./flat/EmiVoting.full.sol", "dist:emireferral": "truffle-flattener ./contracts/EmiReferral.sol > ./flat/EmiReferral.full.sol", "dist:esw": "truffle-flattener ./contracts/ESW.sol > ./flat/ESW.full.sol", + "dist:emilist": "truffle-flattener ./contracts/EmiList.sol > ./flat/EmiList.full.sol", "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", "dist:emivamp": "node update-version.js && truffle-flattener ./contracts/EmiVamp.sol > ./flat/EmiVamp.Full.sol", diff --git a/test/EmiList.test.js b/test/EmiList.test.js index dc97bd1..41800ac 100644 --- a/test/EmiList.test.js +++ b/test/EmiList.test.js @@ -58,6 +58,16 @@ describe('EmiList test', function () { assert.notEqual(c, ivan); } }); + it('should return all blacklist items', async () => { + let bl = await emiList.getBlackList({from: TestOwner}); + assert.equal(bl[0], alice); + assert.equal(bl[1], bob); + assert.equal(bl[2], dave); + assert.equal(bl[3], ivan); + }); + it('should fail when return all blacklist items from not owner', async () => { + expectRevert.unspecified(await emiList.getBlackList({from: TestOwner})); + }); it('should get items successfully', async function () { let b = await emiList.getBlackListItem(0, {from: TestOwner}); assert.equal(b, alice); @@ -113,6 +123,16 @@ describe('EmiList test', function () { b = await emiList.getWhiteListItem(3, {from: TestOwner}); assert.equal(b, ivan); }); + it('should return all whitelist items', async () => { + let bl = await emiList.getWhiteList({from: TestOwner}); + assert.equal(bl[0], alice); + assert.equal(bl[1], bob); + assert.equal(bl[2], dave); + assert.equal(bl[3], ivan); + }); + it('should fail when return all blacklist items from not owner', async () => { + expectRevert.unspecified(await emiList.getWhiteList({from: TestOwner})); + }); }); describe('When using non-admin account', ()=> { it('should fail to add items', async function () { From fcb7e655dea991d906fb69e39bb543e81a539faf Mon Sep 17 00:00:00 2001 From: Maksim Date: Fri, 25 Jun 2021 16:03:40 +0200 Subject: [PATCH 05/24] Added matic ESW version --- contracts/ESW-matic.sol | 60 +++ flat/ESW-matic.full.sol | 1078 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 1139 insertions(+) create mode 100644 contracts/ESW-matic.sol create mode 100644 flat/ESW-matic.full.sol diff --git a/contracts/ESW-matic.sol b/contracts/ESW-matic.sol new file mode 100644 index 0000000..809c16e --- /dev/null +++ b/contracts/ESW-matic.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/ProxiedERC20.sol"; + +contract ESW is ProxiedERC20, Initializable, Priviledgeable { + + string public codeVersion = "ESW v1.1-145-gf234c9e"; + + // keeping it for checking, whether deposit being called by valid address or not + address public childChainManagerProxy; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + function initialize() public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(msg.sender); + } + + function deposit(address user, bytes calldata depositData) external { + require(msg.sender == childChainManagerProxy, "You're not allowed to deposit"); + + uint256 amount = abi.decode(depositData, (uint256)); + + // `amount` token getting minted here & equal amount got locked in RootChainManager + + super._mint(user, amount); + /* _totalSupply = _totalSupply.add(amount); + _balances[user] = _balances[user].add(amount); + + emit Transfer(address(0), user, amount); */ + } + + function withdraw(uint256 amount) external { + super._burn(msg.sender, amount); + /* _balances[msg.sender] = _balances[msg.sender].sub(amount, "ERC20: burn amount exceeds balance"); + _totalSupply = _totalSupply.sub(amount); + + emit Transfer(msg.sender, address(0), amount); */ + } + + /*********************** admin functions *****************************/ + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + // being proxified smart contract, most probably childChainManagerProxy contract's address + // is not going to change ever, but still, lets keep it + function updateChildChainManager(address newChildChainManagerProxy) external onlyAdmin { + require(newChildChainManagerProxy != address(0), "Bad ChildChainManagerProxy address"); + + childChainManagerProxy = newChildChainManagerProxy; + } +} \ No newline at end of file diff --git a/flat/ESW-matic.full.sol b/flat/ESW-matic.full.sol new file mode 100644 index 0000000..df991aa --- /dev/null +++ b/flat/ESW-matic.full.sol @@ -0,0 +1,1078 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/GSN/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/libraries/ProxiedERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ProxiedERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint8 private _intialized; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function _initialize( + string memory name, + string memory symbol, + uint8 decimals + ) internal { + require(_intialized == 0, "Already intialize"); + _name = name; + _symbol = symbol; + _decimals = decimals; + _intialized = 1; + } + + /** + * @dev Returns the name of the token. + */ + function _updateTokenName(string memory newName, string memory newSymbol) + internal + { + _name = newName; + _symbol = newSymbol; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) + public + view + virtual + override + returns (uint256) + { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + +// File: contracts/ESW-matic.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable { + + string public codeVersion = "ESW v1.1-145-gf234c9e"; + + // keeping it for checking, whether deposit being called by valid address or not + address public childChainManagerProxy; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + function initialize() public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(msg.sender); + } + + function deposit(address user, bytes calldata depositData) external { + require(msg.sender == childChainManagerProxy, "You're not allowed to deposit"); + + uint256 amount = abi.decode(depositData, (uint256)); + + // `amount` token getting minted here & equal amount got locked in RootChainManager + + super._mint(user, amount); + /* _totalSupply = _totalSupply.add(amount); + _balances[user] = _balances[user].add(amount); + + emit Transfer(address(0), user, amount); */ + } + + function withdraw(uint256 amount) external { + super._burn(msg.sender, amount); + /* _balances[msg.sender] = _balances[msg.sender].sub(amount, "ERC20: burn amount exceeds balance"); + _totalSupply = _totalSupply.sub(amount); + + emit Transfer(msg.sender, address(0), amount); */ + } + + /*********************** admin functions *****************************/ + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + // being proxified smart contract, most probably childChainManagerProxy contract's address + // is not going to change ever, but still, lets keep it + function updateChildChainManager(address newChildChainManagerProxy) external onlyAdmin { + require(newChildChainManagerProxy != address(0), "Bad ChildChainManagerProxy address"); + + childChainManagerProxy = newChildChainManagerProxy; + } +} diff --git a/package.json b/package.json index bd6a296..e8a79d3 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "dist:emivoting": "truffle-flattener ./contracts/EmiVoting.sol > ./flat/EmiVoting.full.sol", "dist:emireferral": "truffle-flattener ./contracts/EmiReferral.sol > ./flat/EmiReferral.full.sol", "dist:esw": "truffle-flattener ./contracts/ESW.sol > ./flat/ESW.full.sol", + "dist:esw-matic": "truffle-flattener ./contracts/ESW-matic.sol > ./flat/ESW-matic.full.sol", "dist:emilist": "truffle-flattener ./contracts/EmiList.sol > ./flat/EmiList.full.sol", "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", From 122b095a159e6b4fa3c9017fed749bdb2c2aaafc Mon Sep 17 00:00:00 2001 From: Maksim Date: Fri, 25 Jun 2021 16:09:31 +0200 Subject: [PATCH 06/24] added deployerAdmin --- contracts/ESW-matic.sol | 5 +++-- flat/ESW-matic.full.sol | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/ESW-matic.sol b/contracts/ESW-matic.sol index 809c16e..d56e47a 100644 --- a/contracts/ESW-matic.sol +++ b/contracts/ESW-matic.sol @@ -15,9 +15,10 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - function initialize() public virtual initializer { + function initialize(address deployerAdmin) public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); - _addAdmin(msg.sender); + _addAdmin(msg.sender); + _addAdmin(deployerAdmin); } function deposit(address user, bytes calldata depositData) external { diff --git a/flat/ESW-matic.full.sol b/flat/ESW-matic.full.sol index df991aa..c12ce32 100644 --- a/flat/ESW-matic.full.sol +++ b/flat/ESW-matic.full.sol @@ -1033,9 +1033,10 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - function initialize() public virtual initializer { + function initialize(address deployerAdmin) public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); - _addAdmin(msg.sender); + _addAdmin(msg.sender); + _addAdmin(deployerAdmin); } function deposit(address user, bytes calldata depositData) external { From 31f894375b04b63bdb2314815ad35e512b91cf2f Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 28 Jun 2021 11:14:56 +0200 Subject: [PATCH 07/24] ESW-matic with EmiList feature --- contracts/ESW-matic.sol | 45 ++++++++++++++++++++++++------- flat/ESW-matic.full.sol | 59 ++++++++++++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/contracts/ESW-matic.sol b/contracts/ESW-matic.sol index d56e47a..80975fd 100644 --- a/contracts/ESW-matic.sol +++ b/contracts/ESW-matic.sol @@ -2,12 +2,17 @@ pragma solidity ^0.6.2; import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./interfaces/IEmiList.sol"; import "./libraries/Priviledgeable.sol"; import "./libraries/ProxiedERC20.sol"; contract ESW is ProxiedERC20, Initializable, Priviledgeable { - string public codeVersion = "ESW v1.1-145-gf234c9e"; + uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + + address private _emiList; + + string public codeVersion = "ESW-matic v1.0"; // keeping it for checking, whether deposit being called by valid address or not address public childChainManagerProxy; @@ -21,29 +26,51 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable { _addAdmin(deployerAdmin); } + function getVersion() public view returns (string memory) { + return(codeVersion); + } + function deposit(address user, bytes calldata depositData) external { require(msg.sender == childChainManagerProxy, "You're not allowed to deposit"); uint256 amount = abi.decode(depositData, (uint256)); + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW-matic:supply_exceeded" + ); + // `amount` token getting minted here & equal amount got locked in RootChainManager super._mint(user, amount); - /* _totalSupply = _totalSupply.add(amount); - _balances[user] = _balances[user].add(amount); - - emit Transfer(address(0), user, amount); */ } function withdraw(uint256 amount) external { super._burn(msg.sender, amount); - /* _balances[msg.sender] = _balances[msg.sender].sub(amount, "ERC20: burn amount exceeds balance"); - _totalSupply = _totalSupply.sub(amount); - - emit Transfer(msg.sender, address(0), amount); */ + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal override { + if (_emiList != address(0)) { + require(IEmiList(_emiList).approveTransfer(from, to, amount), "Not allowed"); + } } /*********************** admin functions *****************************/ + function getEmilistWallet() public view onlyAdmin returns(address) { + return(_emiList); + } + + function setListAddress(address emiList) + public + onlyAdmin + { + _emiList = emiList; // can be NULL also to remove emiList functionality totally + } + function updateTokenName(string memory newName, string memory newSymbol) public onlyAdmin diff --git a/flat/ESW-matic.full.sol b/flat/ESW-matic.full.sol index c12ce32..84f768e 100644 --- a/flat/ESW-matic.full.sol +++ b/flat/ESW-matic.full.sol @@ -247,6 +247,20 @@ abstract contract Initializable { } } +// File: contracts/interfaces/IEmiList.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +/************************************************************************* + * EmiList inerface + * + ************************************************************************/ +interface IEmiList { + function approveTransfer(address from, address to, uint256 amount) external view returns (bool); +} + // File: @openzeppelin/contracts/math/SafeMath.sol // SPDX-License-Identifier: MIT @@ -1023,9 +1037,14 @@ pragma solidity ^0.6.2; + contract ESW is ProxiedERC20, Initializable, Priviledgeable { - string public codeVersion = "ESW v1.1-145-gf234c9e"; + uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + + address private _emiList; + + string public codeVersion = "ESW-matic v1.0"; // keeping it for checking, whether deposit being called by valid address or not address public childChainManagerProxy; @@ -1039,29 +1058,51 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable { _addAdmin(deployerAdmin); } + function getVersion() public view returns (string memory) { + return(codeVersion); + } + function deposit(address user, bytes calldata depositData) external { require(msg.sender == childChainManagerProxy, "You're not allowed to deposit"); uint256 amount = abi.decode(depositData, (uint256)); + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW-matic:supply_exceeded" + ); + // `amount` token getting minted here & equal amount got locked in RootChainManager super._mint(user, amount); - /* _totalSupply = _totalSupply.add(amount); - _balances[user] = _balances[user].add(amount); - - emit Transfer(address(0), user, amount); */ } function withdraw(uint256 amount) external { super._burn(msg.sender, amount); - /* _balances[msg.sender] = _balances[msg.sender].sub(amount, "ERC20: burn amount exceeds balance"); - _totalSupply = _totalSupply.sub(amount); - - emit Transfer(msg.sender, address(0), amount); */ + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal override { + if (_emiList != address(0)) { + require(IEmiList(_emiList).approveTransfer(from, to, amount), "Not allowed"); + } } /*********************** admin functions *****************************/ + function getEmilistWallet() public view onlyAdmin returns(address) { + return(_emiList); + } + + function setListAddress(address emiList) + public + onlyAdmin + { + _emiList = emiList; // can be NULL also to remove emiList functionality totally + } + function updateTokenName(string memory newName, string memory newSymbol) public onlyAdmin From 2d066b7728542d51fd47e87b51d492d4e8826e26 Mon Sep 17 00:00:00 2001 From: Maksim Date: Sun, 11 Jul 2021 00:54:18 +0200 Subject: [PATCH 08/24] Prepared for kucoin deployment --- contracts/ESW-kucoin.sol | 147 ++++ contracts/EmiVault-kucoin.sol | 82 +++ flat/ESW-kucoin.full.sol | 1221 +++++++++++++++++++++++++++++++++ flat/EmiVault-kucoin.Full.sol | 814 ++++++++++++++++++++++ package.json | 2 + 5 files changed, 2266 insertions(+) create mode 100644 contracts/ESW-kucoin.sol create mode 100644 contracts/EmiVault-kucoin.sol create mode 100644 flat/ESW-kucoin.full.sol create mode 100644 flat/EmiVault-kucoin.Full.sol diff --git a/contracts/ESW-kucoin.sol b/contracts/ESW-kucoin.sol new file mode 100644 index 0000000..1a8556e --- /dev/null +++ b/contracts/ESW-kucoin.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/ProxiedERC20.sol"; +import "./libraries/OracleSign.sol"; + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-kucoin v1.0-228-ge748b4a"; + + uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 20_000_000e18); + } + + /*********************** admin functions *****************************/ + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} \ No newline at end of file diff --git a/contracts/EmiVault-kucoin.sol b/contracts/EmiVault-kucoin.sol new file mode 100644 index 0000000..755b8ef --- /dev/null +++ b/contracts/EmiVault-kucoin.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/OracleSign.sol"; + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-kucoin v1.0-228-ge748b4a"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/ESW-kucoin.full.sol b/flat/ESW-kucoin.full.sol new file mode 100644 index 0000000..29f4823 --- /dev/null +++ b/flat/ESW-kucoin.full.sol @@ -0,0 +1,1221 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/GSN/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/libraries/ProxiedERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ProxiedERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint8 private _intialized; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function _initialize( + string memory name, + string memory symbol, + uint8 decimals + ) internal { + require(_intialized == 0, "Already intialize"); + _name = name; + _symbol = symbol; + _decimals = decimals; + _intialized = 1; + } + + /** + * @dev Returns the name of the token. + */ + function _updateTokenName(string memory newName, string memory newSymbol) + internal + { + _name = newName; + _symbol = newSymbol; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) + public + view + virtual + override + returns (uint256) + { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/ESW-kucoin.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW v1.1-145-gf234c9e"; + + uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(msg.sender); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 20_000_000e18); + } + + /*********************** admin functions *****************************/ + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} diff --git a/flat/EmiVault-kucoin.Full.sol b/flat/EmiVault-kucoin.Full.sol new file mode 100644 index 0000000..421f127 --- /dev/null +++ b/flat/EmiVault-kucoin.Full.sol @@ -0,0 +1,814 @@ +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/EmiVault-kucoin.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + + + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-kucoin v1.0-228-ge748b4a"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/package.json b/package.json index e8a79d3..079aaf0 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "dist:emireferral": "truffle-flattener ./contracts/EmiReferral.sol > ./flat/EmiReferral.full.sol", "dist:esw": "truffle-flattener ./contracts/ESW.sol > ./flat/ESW.full.sol", "dist:esw-matic": "truffle-flattener ./contracts/ESW-matic.sol > ./flat/ESW-matic.full.sol", + "dist:esw-kucoin": "truffle-flattener ./contracts/ESW-kucoin.sol > ./flat/ESW-kucoin.full.sol", "dist:emilist": "truffle-flattener ./contracts/EmiList.sol > ./flat/EmiList.full.sol", "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", @@ -102,6 +103,7 @@ "dist:emirouter": "node update-version.js && truffle-flattener ./contracts/EmiRouter.sol > ./flat/EmiRouter.Full.sol", "dist:mocktoken": "truffle-flattener ./contracts/mocks/MockWBTC.sol > ./flat/MockWBTC.Full.sol", "dist:emivault": "node update-version.js && truffle-flattener ./contracts/EmiVault.sol > ./flat/EmiVault.Full.sol", + "dist:emivault-kucoin": "node update-version.js && truffle-flattener ./contracts/EmiVault-kucoin.sol > ./flat/EmiVault-kucoin.Full.sol", "dist:emiprice": "node update-version.js && truffle-flattener ./contracts/EmiPrice.sol > ./flat/EmiPrice.Full.sol", "dist:emiprice2": "node update-version.js && truffle-flattener ./contracts/EmiPrice2.sol > ./flat/EmiPrice2.Full.sol", "dist:timelock": "node update-version.js && truffle-flattener ./contracts/Timelock.sol > ./flat/Timelock.Full.sol", From 6d043ef99bd19a1ed10b3687a78992999ee4cee3 Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Tue, 13 Jul 2021 13:39:08 +0300 Subject: [PATCH 09/24] Updated kucoin contracts --- contracts/EmiPrice2-kucoin.sol | 348 +++++++++++++++ contracts/EmiVamp-kucoin.sol | 409 ++++++++++++++++++ .../kofeeswap/router/interfaces/IKRC20.sol | 18 + .../router/interfaces/IKoffeeSwapCallee.sol | 6 + .../router/interfaces/IKoffeeSwapFactory.sol | 18 + .../router/interfaces/IKoffeeSwapKRC20.sol | 24 + .../router/interfaces/IKoffeeSwapPair.sol | 53 +++ .../router/interfaces/IKoffeeSwapRouter.sol | 135 ++++++ .../kofeeswap/router/interfaces/IWKCS.sol | 8 + contracts/uniswapv2/interfaces/IERC20Uni.sol | 2 + .../uniswapv2/interfaces/IUniswapV2Callee.sol | 1 + .../uniswapv2/interfaces/IUniswapV2ERC20.sol | 1 + .../interfaces/IUniswapV2Router01.sol | 1 + .../interfaces/IUniswapV2Router02.sol | 1 + contracts/uniswapv2/interfaces/IWETH.sol | 1 + 15 files changed, 1026 insertions(+) create mode 100644 contracts/EmiPrice2-kucoin.sol create mode 100644 contracts/EmiVamp-kucoin.sol create mode 100644 contracts/kofeeswap/router/interfaces/IKRC20.sol create mode 100644 contracts/kofeeswap/router/interfaces/IKoffeeSwapCallee.sol create mode 100644 contracts/kofeeswap/router/interfaces/IKoffeeSwapFactory.sol create mode 100644 contracts/kofeeswap/router/interfaces/IKoffeeSwapKRC20.sol create mode 100644 contracts/kofeeswap/router/interfaces/IKoffeeSwapPair.sol create mode 100644 contracts/kofeeswap/router/interfaces/IKoffeeSwapRouter.sol create mode 100644 contracts/kofeeswap/router/interfaces/IWKCS.sol diff --git a/contracts/EmiPrice2-kucoin.sol b/contracts/EmiPrice2-kucoin.sol new file mode 100644 index 0000000..0780f25 --- /dev/null +++ b/contracts/EmiPrice2-kucoin.sol @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "./kofeeswap/router/interfaces/IKRC20.sol"; +import "./kofeeswap/router/interfaces/IKoffeeSwapFactory.sol"; +import "./kofeeswap/router/interfaces/IKoffeeSwapPair.sol"; +import "./kofeeswap/router/interfaces/IKoffeeSwapRouter.sol"; +import "./libraries/Priviledgeable.sol"; +import "./interfaces/IEmiERC20.sol"; +import "./interfaces/IEmiRouter.sol"; +import "./interfaces/IEmiswap.sol"; + +contract EmiPrice2 is Initializable, Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + address public emiRouter; + address public kofeeRouter; + uint256 constant MARKET_OUR = 0; + uint256 constant MARKET_KOFEESWAP = 1; + uint256 constant MAX_PATH_LENGTH = 5; + + string public codeVersion = "EmiPrice2-kucoin v1.0-200-g8d0b0fa"; + + /** + * @dev Upgradeable proxy constructor replacement + */ + function initialize( + address _emirouter, + address _kofeerouter + ) public initializer { + require(_emirouter != address(0), "EmiRouter address cannot be 0"); + require(_kofeerouter != address(0), "KofeeRouter address cannot be 0"); + + emiRouter = _emirouter; + kofeeRouter = _kofeerouter; + _addAdmin(msg.sender); + } + + /** + * @dev Return coin prices with 18-digit precision + * @param _coins Array of token addresses for price determination + * @param _basictokens Array of basic tokens to determine price against + * @param _market Market index [0..2] to get prices from + */ + function getCoinPrices( + address[] calldata _coins, + address[] calldata _basictokens, + uint8 _market + ) external view returns (uint256[] memory prices) { + require(_market < 2, "Wrong market index"); + uint256[] memory _prices; + + _prices = new uint256[](_coins.length); + + if (_market == MARKET_KOFEESWAP) { + _getKofeeswapPrice(_coins, _basictokens[0], _prices); + } else if (_market == MARKET_OUR) { + _getOurPrice(_coins, _basictokens, _prices); + } + + return _prices; + } + + function calcRoute(address _target, address _base) + external + view + returns (address[] memory path) + { + return _calculateRoute(_target, _base); + } + + /** + * @dev Changes unirouter factory address + */ + function changeKofeeRouter(address _router) external onlyAdmin { + require(_router != address(0), "Router address cannot be 0"); + + kofeeRouter = _router; + } + + /** + * @dev Changes market factory address + */ + function changeEmiRouter(address _router) external onlyAdmin { + require(_router != address(0), "Router address cannot be 0"); + + emiRouter = _router; + } + + // internal methods + function _getKofeeswapPrice( + address[] memory _coins, + address _base, + uint256[] memory _prices + ) internal view { + uint256 base_decimal = IKRC20(_base).decimals(); + + for (uint256 i = 0; i < _coins.length; i++) { + uint256 target_decimal = IKRC20(_coins[i]).decimals(); + + if (_coins[i] == _base) { + _prices[i] = 10**18; // special case: 1 for base token + continue; + } + + uint256 _in = 10**target_decimal; + + address[] memory _path = new address[](2); + _path[0] = _coins[i]; + _path[1] = _base; + uint256[] memory _amts = + IKoffeeSwapRouter(kofeeRouter).getAmountsOut(_in, _path); + if (_amts.length > 0) { + _prices[i] = _amts[_amts.length - 1].mul( + 10**(18 - base_decimal) + ); + } else { + _prices[i] = 0; + } + } + } + + /** + * @dev Get price from our router + */ + function _getOurPrice( + address[] memory _coins, + address[] memory _base, + uint256[] memory _prices + ) internal view { + IEmiswapRegistry _factory = IEmiswapRegistry(IEmiRouter(emiRouter).factory()); + IEmiswap _p; + + if (address(_factory) == address(0)) { + return; + } + + for (uint256 i = 0; i < _coins.length; i++) { + // test each base token -- whether we can use it for price calc + uint256 target_decimal = IEmiERC20(_coins[i]).decimals(); + + for (uint256 m = 0; m < _base.length; m++) { + if (_coins[i] == _base[m]) { + _prices[i] = 10**18; // special case: 1 for base token + break; + } + uint256 base_decimal = IEmiERC20(_base[m]).decimals(); + + (address t0, address t1) = + (_coins[i] < _base[m]) + ? (_coins[i], _base[m]) + : (_base[m], _coins[i]); + _p = IEmiswap(_factory.pools(IERC20(t0), IERC20(t1))); // do we have direct pair? + address[] memory _route; + + if (address(_p) == address(0)) { + // we have to calc route + _route = _calculateRoute(_coins[i], _base[m]); + } else { // just take direct pair + _route = new address[](2); + _route[0] = _coins[i]; + _route[1] = _base[m]; + } + if (_route.length == 0) { + continue; // try next base token + } else { + uint256 _in = 10**target_decimal; + uint256[] memory _amts = + IEmiRouter(emiRouter).getAmountsOut(_in, _route); + if (_amts.length > 0) { + _prices[i] = _amts[_amts.length - 1].mul( + 10**(18 - base_decimal) + ); + } else { + _prices[i] = 0; + } + break; + } + } + } + } + + /** + * @dev Calculates route from _target token to _base, using adapted Li algorithm + * https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9B%D0%B8 + */ + function _calculateRoute(address _target, address _base) + internal + view + returns (address[] memory path) + { + IEmiswapRegistry _factory = IEmiswapRegistry(IEmiRouter(emiRouter).factory()); + IEmiswap[] memory pools = _factory.getAllPools(); // gets all pairs + uint8[] memory pairIdx = new uint8[](pools.length); // vector for storing path step indexes + + // Phase 1. Mark pairs starting from target token + _markPathStep(pools, pairIdx, 1, _target); // start from 1 step + address[] memory _curStep = new address[](pools.length); + _curStep[0] = _target; // store target address as first current step + address[] memory _prevStep = new address[](pools.length); + + for (uint8 i = 2; i < MAX_PATH_LENGTH; i++) { + // pass the wave + _moveSteps(_prevStep, _curStep); + + for (uint256 j = 0; j < pools.length; j++) { + if (pairIdx[j] == i - 1) { + // found previous step, store second token + address _a = _getAddressFromPrevStep(pools[j], _prevStep); + _markPathStep(pools, pairIdx, i, _a); + _addToCurrentStep(_curStep, _a); + } + } + } + + // matrix marked -- start creating route from base token back to target + uint8 baseIdx = 0; + + for (uint8 i = 0; i < pools.length; i++) { + if ( + address(pools[i].tokens(1)) == _base || + address(pools[i].tokens(0)) == _base + ) { + if (baseIdx == 0 || baseIdx > pairIdx[i]) { + // look for shortest available path + baseIdx = pairIdx[i]; + } + } + } + + if (baseIdx == 0) { + // no route found + return new address[](0); + } else { + // get back to target from base + address _a = _base; + + path = new address[](baseIdx + 1); + path[baseIdx] = _base; + + for (uint8 i = baseIdx; i > 0; i--) { + // take pair from last level + for (uint256 j = 0; j < pools.length; j++) { + if ( + pairIdx[j] == i && + (address(pools[j].tokens(1)) == _a || + address(pools[j].tokens(0)) == _a) + ) { + // push path chain + _a = (address(pools[j].tokens(0)) == _a) // get next token from pair + ? address(pools[j].tokens(1)) + : address(pools[j].tokens(0)); + path[i - 1] = _a; + break; + } + } + } + return path; + } + } + + /** + * @dev Marks next path level from _token + */ + function _markPathStep( + IEmiswap[] memory _pools, + uint8[] memory _idx, + uint8 lvl, + address _token + ) internal view { + for (uint256 j = 0; j < _pools.length; j++) { + if ( + _idx[j] == 0 && + (address(_pools[j].tokens(1)) == _token || + address(_pools[j].tokens(0)) == _token) + ) { + // found match + _idx[j] = lvl; + } + } + } + + /** + * @dev Get address of the second token from previous level pair + */ + function _getAddressFromPrevStep(IEmiswap pair, address[] memory prevStep) + internal + view + returns (address r) + { + for (uint256 i = 0; i < prevStep.length; i++) { + if ( + prevStep[i] != address(0) && + (address(pair.tokens(0)) == prevStep[i] || + address(pair.tokens(1)) == prevStep[i]) + ) { + return + (address(pair.tokens(0)) == prevStep[i]) + ? address(pair.tokens(1)) + : address(pair.tokens(0)); + } + } + return address(0); + } + + /** + * @dev Moves one array to another striping empty entries + */ + function _moveSteps(address[] memory _to, address[] memory _from) + internal + pure + { + for (uint256 i = 0; i < _from.length; i++) { + _to[i] = _from[i]; + _from[i] = address(0); + } + } + + /** + * @dev Adds pairs second token address to current step array + * @param _step Array for storing current step addresses + * @param _token First token pair address + */ + function _addToCurrentStep(address[] memory _step, address _token) + internal + pure + { + uint256 l = 0; + + for (uint256 i = 0; i < _step.length; i++) { + if (_step[i] == _token) { + // token already exists in a list + return; + } else { + if (_step[i] == address(0)) { + // first free cell found + break; + } else { + l++; + } + } + } + _step[l] = _token; + } +} diff --git a/contracts/EmiVamp-kucoin.sol b/contracts/EmiVamp-kucoin.sol new file mode 100644 index 0000000..a0b21fc --- /dev/null +++ b/contracts/EmiVamp-kucoin.sol @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +import "./kofeeswap/router/interfaces/IKRC20.sol"; +import "./kofeeswap/router/interfaces/IKoffeeSwapFactory.sol"; +import "./kofeeswap/router/interfaces/IKoffeeSwapPair.sol"; +import "./kofeeswap/router/interfaces/IKoffeeSwapRouter.sol"; +import "./libraries/Priviledgeable.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import "./interfaces/IEmiswap.sol"; +import "./interfaces/IEmiVoting.sol"; +import "./interfaces/IMooniswap.sol"; +import "./libraries/TransferHelper.sol"; +import "./libraries/EmiswapLib.sol"; + +/** + * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. + */ +contract EmiVamp is Initializable, Priviledgeable, ReentrancyGuard { + using SafeERC20 for IERC20; + + struct LPTokenInfo { + address lpToken; + uint16 tokenType; // Token type: 0 - uniswap (default), 1 - mooniswap + } + + // Info of each third-party lp-token. + LPTokenInfo[] public lpTokensInfo; + + string public codeVersion = "EmiVamp-kucoin v1.0-183-g3ae9438"; + address public ourFactory; + event Deposit(address indexed user, address indexed token, uint256 amount); + + address public defRef; + address private _voting; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + /** + * @dev Implementation of {UpgradeableProxy} type of constructors + */ + function initialize( + address[] memory _lptokens, + uint8[] memory _types, + address _ourfactory, + address _ourvoting + ) public initializer { + require(_lptokens.length > 0, "EmiVamp: length>0!"); + require(_lptokens.length == _types.length, "EmiVamp: lengths!"); + require(_ourfactory != address(0), "EmiVamp: factory!"); + require(_ourvoting != address(0), "EmiVamp: voting!"); + + for (uint256 i = 0; i < _lptokens.length; i++) { + lpTokensInfo.push( + LPTokenInfo({lpToken: _lptokens[i], tokenType: _types[i]}) + ); + } + ourFactory = _ourfactory; + _voting = _ourvoting; + defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); + _addAdmin(msg.sender); + } + + /** + * @dev Returns length of LP-tokens private array + */ + function lpTokensInfoLength() external view returns (uint256) { + return lpTokensInfo.length; + } + + /** + * @dev Returns pair base tokens + */ + function lpTokenDetailedInfo(uint256 _pid) + external + view + returns (address, address) + { + require(_pid < lpTokensInfo.length, "EmiVamp: Wrong lpToken idx"); + + if (lpTokensInfo[_pid].tokenType == 0) { + // this is uniswap + IKoffeeSwapPair lpToken = IKoffeeSwapPair(lpTokensInfo[_pid].lpToken); + return (lpToken.token0(), lpToken.token1()); + } else { + // this is mooniswap + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + return (address(t[0]), address(t[1])); + } + } + + /** + + * @dev Adds new entry to the list of convertible LP-tokens + */ + function addLPToken(address _token, uint16 _tokenType) + external + onlyAdmin + returns (uint256) + { + require(_token != address(0), "EmiVamp: Token address cannot be 0"); + require(_tokenType < 2, "EmiVamp: Wrong type"); + + for (uint256 i = 0; i < lpTokensInfo.length; i++) { + if (lpTokensInfo[i].lpToken == _token) { + return i; + } + } + lpTokensInfo.push( + LPTokenInfo({lpToken: _token, tokenType: _tokenType}) + ); + return lpTokensInfo.length; + } + + /** + * @dev Remove entry from the list of convertible LP-tokens + */ + function removeLPToken(uint256 _idx) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + + delete lpTokensInfo[_idx]; + } + + /** + * @dev Change entry from the list of convertible LP-tokens + */ + function changeLPToken( + uint256 _idx, + address _token, + uint16 _tokenType + ) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + require(_token != address(0), "EmiVamp: token=0!"); + require(_tokenType < 2, "EmiVamp: wrong tokenType"); + + lpTokensInfo[_idx].lpToken = _token; + lpTokensInfo[_idx].tokenType = _tokenType; + } + + /** + * @dev Change emifactory address + */ + function changeFactory(uint256 _proposalId) external onlyAdmin { + address _newFactory; + + _newFactory = IEmiVoting(_voting).getVotingResult(_proposalId); + require( + _newFactory != address(0), + "EmiVamp: New factory address is wrong" + ); + + ourFactory = _newFactory; + } + + /** + * @dev Change default referrer address + */ + function changeReferral(address _ref) external onlyAdmin { + defRef = _ref; + } + + // Deposit LP tokens to us + /** + * @dev Main function that converts third-party liquidity (represented by LP-tokens) to our own LP-tokens + */ + function deposit(uint256 _pid, uint256 _amount) public { + require(_pid < lpTokensInfo.length, "EmiVamp: pool idx is wrong"); + + if (lpTokensInfo[_pid].tokenType == 0) { + _depositKofeeswap(_pid, _amount); + } else if (lpTokensInfo[_pid].tokenType == 1) { + _depositMooniswap(_pid, _amount); + } else { + return; + } + emit Deposit(msg.sender, lpTokensInfo[_pid].lpToken, _amount); + } + + /** + * @dev Actual function that converts third-party Uniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositKofeeswap(uint256 _pid, uint256 _amount) internal { + IKoffeeSwapPair lpToken = IKoffeeSwapPair(lpTokensInfo[_pid].lpToken); + + // check pair existance + IKRC20 token0 = IKRC20(lpToken.token0()); + IKRC20 token1 = IKRC20(lpToken.token1()); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(lpToken), + _amount + ); + + // get liquidity + (uint256 amountIn0, uint256 amountIn1) = lpToken.burn(address(this)); + + _addOurLiquidity( + address(token0), + address(token1), + amountIn0, + amountIn1, + msg.sender + ); + } + + function _addOurLiquidity( + address _token0, + address _token1, + uint256 _amount0, + uint256 _amount1, + address _to + ) internal { + (uint256 amountA, uint256 amountB) = + _addLiquidity(_token0, _token1, _amount0, _amount1); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools( + IERC20(_token0), + IERC20(_token1) + ); + + TransferHelper.safeApprove(_token0, address(pairContract), amountA); + TransferHelper.safeApprove(_token1, address(pairContract), amountB); + + uint256[] memory amounts; + amounts = new uint256[](2); + uint256[] memory minAmounts; + minAmounts = new uint256[](2); + + if (_token0 < _token1) { + amounts[0] = amountA; + amounts[1] = amountB; + } else { + amounts[0] = amountB; + amounts[1] = amountA; + } + + uint256 liquidity = + IEmiswap(pairContract).deposit(amounts, minAmounts, defRef); + TransferHelper.safeTransfer(address(pairContract), _to, liquidity); + + // return the change + if (amountA < _amount0) { + // consumed less tokens 0 than given + TransferHelper.safeTransfer( + _token0, + address(msg.sender), + _amount0.sub(amountA) + ); + } + + if (amountB < _amount1) { + // consumed less tokens 1 than given + TransferHelper.safeTransfer( + _token1, + address(msg.sender), + _amount1.sub(amountB) + ); + } + } + + /** + * @dev Actual function that converts third-party Mooniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositMooniswap(uint256 _pid, uint256 _amount) internal { + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + + // check pair existance + IERC20 token0 = IERC20(t[0]); + IERC20 token1 = IERC20(t[1]); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(this), + _amount + ); + + uint256 amountBefore0 = token0.balanceOf(address(this)); + uint256 amountBefore1 = token1.balanceOf(address(this)); + + uint256[] memory minVals = new uint256[](2); + + lpToken.withdraw(_amount, minVals); + + // get liquidity + uint256 amount0 = token0.balanceOf(address(this)).sub(amountBefore0); + uint256 amount1 = token1.balanceOf(address(this)).sub(amountBefore1); + + _addOurLiquidity( + address(token0), + address(token1), + amount0, + amount1, + msg.sender + ); + } + + /** + @dev Function check for LP token pair availability. Return _pid or 0 if none exists + */ + function isPairAvailable(address _token0, address _token1) + public + view + returns (uint16) + { + require(_token0 != address(0), "EmiVamp: wrong token0 address"); + require(_token1 != address(0), "EmiVamp: wrong token1 address"); + + for (uint16 i = 0; i < lpTokensInfo.length; i++) { + address t0 = address(0); + address t1 = address(0); + + if (lpTokensInfo[i].tokenType == 0) { + IKoffeeSwapPair lpt = IKoffeeSwapPair(lpTokensInfo[i].lpToken); + t0 = lpt.token0(); + t1 = lpt.token1(); + } else if (lpTokensInfo[i].tokenType == 1) { + IMooniswap lpToken = IMooniswap(lpTokensInfo[i].lpToken); + + IERC20[] memory t = lpToken.getTokens(); + + t0 = address(t[0]); + t1 = address(t[1]); + } else { + return 0; + } + + if ( + (t0 == _token0 && t1 == _token1) || + (t1 == _token0 && t0 == _token1) + ) { + return 1; + } + } + return 0; + } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired + ) internal returns (uint256 amountA, uint256 amountB) { + IERC20 ERC20tokenA = IERC20(tokenA); + IERC20 ERC20tokenB = IERC20(tokenB); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools(ERC20tokenA, ERC20tokenB); + // create the pair if it doesn't exist yet + if (pairContract == IEmiswap(0)) { + pairContract = IEmiswapRegistry(ourFactory).deploy( + ERC20tokenA, + ERC20tokenB + ); + } + + uint256 reserveA = pairContract.getBalanceForAddition(ERC20tokenA); + uint256 reserveB = pairContract.getBalanceForRemoval(ERC20tokenB); + + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint256 amountBOptimal = + EmiswapLib.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require( + amountBOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_B_AMOUNT" + ); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint256 amountAOptimal = + EmiswapLib.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require( + amountAOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_A_AMOUNT" + ); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "EmiVamp: Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} diff --git a/contracts/kofeeswap/router/interfaces/IKRC20.sol b/contracts/kofeeswap/router/interfaces/IKRC20.sol new file mode 100644 index 0000000..f54f588 --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IKRC20.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKRC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); +} diff --git a/contracts/kofeeswap/router/interfaces/IKoffeeSwapCallee.sol b/contracts/kofeeswap/router/interfaces/IKoffeeSwapCallee.sol new file mode 100644 index 0000000..7a35d2d --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IKoffeeSwapCallee.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapCallee { + function KoffeeSwapCall(address sender, uint amount0, uint amount1, bytes calldata data) external; +} diff --git a/contracts/kofeeswap/router/interfaces/IKoffeeSwapFactory.sol b/contracts/kofeeswap/router/interfaces/IKoffeeSwapFactory.sol new file mode 100644 index 0000000..2fabc03 --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IKoffeeSwapFactory.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapFactory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint); + + function feeTo() external view returns (address); + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + function allPairs(uint) external view returns (address pair); + function allPairsLength() external view returns (uint); + + function createPair(address tokenA, address tokenB) external returns (address pair); + + function setFeeTo(address) external; + function setFeeToSetter(address) external; +} diff --git a/contracts/kofeeswap/router/interfaces/IKoffeeSwapKRC20.sol b/contracts/kofeeswap/router/interfaces/IKoffeeSwapKRC20.sol new file mode 100644 index 0000000..d6ce8c0 --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IKoffeeSwapKRC20.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapKRC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; +} diff --git a/contracts/kofeeswap/router/interfaces/IKoffeeSwapPair.sol b/contracts/kofeeswap/router/interfaces/IKoffeeSwapPair.sol new file mode 100644 index 0000000..b85ecb4 --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IKoffeeSwapPair.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapPair { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; + + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + function factory() external view returns (address); + function token0() external view returns (address); + function token1() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function price0CumulativeLast() external view returns (uint); + function price1CumulativeLast() external view returns (uint); + function kLast() external view returns (uint); + + function mint(address to) external returns (uint liquidity); + function burn(address to) external returns (uint amount0, uint amount1); + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; + function skim(address to) external; + function sync() external; + + function initialize(address, address) external; +} diff --git a/contracts/kofeeswap/router/interfaces/IKoffeeSwapRouter.sol b/contracts/kofeeswap/router/interfaces/IKoffeeSwapRouter.sol new file mode 100644 index 0000000..9d29586 --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IKoffeeSwapRouter.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.2; + +interface IKoffeeSwapRouter { + function factory() external pure returns (address); + function WKCS() external pure returns (address); + + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB, uint liquidity); + function addLiquidityKCS( + address token, + uint amountTokenDesired, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external payable returns (uint amountToken, uint amountKCS, uint liquidity); + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB); + function removeLiquidityKCS( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external returns (uint amountToken, uint amountKCS); + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountA, uint amountB); + function removeLiquidityKCSWithPermit( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountToken, uint amountKCS); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapExactKCSForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + function swapTokensForExactKCS(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapExactTokensForKCS(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapKCSForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + + function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); + + function removeLiquidityKCSSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external returns (uint amountKCS); + function removeLiquidityKCSWithPermitSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountKCS); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; + function swapExactKCSForTokensSupportingFeeOnTransferTokens( + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external payable; + function swapExactTokensForKCSSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; +} diff --git a/contracts/kofeeswap/router/interfaces/IWKCS.sol b/contracts/kofeeswap/router/interfaces/IWKCS.sol new file mode 100644 index 0000000..41b0429 --- /dev/null +++ b/contracts/kofeeswap/router/interfaces/IWKCS.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IWKCS { + function deposit() external payable; + function transfer(address to, uint value) external returns (bool); + function withdraw(uint) external; +} diff --git a/contracts/uniswapv2/interfaces/IERC20Uni.sol b/contracts/uniswapv2/interfaces/IERC20Uni.sol index 97fab6d..63637cb 100644 --- a/contracts/uniswapv2/interfaces/IERC20Uni.sol +++ b/contracts/uniswapv2/interfaces/IERC20Uni.sol @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + pragma solidity ^0.6.0; interface IERC20Uni { diff --git a/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol b/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol index 01d26c2..d7f5945 100644 --- a/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol +++ b/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; interface IUniswapV2Callee { diff --git a/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol b/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol index 5b2b862..b51714d 100644 --- a/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol +++ b/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; interface IUniswapV2ERC20 { diff --git a/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol b/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol index 4619967..5bab257 100644 --- a/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol +++ b/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; interface IUniswapV2Router01 { diff --git a/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol b/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol index 1fc7b0a..cdc12b2 100644 --- a/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol +++ b/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; import './IUniswapV2Router01.sol'; diff --git a/contracts/uniswapv2/interfaces/IWETH.sol b/contracts/uniswapv2/interfaces/IWETH.sol index e05fb77..e5cc99f 100644 --- a/contracts/uniswapv2/interfaces/IWETH.sol +++ b/contracts/uniswapv2/interfaces/IWETH.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IWETH { From d133feb0a19ef7f53cd9ac964692c8f15f5294ca Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Tue, 13 Jul 2021 15:30:13 +0300 Subject: [PATCH 10/24] Rename contracts to QC --- contracts/EmiPrice2-kucoin.sol | 2 +- contracts/EmiVamp-kucoin.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/EmiPrice2-kucoin.sol b/contracts/EmiPrice2-kucoin.sol index 0780f25..323d3e2 100644 --- a/contracts/EmiPrice2-kucoin.sol +++ b/contracts/EmiPrice2-kucoin.sol @@ -13,7 +13,7 @@ import "./interfaces/IEmiERC20.sol"; import "./interfaces/IEmiRouter.sol"; import "./interfaces/IEmiswap.sol"; -contract EmiPrice2 is Initializable, Priviledgeable { +contract EmiPrice2QC is Initializable, Priviledgeable { using SafeMath for uint256; using SafeMath for uint256; address public emiRouter; diff --git a/contracts/EmiVamp-kucoin.sol b/contracts/EmiVamp-kucoin.sol index a0b21fc..2f87bca 100644 --- a/contracts/EmiVamp-kucoin.sol +++ b/contracts/EmiVamp-kucoin.sol @@ -18,7 +18,7 @@ import "./libraries/EmiswapLib.sol"; /** * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. */ -contract EmiVamp is Initializable, Priviledgeable, ReentrancyGuard { +contract EmiVampQC is Initializable, Priviledgeable, ReentrancyGuard { using SafeERC20 for IERC20; struct LPTokenInfo { From 81f14d18f09c02e26f211e732e8fb543b72999db Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 14 Jul 2021 16:15:26 +0200 Subject: [PATCH 11/24] EmiPrice EmiVamp full versions, fix EmiVamp.changeFactory --- contracts/EmiPrice2-kucoin.sol | 2 +- contracts/EmiVamp-kucoin.sol | 13 +- flat/EmiPrice2-kucoin.Full.sol | 1402 ++++++++++++++++++++++++++ flat/EmiVamp-kucoin.Full.sol | 1709 ++++++++++++++++++++++++++++++++ package.json | 2 + 5 files changed, 3117 insertions(+), 11 deletions(-) create mode 100644 flat/EmiPrice2-kucoin.Full.sol create mode 100644 flat/EmiVamp-kucoin.Full.sol diff --git a/contracts/EmiPrice2-kucoin.sol b/contracts/EmiPrice2-kucoin.sol index 323d3e2..4b4d2c4 100644 --- a/contracts/EmiPrice2-kucoin.sol +++ b/contracts/EmiPrice2-kucoin.sol @@ -22,7 +22,7 @@ contract EmiPrice2QC is Initializable, Priviledgeable { uint256 constant MARKET_KOFEESWAP = 1; uint256 constant MAX_PATH_LENGTH = 5; - string public codeVersion = "EmiPrice2-kucoin v1.0-200-g8d0b0fa"; + string public codeVersion = "EmiPrice2-kucoin v1.0-231-gd133feb"; /** * @dev Upgradeable proxy constructor replacement diff --git a/contracts/EmiVamp-kucoin.sol b/contracts/EmiVamp-kucoin.sol index 2f87bca..c013630 100644 --- a/contracts/EmiVamp-kucoin.sol +++ b/contracts/EmiVamp-kucoin.sol @@ -29,12 +29,11 @@ contract EmiVampQC is Initializable, Priviledgeable, ReentrancyGuard { // Info of each third-party lp-token. LPTokenInfo[] public lpTokensInfo; - string public codeVersion = "EmiVamp-kucoin v1.0-183-g3ae9438"; + string public codeVersion = "EmiVamp-kucoin v1.0-231-gd133feb"; address public ourFactory; event Deposit(address indexed user, address indexed token, uint256 amount); address public defRef; - address private _voting; // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- @@ -45,13 +44,11 @@ contract EmiVampQC is Initializable, Priviledgeable, ReentrancyGuard { function initialize( address[] memory _lptokens, uint8[] memory _types, - address _ourfactory, - address _ourvoting + address _ourfactory ) public initializer { require(_lptokens.length > 0, "EmiVamp: length>0!"); require(_lptokens.length == _types.length, "EmiVamp: lengths!"); require(_ourfactory != address(0), "EmiVamp: factory!"); - require(_ourvoting != address(0), "EmiVamp: voting!"); for (uint256 i = 0; i < _lptokens.length; i++) { lpTokensInfo.push( @@ -59,7 +56,6 @@ contract EmiVampQC is Initializable, Priviledgeable, ReentrancyGuard { ); } ourFactory = _ourfactory; - _voting = _ourvoting; defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); _addAdmin(msg.sender); } @@ -144,10 +140,7 @@ contract EmiVampQC is Initializable, Priviledgeable, ReentrancyGuard { /** * @dev Change emifactory address */ - function changeFactory(uint256 _proposalId) external onlyAdmin { - address _newFactory; - - _newFactory = IEmiVoting(_voting).getVotingResult(_proposalId); + function changeFactory(address _newFactory) external onlyAdmin { require( _newFactory != address(0), "EmiVamp: New factory address is wrong" diff --git a/flat/EmiPrice2-kucoin.Full.sol b/flat/EmiPrice2-kucoin.Full.sol new file mode 100644 index 0000000..8cf3c0f --- /dev/null +++ b/flat/EmiPrice2-kucoin.Full.sol @@ -0,0 +1,1402 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/kofeeswap/router/interfaces/IKRC20.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKRC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); +} + +// File: contracts/kofeeswap/router/interfaces/IKoffeeSwapFactory.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapFactory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint); + + function feeTo() external view returns (address); + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + function allPairs(uint) external view returns (address pair); + function allPairsLength() external view returns (uint); + + function createPair(address tokenA, address tokenB) external returns (address pair); + + function setFeeTo(address) external; + function setFeeToSetter(address) external; +} + +// File: contracts/kofeeswap/router/interfaces/IKoffeeSwapPair.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapPair { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; + + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + function factory() external view returns (address); + function token0() external view returns (address); + function token1() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function price0CumulativeLast() external view returns (uint); + function price1CumulativeLast() external view returns (uint); + function kLast() external view returns (uint); + + function mint(address to) external returns (uint liquidity); + function burn(address to) external returns (uint amount0, uint amount1); + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; + function skim(address to) external; + function sync() external; + + function initialize(address, address) external; +} + +// File: contracts/kofeeswap/router/interfaces/IKoffeeSwapRouter.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.2; + +interface IKoffeeSwapRouter { + function factory() external pure returns (address); + function WKCS() external pure returns (address); + + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB, uint liquidity); + function addLiquidityKCS( + address token, + uint amountTokenDesired, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external payable returns (uint amountToken, uint amountKCS, uint liquidity); + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB); + function removeLiquidityKCS( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external returns (uint amountToken, uint amountKCS); + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountA, uint amountB); + function removeLiquidityKCSWithPermit( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountToken, uint amountKCS); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapExactKCSForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + function swapTokensForExactKCS(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapExactTokensForKCS(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapKCSForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + + function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); + + function removeLiquidityKCSSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external returns (uint amountKCS); + function removeLiquidityKCSWithPermitSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountKCS); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; + function swapExactKCSForTokensSupportingFeeOnTransferTokens( + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external payable; + function swapExactTokensForKCSSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/interfaces/IEmiERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +interface IEmiERC20 { + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); + event Transfer(address indexed from, address indexed to, uint256 value); + + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function decimals() external view returns (uint8); + + function totalSupply() external view returns (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function allowance(address owner, address spender) + external + view + returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/interfaces/IEmiRouter.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.6.2; + + +interface IEmiRouter { + function factory() external pure returns (address); + + function WETH() external pure returns (address); + + function getReserves(IERC20 token0, IERC20 token1) + external + view + returns ( + uint256 _reserve0, + uint256 _reserve1, + address poolAddresss + ); + + function addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired, + uint256 amountAMin, + uint256 amountBMin, + address ref + ) + external + returns ( + uint256 amountA, + uint256 amountB, + uint256 liquidity + ); + + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to, + address ref + ) external returns (uint256[] memory amounts); + + function swapTokensForExactTokens( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address[] calldata pathDAI + ) external returns (uint256[] memory amounts); + + function swapExactETHForTokens( + uint256 amountOutMin, + address[] calldata path, + address[] calldata pathDAI + ) external payable returns (uint256[] memory amounts); + + function swapTokensForExactETH( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address[] calldata pathDAI + ) external returns (uint256[] memory amounts); + + function swapExactTokensForETH( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address[] calldata pathDAI + ) external returns (uint256[] memory amounts); + + function swapETHForExactTokens( + uint256 amountOut, + address[] calldata path, + address[] calldata pathDAI + ) external payable returns (uint256[] memory amounts); + + function getAmountOut( + uint256 amountIn, + uint256 reserveIn, + uint256 reserveOut + ) external view returns (uint256 amountOut); + + function getAmountIn( + uint256 amountOut, + uint256 reserveIn, + uint256 reserveOut + ) external view returns (uint256 amountIn); + + function getAmountsOut(uint256 amountIn, address[] calldata path) + external + view + returns (uint256[] memory amounts); + + function getAmountsIn(uint256 amountOut, address[] calldata path) + external + view + returns (uint256[] memory amounts); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address[] calldata pathDAI + ) external; + + function swapExactETHForTokensSupportingFeeOnTransferTokens( + uint256 amountOutMin, + address[] calldata path, + address[] calldata pathDAI + ) external payable; + + function swapExactTokensForETHSupportingFeeOnTransferTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address[] calldata pathDAI + ) external; +} + +// File: contracts/interfaces/IEmiswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IEmiswapRegistry { + function pools(IERC20 token1, IERC20 token2) + external + view + returns (IEmiswap); + + function isPool(address addr) external view returns (bool); + + function deploy(IERC20 tokenA, IERC20 tokenB) external returns (IEmiswap); + function getAllPools() external view returns (IEmiswap[] memory); +} + +interface IEmiswap { + function fee() external view returns (uint256); + + function tokens(uint256 i) external view returns (IERC20); + + function deposit( + uint256[] calldata amounts, + uint256[] calldata minAmounts, + address referral + ) external payable returns (uint256 fairSupply); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; + + function getBalanceForAddition(IERC20 token) + external + view + returns (uint256); + + function getBalanceForRemoval(IERC20 token) external view returns (uint256); + + function getReturn( + IERC20 fromToken, + IERC20 destToken, + uint256 amount + ) external view returns (uint256, uint256); + + function swap( + IERC20 fromToken, + IERC20 destToken, + uint256 amount, + uint256 minReturn, + address to, + address referral + ) external payable returns (uint256 returnAmount); + + function initialize(IERC20[] calldata assets) external; +} + +// File: contracts/EmiPrice2-kucoin.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; +pragma experimental ABIEncoderV2; + + + + + + + + + + + +contract EmiPrice2QC is Initializable, Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + address public emiRouter; + address public kofeeRouter; + uint256 constant MARKET_OUR = 0; + uint256 constant MARKET_KOFEESWAP = 1; + uint256 constant MAX_PATH_LENGTH = 5; + + string public codeVersion = "EmiPrice2-kucoin v1.0-231-gd133feb"; + + /** + * @dev Upgradeable proxy constructor replacement + */ + function initialize( + address _emirouter, + address _kofeerouter + ) public initializer { + require(_emirouter != address(0), "EmiRouter address cannot be 0"); + require(_kofeerouter != address(0), "KofeeRouter address cannot be 0"); + + emiRouter = _emirouter; + kofeeRouter = _kofeerouter; + _addAdmin(msg.sender); + } + + /** + * @dev Return coin prices with 18-digit precision + * @param _coins Array of token addresses for price determination + * @param _basictokens Array of basic tokens to determine price against + * @param _market Market index [0..2] to get prices from + */ + function getCoinPrices( + address[] calldata _coins, + address[] calldata _basictokens, + uint8 _market + ) external view returns (uint256[] memory prices) { + require(_market < 2, "Wrong market index"); + uint256[] memory _prices; + + _prices = new uint256[](_coins.length); + + if (_market == MARKET_KOFEESWAP) { + _getKofeeswapPrice(_coins, _basictokens[0], _prices); + } else if (_market == MARKET_OUR) { + _getOurPrice(_coins, _basictokens, _prices); + } + + return _prices; + } + + function calcRoute(address _target, address _base) + external + view + returns (address[] memory path) + { + return _calculateRoute(_target, _base); + } + + /** + * @dev Changes unirouter factory address + */ + function changeKofeeRouter(address _router) external onlyAdmin { + require(_router != address(0), "Router address cannot be 0"); + + kofeeRouter = _router; + } + + /** + * @dev Changes market factory address + */ + function changeEmiRouter(address _router) external onlyAdmin { + require(_router != address(0), "Router address cannot be 0"); + + emiRouter = _router; + } + + // internal methods + function _getKofeeswapPrice( + address[] memory _coins, + address _base, + uint256[] memory _prices + ) internal view { + uint256 base_decimal = IKRC20(_base).decimals(); + + for (uint256 i = 0; i < _coins.length; i++) { + uint256 target_decimal = IKRC20(_coins[i]).decimals(); + + if (_coins[i] == _base) { + _prices[i] = 10**18; // special case: 1 for base token + continue; + } + + uint256 _in = 10**target_decimal; + + address[] memory _path = new address[](2); + _path[0] = _coins[i]; + _path[1] = _base; + uint256[] memory _amts = + IKoffeeSwapRouter(kofeeRouter).getAmountsOut(_in, _path); + if (_amts.length > 0) { + _prices[i] = _amts[_amts.length - 1].mul( + 10**(18 - base_decimal) + ); + } else { + _prices[i] = 0; + } + } + } + + /** + * @dev Get price from our router + */ + function _getOurPrice( + address[] memory _coins, + address[] memory _base, + uint256[] memory _prices + ) internal view { + IEmiswapRegistry _factory = IEmiswapRegistry(IEmiRouter(emiRouter).factory()); + IEmiswap _p; + + if (address(_factory) == address(0)) { + return; + } + + for (uint256 i = 0; i < _coins.length; i++) { + // test each base token -- whether we can use it for price calc + uint256 target_decimal = IEmiERC20(_coins[i]).decimals(); + + for (uint256 m = 0; m < _base.length; m++) { + if (_coins[i] == _base[m]) { + _prices[i] = 10**18; // special case: 1 for base token + break; + } + uint256 base_decimal = IEmiERC20(_base[m]).decimals(); + + (address t0, address t1) = + (_coins[i] < _base[m]) + ? (_coins[i], _base[m]) + : (_base[m], _coins[i]); + _p = IEmiswap(_factory.pools(IERC20(t0), IERC20(t1))); // do we have direct pair? + address[] memory _route; + + if (address(_p) == address(0)) { + // we have to calc route + _route = _calculateRoute(_coins[i], _base[m]); + } else { // just take direct pair + _route = new address[](2); + _route[0] = _coins[i]; + _route[1] = _base[m]; + } + if (_route.length == 0) { + continue; // try next base token + } else { + uint256 _in = 10**target_decimal; + uint256[] memory _amts = + IEmiRouter(emiRouter).getAmountsOut(_in, _route); + if (_amts.length > 0) { + _prices[i] = _amts[_amts.length - 1].mul( + 10**(18 - base_decimal) + ); + } else { + _prices[i] = 0; + } + break; + } + } + } + } + + /** + * @dev Calculates route from _target token to _base, using adapted Li algorithm + * https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9B%D0%B8 + */ + function _calculateRoute(address _target, address _base) + internal + view + returns (address[] memory path) + { + IEmiswapRegistry _factory = IEmiswapRegistry(IEmiRouter(emiRouter).factory()); + IEmiswap[] memory pools = _factory.getAllPools(); // gets all pairs + uint8[] memory pairIdx = new uint8[](pools.length); // vector for storing path step indexes + + // Phase 1. Mark pairs starting from target token + _markPathStep(pools, pairIdx, 1, _target); // start from 1 step + address[] memory _curStep = new address[](pools.length); + _curStep[0] = _target; // store target address as first current step + address[] memory _prevStep = new address[](pools.length); + + for (uint8 i = 2; i < MAX_PATH_LENGTH; i++) { + // pass the wave + _moveSteps(_prevStep, _curStep); + + for (uint256 j = 0; j < pools.length; j++) { + if (pairIdx[j] == i - 1) { + // found previous step, store second token + address _a = _getAddressFromPrevStep(pools[j], _prevStep); + _markPathStep(pools, pairIdx, i, _a); + _addToCurrentStep(_curStep, _a); + } + } + } + + // matrix marked -- start creating route from base token back to target + uint8 baseIdx = 0; + + for (uint8 i = 0; i < pools.length; i++) { + if ( + address(pools[i].tokens(1)) == _base || + address(pools[i].tokens(0)) == _base + ) { + if (baseIdx == 0 || baseIdx > pairIdx[i]) { + // look for shortest available path + baseIdx = pairIdx[i]; + } + } + } + + if (baseIdx == 0) { + // no route found + return new address[](0); + } else { + // get back to target from base + address _a = _base; + + path = new address[](baseIdx + 1); + path[baseIdx] = _base; + + for (uint8 i = baseIdx; i > 0; i--) { + // take pair from last level + for (uint256 j = 0; j < pools.length; j++) { + if ( + pairIdx[j] == i && + (address(pools[j].tokens(1)) == _a || + address(pools[j].tokens(0)) == _a) + ) { + // push path chain + _a = (address(pools[j].tokens(0)) == _a) // get next token from pair + ? address(pools[j].tokens(1)) + : address(pools[j].tokens(0)); + path[i - 1] = _a; + break; + } + } + } + return path; + } + } + + /** + * @dev Marks next path level from _token + */ + function _markPathStep( + IEmiswap[] memory _pools, + uint8[] memory _idx, + uint8 lvl, + address _token + ) internal view { + for (uint256 j = 0; j < _pools.length; j++) { + if ( + _idx[j] == 0 && + (address(_pools[j].tokens(1)) == _token || + address(_pools[j].tokens(0)) == _token) + ) { + // found match + _idx[j] = lvl; + } + } + } + + /** + * @dev Get address of the second token from previous level pair + */ + function _getAddressFromPrevStep(IEmiswap pair, address[] memory prevStep) + internal + view + returns (address r) + { + for (uint256 i = 0; i < prevStep.length; i++) { + if ( + prevStep[i] != address(0) && + (address(pair.tokens(0)) == prevStep[i] || + address(pair.tokens(1)) == prevStep[i]) + ) { + return + (address(pair.tokens(0)) == prevStep[i]) + ? address(pair.tokens(1)) + : address(pair.tokens(0)); + } + } + return address(0); + } + + /** + * @dev Moves one array to another striping empty entries + */ + function _moveSteps(address[] memory _to, address[] memory _from) + internal + pure + { + for (uint256 i = 0; i < _from.length; i++) { + _to[i] = _from[i]; + _from[i] = address(0); + } + } + + /** + * @dev Adds pairs second token address to current step array + * @param _step Array for storing current step addresses + * @param _token First token pair address + */ + function _addToCurrentStep(address[] memory _step, address _token) + internal + pure + { + uint256 l = 0; + + for (uint256 i = 0; i < _step.length; i++) { + if (_step[i] == _token) { + // token already exists in a list + return; + } else { + if (_step[i] == address(0)) { + // first free cell found + break; + } else { + l++; + } + } + } + _step[l] = _token; + } +} diff --git a/flat/EmiVamp-kucoin.Full.sol b/flat/EmiVamp-kucoin.Full.sol new file mode 100644 index 0000000..3d8fcf1 --- /dev/null +++ b/flat/EmiVamp-kucoin.Full.sol @@ -0,0 +1,1709 @@ +// File: contracts/kofeeswap/router/interfaces/IKRC20.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKRC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); +} + +// File: contracts/kofeeswap/router/interfaces/IKoffeeSwapFactory.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapFactory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint); + + function feeTo() external view returns (address); + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + function allPairs(uint) external view returns (address pair); + function allPairsLength() external view returns (uint); + + function createPair(address tokenA, address tokenB) external returns (address pair); + + function setFeeTo(address) external; + function setFeeToSetter(address) external; +} + +// File: contracts/kofeeswap/router/interfaces/IKoffeeSwapPair.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + +interface IKoffeeSwapPair { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; + + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + function factory() external view returns (address); + function token0() external view returns (address); + function token1() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function price0CumulativeLast() external view returns (uint); + function price1CumulativeLast() external view returns (uint); + function kLast() external view returns (uint); + + function mint(address to) external returns (uint liquidity); + function burn(address to) external returns (uint amount0, uint amount1); + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; + function skim(address to) external; + function sync() external; + + function initialize(address, address) external; +} + +// File: contracts/kofeeswap/router/interfaces/IKoffeeSwapRouter.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.2; + +interface IKoffeeSwapRouter { + function factory() external pure returns (address); + function WKCS() external pure returns (address); + + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB, uint liquidity); + function addLiquidityKCS( + address token, + uint amountTokenDesired, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external payable returns (uint amountToken, uint amountKCS, uint liquidity); + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB); + function removeLiquidityKCS( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external returns (uint amountToken, uint amountKCS); + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountA, uint amountB); + function removeLiquidityKCSWithPermit( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountToken, uint amountKCS); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapExactKCSForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + function swapTokensForExactKCS(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapExactTokensForKCS(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapKCSForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + + function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); + + function removeLiquidityKCSSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline + ) external returns (uint amountKCS); + function removeLiquidityKCSWithPermitSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountKCSMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountKCS); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; + function swapExactKCSForTokensSupportingFeeOnTransferTokens( + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external payable; + function swapExactTokensForKCSSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: @openzeppelin/contracts/utils/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () internal { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + +// File: contracts/interfaces/IEmiswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IEmiswapRegistry { + function pools(IERC20 token1, IERC20 token2) + external + view + returns (IEmiswap); + + function isPool(address addr) external view returns (bool); + + function deploy(IERC20 tokenA, IERC20 tokenB) external returns (IEmiswap); + function getAllPools() external view returns (IEmiswap[] memory); +} + +interface IEmiswap { + function fee() external view returns (uint256); + + function tokens(uint256 i) external view returns (IERC20); + + function deposit( + uint256[] calldata amounts, + uint256[] calldata minAmounts, + address referral + ) external payable returns (uint256 fairSupply); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; + + function getBalanceForAddition(IERC20 token) + external + view + returns (uint256); + + function getBalanceForRemoval(IERC20 token) external view returns (uint256); + + function getReturn( + IERC20 fromToken, + IERC20 destToken, + uint256 amount + ) external view returns (uint256, uint256); + + function swap( + IERC20 fromToken, + IERC20 destToken, + uint256 amount, + uint256 minReturn, + address to, + address referral + ) external payable returns (uint256 returnAmount); + + function initialize(IERC20[] calldata assets) external; +} + +// File: contracts/interfaces/IEmiVoting.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +interface IEmiVoting { + function getVotingResult(uint256 _hash) external view returns (address); +} + +// File: contracts/interfaces/IMooniswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IMooniswap { + function getTokens() external view returns (IERC20[] memory); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; +} + +// File: contracts/libraries/TransferHelper.sol + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity >=0.6.0; + +// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false +library TransferHelper { + function safeApprove( + address token, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('approve(address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: APPROVE_FAILED" + ); + } + + function safeTransfer( + address token, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('transfer(address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: TRANSFER_FAILED" + ); + } + + function safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: TRANSFER_FROM_FAILED" + ); + } + + function safeTransferETH(address to, uint256 value) internal { + (bool success, ) = to.call{value: value}(new bytes(0)); + require(success, "TransferHelper: ETH_TRANSFER_FAILED"); + } +} + +// File: contracts/libraries/EmiswapLib.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + +library EmiswapLib { + using SafeMath for uint256; + uint256 public constant FEE_DENOMINATOR = 1e18; + + function previewSwapExactTokenForToken( + address factory, + address tokenFrom, + address tokenTo, + uint256 ammountFrom + ) internal view returns (uint256 ammountTo) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools(IERC20(tokenFrom), IERC20(tokenTo)); + + if (pairContract != IEmiswap(0)) { + (,ammountTo) = pairContract.getReturn( + IERC20(tokenFrom), + IERC20(tokenTo), + ammountFrom + ); + } + } + + /************************************************************************************** + * get preview result of virtual swap by route of tokens + **************************************************************************************/ + function previewSwapbyRoute( + address factory, + address[] memory path, + uint256 ammountFrom + ) internal view returns (uint256 ammountTo) { + for (uint256 i = 0; i < path.length - 1; i++) { + if (path.length >= 2) { + ammountTo = previewSwapExactTokenForToken( + factory, + path[i], + path[i + 1], + ammountFrom + ); + + if (i == (path.length - 2)) { + return (ammountTo); + } else { + ammountFrom = ammountTo; + } + } + } + } + + function fee(address factory) internal view returns (uint256) { + return IEmiswap(factory).fee(); + } + + // given an output amount of an asset and pair reserves, returns a required input amount of the other asset + function getAmountIn( + address factory, + uint256 amountOut, + uint256 reserveIn, + uint256 reserveOut + ) internal view returns (uint256 amountIn) { + require(amountOut > 0, "EmiswapLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); + require( + reserveIn > 0 && reserveOut > 0, + "EmiswapLibrary: INSUFFICIENT_LIQUIDITY" + ); + uint256 numerator = reserveIn.mul(amountOut).mul(1000); + uint256 denominator = + reserveOut.sub(amountOut).mul( + uint256(1000000000000000000).sub(fee(factory)).div(1e15) + ); // 997 + amountIn = (numerator / denominator).add(1); + } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut( + address factory, + uint256 amountIn, + uint256 reserveIn, + uint256 reserveOut + ) internal view returns (uint256 amountOut) { + if (amountIn == 0 || reserveIn == 0 || reserveOut == 0) { + return (0); + } + + uint256 amountInWithFee = + amountIn.mul( + uint256(1000000000000000000).sub(fee(factory)).div(1e15) + ); //997 + uint256 numerator = amountInWithFee.mul(reserveOut); + uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); + amountOut = (denominator == 0 ? 0 : amountOut = + numerator / + denominator); + } + + // performs chained getAmountIn calculations on any number of pairs + function getAmountsIn( + address factory, + uint256 amountOut, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2, "EmiswapLibrary: INVALID_PATH"); + amounts = new uint256[](path.length); + amounts[amounts.length - 1] = amountOut; + for (uint256 i = path.length - 1; i > 0; i--) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools( + IERC20(IERC20(path[i])), + IERC20(path[i - 1]) + ); + + uint256 reserveIn; + uint256 reserveOut; + + if (address(pairContract) != address(0)) { + reserveIn = IEmiswap(pairContract).getBalanceForAddition( + IERC20(path[i - 1]) + ); + reserveOut = IEmiswap(pairContract).getBalanceForRemoval( + IERC20(path[i]) + ); + } + + amounts[i - 1] = getAmountIn( + factory, + amounts[i], + reserveIn, + reserveOut + ); + } + } + + // performs chained getAmountOut calculations on any number of pairs + function getAmountsOut( + address factory, + uint256 amountIn, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2, "EmiswapLibrary: INVALID_PATH"); + amounts = new uint256[](path.length); + amounts[0] = amountIn; + for (uint256 i = 0; i < path.length - 1; i++) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools( + IERC20(IERC20(path[i])), + IERC20(path[i + 1]) + ); + + uint256 reserveIn; + uint256 reserveOut; + + if (address(pairContract) != address(0)) { + reserveIn = IEmiswap(pairContract).getBalanceForAddition( + IERC20(path[i]) + ); + reserveOut = IEmiswap(pairContract).getBalanceForRemoval( + IERC20(path[i + 1]) + ); + } + + amounts[i + 1] = getAmountOut( + factory, + amounts[i], + reserveIn, + reserveOut + ); + } + } + + // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset + function quote( + uint256 amountA, + uint256 reserveA, + uint256 reserveB + ) internal pure returns (uint256 amountB) { + require(amountA > 0, "EmiswapLibrary: INSUFFICIENT_AMOUNT"); + require( + reserveA > 0 && reserveB > 0, + "EmiswapLibrary: INSUFFICIENT_LIQUIDITY" + ); + amountB = amountA.mul(reserveB) / reserveA; + } +} + +// File: contracts/EmiVamp-kucoin.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + + + + + + + + + + + + + + +/** + * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. + */ +contract EmiVampQC is Initializable, Priviledgeable, ReentrancyGuard { + using SafeERC20 for IERC20; + + struct LPTokenInfo { + address lpToken; + uint16 tokenType; // Token type: 0 - uniswap (default), 1 - mooniswap + } + + // Info of each third-party lp-token. + LPTokenInfo[] public lpTokensInfo; + + string public codeVersion = "EmiVamp-kucoin v1.0-231-gd133feb"; + address public ourFactory; + event Deposit(address indexed user, address indexed token, uint256 amount); + + address public defRef; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + /** + * @dev Implementation of {UpgradeableProxy} type of constructors + */ + function initialize( + address[] memory _lptokens, + uint8[] memory _types, + address _ourfactory + ) public initializer { + require(_lptokens.length > 0, "EmiVamp: length>0!"); + require(_lptokens.length == _types.length, "EmiVamp: lengths!"); + require(_ourfactory != address(0), "EmiVamp: factory!"); + + for (uint256 i = 0; i < _lptokens.length; i++) { + lpTokensInfo.push( + LPTokenInfo({lpToken: _lptokens[i], tokenType: _types[i]}) + ); + } + ourFactory = _ourfactory; + defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); + _addAdmin(msg.sender); + } + + /** + * @dev Returns length of LP-tokens private array + */ + function lpTokensInfoLength() external view returns (uint256) { + return lpTokensInfo.length; + } + + /** + * @dev Returns pair base tokens + */ + function lpTokenDetailedInfo(uint256 _pid) + external + view + returns (address, address) + { + require(_pid < lpTokensInfo.length, "EmiVamp: Wrong lpToken idx"); + + if (lpTokensInfo[_pid].tokenType == 0) { + // this is uniswap + IKoffeeSwapPair lpToken = IKoffeeSwapPair(lpTokensInfo[_pid].lpToken); + return (lpToken.token0(), lpToken.token1()); + } else { + // this is mooniswap + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + return (address(t[0]), address(t[1])); + } + } + + /** + + * @dev Adds new entry to the list of convertible LP-tokens + */ + function addLPToken(address _token, uint16 _tokenType) + external + onlyAdmin + returns (uint256) + { + require(_token != address(0), "EmiVamp: Token address cannot be 0"); + require(_tokenType < 2, "EmiVamp: Wrong type"); + + for (uint256 i = 0; i < lpTokensInfo.length; i++) { + if (lpTokensInfo[i].lpToken == _token) { + return i; + } + } + lpTokensInfo.push( + LPTokenInfo({lpToken: _token, tokenType: _tokenType}) + ); + return lpTokensInfo.length; + } + + /** + * @dev Remove entry from the list of convertible LP-tokens + */ + function removeLPToken(uint256 _idx) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + + delete lpTokensInfo[_idx]; + } + + /** + * @dev Change entry from the list of convertible LP-tokens + */ + function changeLPToken( + uint256 _idx, + address _token, + uint16 _tokenType + ) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + require(_token != address(0), "EmiVamp: token=0!"); + require(_tokenType < 2, "EmiVamp: wrong tokenType"); + + lpTokensInfo[_idx].lpToken = _token; + lpTokensInfo[_idx].tokenType = _tokenType; + } + + /** + * @dev Change emifactory address + */ + function changeFactory(address _newFactory) external onlyAdmin { + require( + _newFactory != address(0), + "EmiVamp: New factory address is wrong" + ); + + ourFactory = _newFactory; + } + + /** + * @dev Change default referrer address + */ + function changeReferral(address _ref) external onlyAdmin { + defRef = _ref; + } + + // Deposit LP tokens to us + /** + * @dev Main function that converts third-party liquidity (represented by LP-tokens) to our own LP-tokens + */ + function deposit(uint256 _pid, uint256 _amount) public { + require(_pid < lpTokensInfo.length, "EmiVamp: pool idx is wrong"); + + if (lpTokensInfo[_pid].tokenType == 0) { + _depositKofeeswap(_pid, _amount); + } else if (lpTokensInfo[_pid].tokenType == 1) { + _depositMooniswap(_pid, _amount); + } else { + return; + } + emit Deposit(msg.sender, lpTokensInfo[_pid].lpToken, _amount); + } + + /** + * @dev Actual function that converts third-party Uniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositKofeeswap(uint256 _pid, uint256 _amount) internal { + IKoffeeSwapPair lpToken = IKoffeeSwapPair(lpTokensInfo[_pid].lpToken); + + // check pair existance + IKRC20 token0 = IKRC20(lpToken.token0()); + IKRC20 token1 = IKRC20(lpToken.token1()); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(lpToken), + _amount + ); + + // get liquidity + (uint256 amountIn0, uint256 amountIn1) = lpToken.burn(address(this)); + + _addOurLiquidity( + address(token0), + address(token1), + amountIn0, + amountIn1, + msg.sender + ); + } + + function _addOurLiquidity( + address _token0, + address _token1, + uint256 _amount0, + uint256 _amount1, + address _to + ) internal { + (uint256 amountA, uint256 amountB) = + _addLiquidity(_token0, _token1, _amount0, _amount1); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools( + IERC20(_token0), + IERC20(_token1) + ); + + TransferHelper.safeApprove(_token0, address(pairContract), amountA); + TransferHelper.safeApprove(_token1, address(pairContract), amountB); + + uint256[] memory amounts; + amounts = new uint256[](2); + uint256[] memory minAmounts; + minAmounts = new uint256[](2); + + if (_token0 < _token1) { + amounts[0] = amountA; + amounts[1] = amountB; + } else { + amounts[0] = amountB; + amounts[1] = amountA; + } + + uint256 liquidity = + IEmiswap(pairContract).deposit(amounts, minAmounts, defRef); + TransferHelper.safeTransfer(address(pairContract), _to, liquidity); + + // return the change + if (amountA < _amount0) { + // consumed less tokens 0 than given + TransferHelper.safeTransfer( + _token0, + address(msg.sender), + _amount0.sub(amountA) + ); + } + + if (amountB < _amount1) { + // consumed less tokens 1 than given + TransferHelper.safeTransfer( + _token1, + address(msg.sender), + _amount1.sub(amountB) + ); + } + } + + /** + * @dev Actual function that converts third-party Mooniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositMooniswap(uint256 _pid, uint256 _amount) internal { + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + + // check pair existance + IERC20 token0 = IERC20(t[0]); + IERC20 token1 = IERC20(t[1]); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(this), + _amount + ); + + uint256 amountBefore0 = token0.balanceOf(address(this)); + uint256 amountBefore1 = token1.balanceOf(address(this)); + + uint256[] memory minVals = new uint256[](2); + + lpToken.withdraw(_amount, minVals); + + // get liquidity + uint256 amount0 = token0.balanceOf(address(this)).sub(amountBefore0); + uint256 amount1 = token1.balanceOf(address(this)).sub(amountBefore1); + + _addOurLiquidity( + address(token0), + address(token1), + amount0, + amount1, + msg.sender + ); + } + + /** + @dev Function check for LP token pair availability. Return _pid or 0 if none exists + */ + function isPairAvailable(address _token0, address _token1) + public + view + returns (uint16) + { + require(_token0 != address(0), "EmiVamp: wrong token0 address"); + require(_token1 != address(0), "EmiVamp: wrong token1 address"); + + for (uint16 i = 0; i < lpTokensInfo.length; i++) { + address t0 = address(0); + address t1 = address(0); + + if (lpTokensInfo[i].tokenType == 0) { + IKoffeeSwapPair lpt = IKoffeeSwapPair(lpTokensInfo[i].lpToken); + t0 = lpt.token0(); + t1 = lpt.token1(); + } else if (lpTokensInfo[i].tokenType == 1) { + IMooniswap lpToken = IMooniswap(lpTokensInfo[i].lpToken); + + IERC20[] memory t = lpToken.getTokens(); + + t0 = address(t[0]); + t1 = address(t[1]); + } else { + return 0; + } + + if ( + (t0 == _token0 && t1 == _token1) || + (t1 == _token0 && t0 == _token1) + ) { + return 1; + } + } + return 0; + } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired + ) internal returns (uint256 amountA, uint256 amountB) { + IERC20 ERC20tokenA = IERC20(tokenA); + IERC20 ERC20tokenB = IERC20(tokenB); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools(ERC20tokenA, ERC20tokenB); + // create the pair if it doesn't exist yet + if (pairContract == IEmiswap(0)) { + pairContract = IEmiswapRegistry(ourFactory).deploy( + ERC20tokenA, + ERC20tokenB + ); + } + + uint256 reserveA = pairContract.getBalanceForAddition(ERC20tokenA); + uint256 reserveB = pairContract.getBalanceForRemoval(ERC20tokenB); + + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint256 amountBOptimal = + EmiswapLib.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require( + amountBOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_B_AMOUNT" + ); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint256 amountAOptimal = + EmiswapLib.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require( + amountAOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_A_AMOUNT" + ); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "EmiVamp: Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} diff --git a/package.json b/package.json index 079aaf0..99edd37 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", "dist:emivamp": "node update-version.js && truffle-flattener ./contracts/EmiVamp.sol > ./flat/EmiVamp.Full.sol", + "dist:emivamp-kucoin": "truffle-flattener ./contracts/EmiVamp-kucoin.sol > ./flat/EmiVamp-kucoin.Full.sol", "dist:votableproxyadmin": "node update-version.js && truffle-flattener ./contracts/VotableProxyAdmin.sol > ./flat/VotableProxyAdmin.Full.sol", "dist:emifactory": "node update-version.js && truffle-flattener ./contracts/EmiFactory.sol > ./flat/EmiFactory.Full.sol", "dist:emirouter": "node update-version.js && truffle-flattener ./contracts/EmiRouter.sol > ./flat/EmiRouter.Full.sol", @@ -106,6 +107,7 @@ "dist:emivault-kucoin": "node update-version.js && truffle-flattener ./contracts/EmiVault-kucoin.sol > ./flat/EmiVault-kucoin.Full.sol", "dist:emiprice": "node update-version.js && truffle-flattener ./contracts/EmiPrice.sol > ./flat/EmiPrice.Full.sol", "dist:emiprice2": "node update-version.js && truffle-flattener ./contracts/EmiPrice2.sol > ./flat/EmiPrice2.Full.sol", + "dist:emiprice2-kucoin": "truffle-flattener ./contracts/EmiPrice2-kucoin.sol > ./flat/EmiPrice2-kucoin.Full.sol", "dist:timelock": "node update-version.js && truffle-flattener ./contracts/Timelock.sol > ./flat/Timelock.Full.sol", "dist:tokenmock": "node update-version.js && truffle-flattener ./contracts/mocks/TokenMock.sol > ./flat/mocks/TokenMock.Full.sol", "prettier": "prettier --write \"contracts/**/*.sol\"" From fb35ff37d05ff0f416931650ee782f04a1fcd69d Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Thu, 29 Jul 2021 09:20:51 +0300 Subject: [PATCH 12/24] Added readme for EmiPrice2 --- README.EmiPrice2.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 README.EmiPrice2.md diff --git a/README.EmiPrice2.md b/README.EmiPrice2.md new file mode 100644 index 0000000..6c77bf1 --- /dev/null +++ b/README.EmiPrice2.md @@ -0,0 +1,20 @@ +# Pricedump contract README + +Êîíòðàêò ïðåäíàçíà÷åí äëÿ ïîëó÷åíèÿ èíôîðìàöèè î öåíàõ òîêåíîâ íà áèðæàõ òèïà Uniswap îäíèì ìàññèâîì. + +## Ìåòîäû êîíòðàêòà + +### getCoinPrices +Ìåòîä ïðèíèìàåò íà âõîä ñïèñîê àäðåñîâ òîêåíîâ, äëÿ êîòîðûõ íåîáõîäèìî ïîëó÷èòü öåíó è èíäåêñ-óêàçàòåëü íà áèðæó, ñ êîòîðîé íåîáõîäèìî ïîëó÷àòü ýòè öåíû. +Ìåòîä âîçâðàùàåò ìàññèâ öåí óêàçàííûõ òîêåíîâ ïî îòíîøåíèþ ê DAI, óìíîæåííûõ íà 100000 (10 â ñòåïåíè 5) äëÿ èñêëþ÷åíèÿ îøèáîê îêðóãëåíèÿ. +Ò.å. äëÿ ïîëó÷åíèÿ òî÷íîé öåíû ñ òî÷íîñòüþ äî 5 çíàêà ïîñëå çàïÿòîé íåîáõîäèìî ïîëó÷åííîå çíà÷åíèå ïðèâåñòè ê ôîðìàòó ñ ïëàâàþùåé òî÷êîé è ïîäåëèòü íà 100000. +Åñëè öåíó äëÿ êàêîãî-òî òîêåíà îïðåäåëèòü íå óäàëîñü, â ñîîòâåòñòâóþùåé ïîçèöèè âîçâðàùàåòñÿ 0. + +Çíà÷åíèÿ ïàðàìåòðà _market: + - 0: íàøà ñîáñòâåííàÿ áèðæà + - 1: áèðæà Uniswap + - 2: áèðæà Mooniswap + +```solidity + function getCoinPrices(address [] calldata _coins, uint8 _market) external view returns(uint[] memory prices) +``` From fb43e3ebd69bd1bb3c4793ac1ec48fb2c30662de Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Sun, 1 Aug 2021 10:04:41 +0300 Subject: [PATCH 13/24] Update EmiList.full.sol --- flat/EmiList.full.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/flat/EmiList.full.sol b/flat/EmiList.full.sol index 3e2984b..ef2af70 100644 --- a/flat/EmiList.full.sol +++ b/flat/EmiList.full.sol @@ -27,8 +27,6 @@ abstract contract Context { // File: @openzeppelin/contracts/access/Ownable.sol -// SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.8.0; /** @@ -97,8 +95,6 @@ abstract contract Ownable is Context { // File: @openzeppelin/contracts/math/SafeMath.sol -// SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.8.0; /** @@ -314,8 +310,6 @@ library SafeMath { // File: contracts/interfaces/IEmiList.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.2; /************************************************************************* From ac2d833eb0e7faf3ab357917d1d7f9506ea77295 Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Sun, 1 Aug 2021 10:05:31 +0300 Subject: [PATCH 14/24] Update EmiList.full.sol Removed license comments --- flat/EmiList.full.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/flat/EmiList.full.sol b/flat/EmiList.full.sol index ef2af70..51cf70e 100644 --- a/flat/EmiList.full.sol +++ b/flat/EmiList.full.sol @@ -322,8 +322,6 @@ interface IEmiList { // File: contracts/EmiList.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.2; From 03b345f3f83ff75c316d560a773c08378a10971c Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Sun, 1 Aug 2021 11:33:52 +0300 Subject: [PATCH 15/24] Update EmiRouter.Full.sol Removed license --- flat/EmiRouter.Full.sol | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/flat/EmiRouter.Full.sol b/flat/EmiRouter.Full.sol index e2c904f..cf6c235 100644 --- a/flat/EmiRouter.Full.sol +++ b/flat/EmiRouter.Full.sol @@ -80,8 +80,6 @@ interface IERC20 { // File: @openzeppelin/contracts/math/SafeMath.sol -// SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.8.0; /** @@ -297,8 +295,6 @@ library SafeMath { // File: contracts/interfaces/IEmiswap.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.0; @@ -354,8 +350,6 @@ interface IEmiswap { // File: contracts/libraries/EmiswapLib.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.0; @@ -546,8 +540,6 @@ library EmiswapLib { // File: contracts/libraries/TransferHelper.sol -// SPDX-License-Identifier: GPL-3.0-or-later - pragma solidity >=0.6.0; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false @@ -603,8 +595,6 @@ library TransferHelper { // File: contracts/interfaces/IWETH.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.0; interface IWETH { @@ -617,8 +607,6 @@ interface IWETH { // File: contracts/EmiRouter.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.2; pragma experimental ABIEncoderV2; From 31aa555de2bd6b89ee5c9922d50fe5e82c4e5436 Mon Sep 17 00:00:00 2001 From: Eugene Rupakov Date: Sun, 1 Aug 2021 12:36:00 +0300 Subject: [PATCH 16/24] Update ESW.full.sol Removed license comments --- flat/ESW.full.sol | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/flat/ESW.full.sol b/flat/ESW.full.sol index f223071..0bf2e85 100644 --- a/flat/ESW.full.sol +++ b/flat/ESW.full.sol @@ -192,8 +192,6 @@ library Address { // File: @openzeppelin/contracts/proxy/Initializable.sol -// SPDX-License-Identifier: MIT - // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; @@ -249,8 +247,6 @@ abstract contract Initializable { // File: contracts/interfaces/IEmiVesting.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.2; /************************************************************************* @@ -265,7 +261,6 @@ interface IEmiVesting { // File: contracts/interfaces/IEmiList.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -279,7 +274,6 @@ interface IEmiList { // File: @openzeppelin/contracts/math/SafeMath.sol -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -496,7 +490,6 @@ library SafeMath { // File: contracts/libraries/Priviledgeable.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -549,8 +542,6 @@ abstract contract Priviledgeable { // File: @openzeppelin/contracts/utils/Context.sol -// SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.8.0; /* @@ -576,14 +567,10 @@ abstract contract Context { // File: @openzeppelin/contracts/GSN/Context.sol -// SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.8.0; // File: @openzeppelin/contracts/token/ERC20/IERC20.sol -// SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.8.0; /** @@ -662,8 +649,6 @@ interface IERC20 { // File: contracts/libraries/ProxiedERC20.sol -// SPDX-License-Identifier: UNLICENSED - pragma solidity ^0.6.0; @@ -1047,7 +1032,6 @@ contract ProxiedERC20 is Context, IERC20 { // File: contracts/libraries/OracleSign.sol -// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; abstract contract OracleSign { @@ -1102,7 +1086,6 @@ abstract contract OracleSign { // File: contracts/ESW.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; From ad511965131487aa1cf00a6763d8ffe3694cd4aa Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 28 Sep 2021 16:17:58 +0200 Subject: [PATCH 17/24] Fixed getting price for low reserve pairs (Emiswap, Uniswap) - modified _getOurPrice, _getUniswapPrice: set input value as small as available - new function _valueToDecimals - to get decimals in value --- contracts/EmiPrice2.sol | 93 +++++++++++++++++++++++++++++++++++++---- test/EmiPrice2.test.js | 49 +++++++++++++++++++--- 2 files changed, 128 insertions(+), 14 deletions(-) diff --git a/contracts/EmiPrice2.sol b/contracts/EmiPrice2.sol index fe0c9b5..6a4cd00 100644 --- a/contracts/EmiPrice2.sol +++ b/contracts/EmiPrice2.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; pragma experimental ABIEncoderV2; @@ -24,7 +24,7 @@ contract EmiPrice2 is Initializable, Priviledgeable { uint256 constant MARKET_1INCH = 2; uint256 constant MAX_PATH_LENGTH = 5; - string public codeVersion = "EmiPrice2 v1.0-200-g8d0b0fa"; + string public codeVersion = "EmiPrice2 v1.0-234-g31aa555"; /** * @dev Upgradeable proxy constructor replacement @@ -128,17 +128,32 @@ contract EmiPrice2 is Initializable, Priviledgeable { _prices[i] = 10**18; // special case: 1 for base token continue; } - - uint256 _in = 10**target_decimal; - + address[] memory _path = new address[](2); _path[0] = _coins[i]; _path[1] = _base; + + // get reserve to accurately check prices + (uint112 reserve0, uint112 reserve1, ) = + IUniswapV2Pair( + IUniswapV2Factory(IUniswapV2Router02(uniRouter).factory()) + .getPair(_path[0], _path[1]) + ) + .getReserves(); + + uint256 res = + address(_path[0]) < address(_path[1]) ? reserve0 : reserve1; + uint256 _inDecimals = + _valueToDecimals(res) <= target_decimal + ? _valueToDecimals(res) - 1 + : target_decimal; + uint256 _in = 10**(_inDecimals); + uint256[] memory _amts = IUniswapV2Router02(uniRouter).getAmountsOut(_in, _path); if (_amts.length > 0) { _prices[i] = _amts[_amts.length - 1].mul( - 10**(18 - base_decimal) + 10**(18 - base_decimal + target_decimal - _inDecimals) ); } else { _prices[i] = 0; @@ -182,7 +197,8 @@ contract EmiPrice2 is Initializable, Priviledgeable { if (address(_p) == address(0)) { // we have to calc route _route = _calculateRoute(_coins[i], _base[m]); - } else { // just take direct pair + } else { + // just take direct pair _route = new address[](2); _route[0] = _coins[i]; _route[1] = _base[m]; @@ -190,12 +206,25 @@ contract EmiPrice2 is Initializable, Priviledgeable { if (_route.length == 0) { continue; // try next base token } else { - uint256 _in = 10**target_decimal; + uint256 res = + IEmiswap( + _factory.pools(IERC20(_route[0]), IERC20(_route[1])) + ) + .getBalanceForAddition(IERC20(_route[0])); + uint256 _inDecimals = + _valueToDecimals(res) <= target_decimal + ? _valueToDecimals(res) - 1 + : target_decimal; + uint256 _in = 10**(_inDecimals); uint256[] memory _amts = IEmiRouter(emiRouter).getAmountsOut(_in, _route); if (_amts.length > 0) { _prices[i] = _amts[_amts.length - 1].mul( - 10**(18 - base_decimal) + 10 ** + (18 - + base_decimal + + target_decimal - + _inDecimals) ); } else { _prices[i] = 0; @@ -206,6 +235,52 @@ contract EmiPrice2 is Initializable, Priviledgeable { } } + function _valueToDecimals(uint256 value) + internal + pure + returns (uint256 fullDecimals) + { + if (value >= 1e18) { + fullDecimals = 18; + } else if (value >= 1e17) { + fullDecimals = 17; + } else if (value >= 1e16) { + fullDecimals = 16; + } else if (value >= 1e15) { + fullDecimals = 15; + } else if (value >= 1e14) { + fullDecimals = 14; + } else if (value >= 1e13) { + fullDecimals = 13; + } else if (value >= 1e12) { + fullDecimals = 12; + } else if (value >= 1e11) { + fullDecimals = 11; + } else if (value >= 1e10) { + fullDecimals = 10; + } else if (value >= 1e9) { + fullDecimals = 9; + } else if (value >= 1e8) { + fullDecimals = 8; + } else if (value >= 1e7) { + fullDecimals = 7; + } else if (value >= 1e6) { + fullDecimals = 6; + } else if (value >= 1e5) { + fullDecimals = 5; + } else if (value >= 1e4) { + fullDecimals = 4; + } else if (value >= 1e3) { + fullDecimals = 3; + } else if (value >= 1e2) { + fullDecimals = 2; + } else if (value >= 1e1) { + fullDecimals = 1; + } else { + fullDecimals = 0; + } + } + /** * @dev Get price from 1inch integrator */ diff --git a/test/EmiPrice2.test.js b/test/EmiPrice2.test.js index 2b3e227..c8e68b7 100644 --- a/test/EmiPrice2.test.js +++ b/test/EmiPrice2.test.js @@ -14,6 +14,7 @@ const OneSplitFactory = contract.fromArtifact('OneSplitMock'); const EmiRouter = contract.fromArtifact('EmiRouter'); const MockUSDX = contract.fromArtifact('MockUSDX'); const MockUSDY = contract.fromArtifact('MockUSDY'); +const MockSMLTKN = contract.fromArtifact('MockUSDY'); const MockUSDZ = contract.fromArtifact('MockUSDZ'); const MockWETH = contract.fromArtifact('MockWETH'); const MockWBTC = contract.fromArtifact('MockWBTC'); @@ -36,6 +37,7 @@ let uniswapPair; let uPair; let usdx; let akita; +let smlTkn; let usdy; let usdz; let usdzz; @@ -80,6 +82,7 @@ describe('EmiPrice2 test', function () { usdz = await MockUSDZ.new(); usdzz = await MockUSDZ.new(); akita = await MockUSDY.new(); + smlTkn = await MockSMLTKN.new(); weth = await MockWETH.new(); wbtc = await MockWBTC.new(); price = await EmiPrice.new(); @@ -109,8 +112,8 @@ describe('EmiPrice2 test', function () { const wethToPair = new BN(1000).mul(new BN(10).pow(new BN(await weth.decimals()))).toString(); const usdzToPair = new BN(4010).mul(new BN(10).pow(new BN(await usdz.decimals()))).toString(); - const usdxToPair_USDXWETH = new BN(400000).mul(new BN(10).pow(new BN(await usdx.decimals()))).toString(); - const wethToPair_USDXWETH = new BN(1000).mul(new BN(10).pow(new BN(await weth.decimals()))).toString(); + const usdxToPair_USDXWETH = new BN(400).mul(new BN(10).pow(new BN(await usdx.decimals()))).toString(); + const wethToPair_USDXWETH = new BN(1).mul(new BN(10).pow(new BN(await weth.decimals()))).toString(); await weth.deposit({ value: wethToPair }); await weth.transfer(uniswapPair.address, wethToPair); @@ -213,6 +216,21 @@ describe('EmiPrice2 test', function () { money.zero, ZERO_ADDRESS); + // Init Small token pair + // smlTkn-usdx Add liquidity (1:1) (100000000:1000000000000000000) + console.log("smlTkn.balanceOf(TestOwner)", (await smlTkn.balanceOf(defaultSender)).toString()); + console.log("usdx.balanceOf(TestOwner)", (await usdx.balanceOf(defaultSender)).toString()); + await smlTkn.approve(emiRouter.address, money.weth('100000000')); + await usdx.approve(emiRouter.address, money.usdx('100000000')); + await emiRouter.addLiquidity( + smlTkn.address, + usdx.address, + '10000000000000000', + '100000000000000000000000000', + money.zero, + money.zero, + ZERO_ADDRESS); + await time.increase(60 * 10); // increase time to 10 minutes }); describe('get prices of coins', ()=> { @@ -282,8 +300,8 @@ describe('EmiPrice2 test', function () { assert.equal(p0, 1); assert.isAbove(p1, 1.91); assert.isBelow(p1, 1.917); - assert.isAbove(p2, 10.81); - assert.isBelow(p2, 10.811); + assert.isAbove(p2, 13.029); + assert.isBelow(p2, 13.03); }); it('should get our direct prices successfully', async function () { let route = await price.calcRoute(usdzz.address, usdx.address); @@ -301,7 +319,6 @@ describe('EmiPrice2 test', function () { assert.isAbove(p0, 0.029); assert.isBelow(p0, 0.03); }); - it('should get base token prices successfully', async function () { let b = await price.getCoinPrices([usdx.address, usdz.address], [usdx.address, usdz.address], 0); console.log('Got price results: %s, %s', b[0].toString(), b[1].toString()); @@ -358,5 +375,27 @@ describe('EmiPrice2 test', function () { assert.isAbove(p0, 0.38); assert.isBelow(p0, 0.39); }); + it('should get smlTkn price successfully', async function () { + console.log('Tokens: smlTkn %s, USDX %s', smlTkn.address, usdx.address); + + let p = await price.calcRoute(smlTkn.address, usdx.address); + console.log('Route from smlTnk to USDX: ', p); + + let b = await price.getCoinPrices([smlTkn.address], [usdx.address], 0); + console.log('Got price results: %s', b[0].toString()); + + let amt = await emiRouter.getAmountsOut('1000000000000', p); + amt.forEach(element => { + console.log('amt', element.toString()) + }) + + let p0 = parseFloat(web3.utils.fromWei(b[0])); + + console.log('Price calc: %f', p0, b[0].toString()); + + /* assert.equal(b.length, 1); + assert.isAbove(p0, 0.38); + assert.isBelow(p0, 0.39); */ + }); }); }); From 62e0379ccce1c4587c116f4c661f5101c799f494 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 6 Oct 2021 15:30:40 +0200 Subject: [PATCH 18/24] added Polygon vampirism contracts --- contracts/EmiVamp-polygon.sol | 399 ++++++++ flat/EmiVamp-polygon.Full.sol | 1622 +++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 2022 insertions(+) create mode 100644 contracts/EmiVamp-polygon.sol create mode 100644 flat/EmiVamp-polygon.Full.sol diff --git a/contracts/EmiVamp-polygon.sol b/contracts/EmiVamp-polygon.sol new file mode 100644 index 0000000..43cfc73 --- /dev/null +++ b/contracts/EmiVamp-polygon.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +import "./uniswapv2/interfaces/IUniswapV2Pair.sol"; +import "./uniswapv2/interfaces/IUniswapV2Factory.sol"; +import "./libraries/Priviledgeable.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import "./interfaces/IEmiswap.sol"; +import "./interfaces/IEmiVoting.sol"; +import "./interfaces/IMooniswap.sol"; +import "./libraries/TransferHelper.sol"; +import "./libraries/EmiswapLib.sol"; + +/** + * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. + */ +contract EmiVampPolygon is Priviledgeable, ReentrancyGuard { + using SafeERC20 for IERC20; + + struct LPTokenInfo { + address lpToken; + uint16 tokenType; // Token type: 0 - uniswap (default), 1 - mooniswap + } + + // Info of each third-party lp-token. + LPTokenInfo[] public lpTokensInfo; + + string public codeVersion = "EmiVampPolygon v1.0.0"; + address public ourFactory; + event Deposit(address indexed user, address indexed token, uint256 amount); + + address public defRef; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + /** + * @dev Implementation of {UpgradeableProxy} type of constructors + */ + constructor( + address[] memory _lptokens, + uint8[] memory _types, + address _ourfactory + ) public { + require(_lptokens.length > 0, "EmiVamp: length>0!"); + require(_lptokens.length == _types.length, "EmiVamp: lengths!"); + require(_ourfactory != address(0), "EmiVamp: factory!"); + + for (uint256 i = 0; i < _lptokens.length; i++) { + lpTokensInfo.push( + LPTokenInfo({lpToken: _lptokens[i], tokenType: _types[i]}) + ); + } + ourFactory = _ourfactory; + defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); + _addAdmin(msg.sender); + } + + /** + * @dev Returns length of LP-tokens private array + */ + function lpTokensInfoLength() external view returns (uint256) { + return lpTokensInfo.length; + } + + /** + * @dev Returns pair base tokens + */ + function lpTokenDetailedInfo(uint256 _pid) + external + view + returns (address, address) + { + require(_pid < lpTokensInfo.length, "EmiVamp: Wrong lpToken idx"); + + if (lpTokensInfo[_pid].tokenType == 0) { + // this is uniswap + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + return (lpToken.token0(), lpToken.token1()); + } else { + // this is mooniswap + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + return (address(t[0]), address(t[1])); + } + } + + /** + + * @dev Adds new entry to the list of convertible LP-tokens + */ + function addLPToken(address _token, uint16 _tokenType) + external + onlyAdmin + returns (uint256) + { + require(_token != address(0), "EmiVamp: Token address cannot be 0"); + require(_tokenType < 2, "EmiVamp: Wrong type"); + + for (uint256 i = 0; i < lpTokensInfo.length; i++) { + if (lpTokensInfo[i].lpToken == _token) { + return i; + } + } + lpTokensInfo.push( + LPTokenInfo({lpToken: _token, tokenType: _tokenType}) + ); + return lpTokensInfo.length; + } + + /** + * @dev Remove entry from the list of convertible LP-tokens + */ + function removeLPToken(uint256 _idx) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + + delete lpTokensInfo[_idx]; + } + + /** + * @dev Change entry from the list of convertible LP-tokens + */ + function changeLPToken( + uint256 _idx, + address _token, + uint16 _tokenType + ) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + require(_token != address(0), "EmiVamp: token=0!"); + require(_tokenType < 2, "EmiVamp: wrong tokenType"); + + lpTokensInfo[_idx].lpToken = _token; + lpTokensInfo[_idx].tokenType = _tokenType; + } + + /** + * @dev Change emifactory address + */ + function changeFactory(address _newFactory) external onlyAdmin { + require( + _newFactory != address(0), + "EmiVamp: New factory address is wrong" + ); + ourFactory = _newFactory; + } + + /** + * @dev Change default referrer address + */ + function changeReferral(address _ref) external onlyAdmin { + defRef = _ref; + } + + // Deposit LP tokens to us + /** + * @dev Main function that converts third-party liquidity (represented by LP-tokens) to our own LP-tokens + */ + function deposit(uint256 _pid, uint256 _amount) public { + require(_pid < lpTokensInfo.length, "EmiVamp: pool idx is wrong"); + + if (lpTokensInfo[_pid].tokenType == 0) { + _depositUniswap(_pid, _amount); + } else if (lpTokensInfo[_pid].tokenType == 1) { + _depositMooniswap(_pid, _amount); + } else { + return; + } + emit Deposit(msg.sender, lpTokensInfo[_pid].lpToken, _amount); + } + + /** + * @dev Actual function that converts third-party Uniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositUniswap(uint256 _pid, uint256 _amount) internal { + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + + // check pair existance + IERC20 token0 = IERC20(lpToken.token0()); + IERC20 token1 = IERC20(lpToken.token1()); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(lpToken), + _amount + ); + + // get liquidity + (uint256 amountIn0, uint256 amountIn1) = lpToken.burn(address(this)); + + _addOurLiquidity( + address(token0), + address(token1), + amountIn0, + amountIn1, + msg.sender + ); + } + + function _addOurLiquidity( + address _token0, + address _token1, + uint256 _amount0, + uint256 _amount1, + address _to + ) internal { + (uint256 amountA, uint256 amountB) = + _addLiquidity(_token0, _token1, _amount0, _amount1); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools( + IERC20(_token0), + IERC20(_token1) + ); + + TransferHelper.safeApprove(_token0, address(pairContract), amountA); + TransferHelper.safeApprove(_token1, address(pairContract), amountB); + + uint256[] memory amounts; + amounts = new uint256[](2); + uint256[] memory minAmounts; + minAmounts = new uint256[](2); + + if (_token0 < _token1) { + amounts[0] = amountA; + amounts[1] = amountB; + } else { + amounts[0] = amountB; + amounts[1] = amountA; + } + + uint256 liquidity = + IEmiswap(pairContract).deposit(amounts, minAmounts, defRef); + TransferHelper.safeTransfer(address(pairContract), _to, liquidity); + + // return the change + if (amountA < _amount0) { + // consumed less tokens 0 than given + TransferHelper.safeTransfer( + _token0, + address(msg.sender), + _amount0.sub(amountA) + ); + } + + if (amountB < _amount1) { + // consumed less tokens 1 than given + TransferHelper.safeTransfer( + _token1, + address(msg.sender), + _amount1.sub(amountB) + ); + } + } + + /** + * @dev Actual function that converts third-party Mooniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositMooniswap(uint256 _pid, uint256 _amount) internal { + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + + // check pair existance + IERC20 token0 = IERC20(t[0]); + IERC20 token1 = IERC20(t[1]); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(this), + _amount + ); + + uint256 amountBefore0 = token0.balanceOf(address(this)); + uint256 amountBefore1 = token1.balanceOf(address(this)); + + uint256[] memory minVals = new uint256[](2); + + lpToken.withdraw(_amount, minVals); + + // get liquidity + uint256 amount0 = token0.balanceOf(address(this)).sub(amountBefore0); + uint256 amount1 = token1.balanceOf(address(this)).sub(amountBefore1); + + _addOurLiquidity( + address(token0), + address(token1), + amount0, + amount1, + msg.sender + ); + } + + /** + @dev Function check for LP token pair availability. Return _pid or 0 if none exists + */ + function isPairAvailable(address _token0, address _token1) + public + view + returns (uint16) + { + require(_token0 != address(0), "EmiVamp: wrong token0 address"); + require(_token1 != address(0), "EmiVamp: wrong token1 address"); + + for (uint16 i = 0; i < lpTokensInfo.length; i++) { + address t0 = address(0); + address t1 = address(0); + + if (lpTokensInfo[i].tokenType == 0) { + IUniswapV2Pair lpt = IUniswapV2Pair(lpTokensInfo[i].lpToken); + t0 = lpt.token0(); + t1 = lpt.token1(); + } else if (lpTokensInfo[i].tokenType == 1) { + IMooniswap lpToken = IMooniswap(lpTokensInfo[i].lpToken); + + IERC20[] memory t = lpToken.getTokens(); + + t0 = address(t[0]); + t1 = address(t[1]); + } else { + return 0; + } + + if ( + (t0 == _token0 && t1 == _token1) || + (t1 == _token0 && t0 == _token1) + ) { + return 1; + } + } + return 0; + } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired + ) internal returns (uint256 amountA, uint256 amountB) { + IERC20 ERC20tokenA = IERC20(tokenA); + IERC20 ERC20tokenB = IERC20(tokenB); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools(ERC20tokenA, ERC20tokenB); + // create the pair if it doesn't exist yet + if (pairContract == IEmiswap(0)) { + pairContract = IEmiswapRegistry(ourFactory).deploy( + ERC20tokenA, + ERC20tokenB + ); + } + + uint256 reserveA = pairContract.getBalanceForAddition(ERC20tokenA); + uint256 reserveB = pairContract.getBalanceForRemoval(ERC20tokenB); + + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint256 amountBOptimal = + EmiswapLib.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require( + amountBOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_B_AMOUNT" + ); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint256 amountAOptimal = + EmiswapLib.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require( + amountAOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_A_AMOUNT" + ); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "EmiVamp: Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} diff --git a/flat/EmiVamp-polygon.Full.sol b/flat/EmiVamp-polygon.Full.sol new file mode 100644 index 0000000..79c9b5c --- /dev/null +++ b/flat/EmiVamp-polygon.Full.sol @@ -0,0 +1,1622 @@ +// File: contracts/uniswapv2/interfaces/IUniswapV2Pair.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +interface IUniswapV2Pair { + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); + event Transfer(address indexed from, address indexed to, uint256 value); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); + + function decimals() external pure returns (uint8); + + function totalSupply() external view returns (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function allowance(address owner, address spender) + external + view + returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external view returns (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + event Burn( + address indexed sender, + uint256 amount0, + uint256 amount1, + address indexed to + ); + event Swap( + address indexed sender, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint256); + + function factory() external view returns (address); + + function token0() external view returns (address); + + function token1() external view returns (address); + + function getReserves() + external + view + returns ( + uint112 reserve0, + uint112 reserve1, + uint32 blockTimestampLast + ); + + function price0CumulativeLast() external view returns (uint256); + + function price1CumulativeLast() external view returns (uint256); + + function kLast() external view returns (uint256); + + function mint(address to) external returns (uint256 liquidity); + + function burn(address to) + external + returns (uint256 amount0, uint256 amount1); + + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data + ) external; + + function skim(address to) external; + + function sync() external; + + function initialize(address, address) external; +} + +// File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +interface IUniswapV2Factory { + event PairCreated( + address indexed token0, + address indexed token1, + address pair, + uint256 + ); + + function feeTo() external view returns (address); + + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) + external + view + returns (address pair); + + function allPairs(uint256) external view returns (address pair); + + function allPairsLength() external view returns (uint256); + + function createPair(address tokenA, address tokenB) + external + returns (address pair); + + function setFeeTo(address) external; + + function setFeeToSetter(address) external; +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: @openzeppelin/contracts/utils/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () internal { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + +// File: contracts/interfaces/IEmiswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IEmiswapRegistry { + function pools(IERC20 token1, IERC20 token2) + external + view + returns (IEmiswap); + + function isPool(address addr) external view returns (bool); + + function deploy(IERC20 tokenA, IERC20 tokenB) external returns (IEmiswap); + + function getAllPools() external view returns (IEmiswap[] memory); +} + +interface IEmiswap { + function fee() external view returns (uint256); + + function tokens(uint256 i) external view returns (IERC20); + + function deposit( + uint256[] calldata amounts, + uint256[] calldata minAmounts, + address referral + ) external payable returns (uint256 fairSupply); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; + + function getBalanceForAddition(IERC20 token) + external + view + returns (uint256); + + function getBalanceForRemoval(IERC20 token) external view returns (uint256); + + function getReturn( + IERC20 fromToken, + IERC20 destToken, + uint256 amount + ) external view returns (uint256, uint256); + + function swap( + IERC20 fromToken, + IERC20 destToken, + uint256 amount, + uint256 minReturn, + address to, + address referral + ) external payable returns (uint256 returnAmount); + + function initialize(IERC20[] calldata assets) external; +} + +// File: contracts/interfaces/IEmiVoting.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +interface IEmiVoting { + function getVotingResult(uint256 _hash) external view returns (address); +} + +// File: contracts/interfaces/IMooniswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IMooniswap { + function getTokens() external view returns (IERC20[] memory); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; +} + +// File: contracts/libraries/TransferHelper.sol + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity >=0.6.0; + +// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false +library TransferHelper { + function safeApprove( + address token, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('approve(address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: APPROVE_FAILED" + ); + } + + function safeTransfer( + address token, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('transfer(address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: TRANSFER_FAILED" + ); + } + + function safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: TRANSFER_FROM_FAILED" + ); + } + + function safeTransferETH(address to, uint256 value) internal { + (bool success, ) = to.call{value: value}(new bytes(0)); + require(success, "TransferHelper: ETH_TRANSFER_FAILED"); + } +} + +// File: contracts/libraries/EmiswapLib.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + +library EmiswapLib { + using SafeMath for uint256; + uint256 public constant FEE_DENOMINATOR = 1e18; + + function previewSwapExactTokenForToken( + address factory, + address tokenFrom, + address tokenTo, + uint256 ammountFrom + ) internal view returns (uint256 ammountTo) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools(IERC20(tokenFrom), IERC20(tokenTo)); + + if (pairContract != IEmiswap(0)) { + (, ammountTo) = pairContract.getReturn( + IERC20(tokenFrom), + IERC20(tokenTo), + ammountFrom + ); + } + } + + /************************************************************************************** + * get preview result of virtual swap by route of tokens + **************************************************************************************/ + function previewSwapbyRoute( + address factory, + address[] memory path, + uint256 ammountFrom + ) internal view returns (uint256 ammountTo) { + for (uint256 i = 0; i < path.length - 1; i++) { + if (path.length >= 2) { + ammountTo = previewSwapExactTokenForToken( + factory, + path[i], + path[i + 1], + ammountFrom + ); + + if (i == (path.length - 2)) { + return (ammountTo); + } else { + ammountFrom = ammountTo; + } + } + } + } + + function fee(address factory) internal view returns (uint256) { + return IEmiswap(factory).fee(); + } + + // given an output amount of an asset and pair reserves, returns a required input amount of the other asset + function getAmountIn( + address factory, + uint256 amountOut, + uint256 reserveIn, + uint256 reserveOut + ) internal view returns (uint256 amountIn) { + require(amountOut > 0, "EmiswapLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); + require( + reserveIn > 0 && reserveOut > 0, + "EmiswapLibrary: INSUFFICIENT_LIQUIDITY" + ); + uint256 numerator = reserveIn.mul(amountOut).mul(1000); + uint256 denominator = + reserveOut.sub(amountOut).mul( + uint256(1000000000000000000).sub(fee(factory)).div(1e15) + ); // 997 + amountIn = (numerator / denominator).add(1); + } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut( + address factory, + uint256 amountIn, + uint256 reserveIn, + uint256 reserveOut + ) internal view returns (uint256 amountOut) { + if (amountIn == 0 || reserveIn == 0 || reserveOut == 0) { + return (0); + } + + uint256 amountInWithFee = + amountIn.mul( + uint256(1000000000000000000).sub(fee(factory)).div(1e15) + ); //997 + uint256 numerator = amountInWithFee.mul(reserveOut); + uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); + amountOut = (denominator == 0 ? 0 : amountOut = + numerator / + denominator); + } + + // performs chained getAmountIn calculations on any number of pairs + function getAmountsIn( + address factory, + uint256 amountOut, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2, "EmiswapLibrary: INVALID_PATH"); + amounts = new uint256[](path.length); + amounts[amounts.length - 1] = amountOut; + for (uint256 i = path.length - 1; i > 0; i--) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools( + IERC20(IERC20(path[i])), + IERC20(path[i - 1]) + ); + + uint256 reserveIn; + uint256 reserveOut; + + if (address(pairContract) != address(0)) { + reserveIn = IEmiswap(pairContract).getBalanceForAddition( + IERC20(path[i - 1]) + ); + reserveOut = IEmiswap(pairContract).getBalanceForRemoval( + IERC20(path[i]) + ); + } + + amounts[i - 1] = getAmountIn( + factory, + amounts[i], + reserveIn, + reserveOut + ); + } + } + + // performs chained getAmountOut calculations on any number of pairs + function getAmountsOut( + address factory, + uint256 amountIn, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2, "EmiswapLibrary: INVALID_PATH"); + amounts = new uint256[](path.length); + amounts[0] = amountIn; + for (uint256 i = 0; i < path.length - 1; i++) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools( + IERC20(IERC20(path[i])), + IERC20(path[i + 1]) + ); + + uint256 reserveIn; + uint256 reserveOut; + + if (address(pairContract) != address(0)) { + reserveIn = IEmiswap(pairContract).getBalanceForAddition( + IERC20(path[i]) + ); + reserveOut = IEmiswap(pairContract).getBalanceForRemoval( + IERC20(path[i + 1]) + ); + } + + amounts[i + 1] = getAmountOut( + factory, + amounts[i], + reserveIn, + reserveOut + ); + } + } + + // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset + function quote( + uint256 amountA, + uint256 reserveA, + uint256 reserveB + ) internal pure returns (uint256 amountB) { + require(amountA > 0, "EmiswapLibrary: INSUFFICIENT_AMOUNT"); + require( + reserveA > 0 && reserveB > 0, + "EmiswapLibrary: INSUFFICIENT_LIQUIDITY" + ); + amountB = amountA.mul(reserveB) / reserveA; + } +} + +// File: contracts/EmiVamp-polygon.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + + + + + + + + + + + + +/** + * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. + */ +contract EmiVampPolygon is Priviledgeable, ReentrancyGuard { + using SafeERC20 for IERC20; + + struct LPTokenInfo { + address lpToken; + uint16 tokenType; // Token type: 0 - uniswap (default), 1 - mooniswap + } + + // Info of each third-party lp-token. + LPTokenInfo[] public lpTokensInfo; + + string public codeVersion = "EmiVampPolygon v1.0.0"; + address public ourFactory; + event Deposit(address indexed user, address indexed token, uint256 amount); + + address public defRef; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + /** + * @dev Implementation of {UpgradeableProxy} type of constructors + */ + constructor( + address[] memory _lptokens, + uint8[] memory _types, + address _ourfactory + ) public { + require(_lptokens.length > 0, "EmiVamp: length>0!"); + require(_lptokens.length == _types.length, "EmiVamp: lengths!"); + require(_ourfactory != address(0), "EmiVamp: factory!"); + + for (uint256 i = 0; i < _lptokens.length; i++) { + lpTokensInfo.push( + LPTokenInfo({lpToken: _lptokens[i], tokenType: _types[i]}) + ); + } + ourFactory = _ourfactory; + defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); + _addAdmin(msg.sender); + } + + /** + * @dev Returns length of LP-tokens private array + */ + function lpTokensInfoLength() external view returns (uint256) { + return lpTokensInfo.length; + } + + /** + * @dev Returns pair base tokens + */ + function lpTokenDetailedInfo(uint256 _pid) + external + view + returns (address, address) + { + require(_pid < lpTokensInfo.length, "EmiVamp: Wrong lpToken idx"); + + if (lpTokensInfo[_pid].tokenType == 0) { + // this is uniswap + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + return (lpToken.token0(), lpToken.token1()); + } else { + // this is mooniswap + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + return (address(t[0]), address(t[1])); + } + } + + /** + + * @dev Adds new entry to the list of convertible LP-tokens + */ + function addLPToken(address _token, uint16 _tokenType) + external + onlyAdmin + returns (uint256) + { + require(_token != address(0), "EmiVamp: Token address cannot be 0"); + require(_tokenType < 2, "EmiVamp: Wrong type"); + + for (uint256 i = 0; i < lpTokensInfo.length; i++) { + if (lpTokensInfo[i].lpToken == _token) { + return i; + } + } + lpTokensInfo.push( + LPTokenInfo({lpToken: _token, tokenType: _tokenType}) + ); + return lpTokensInfo.length; + } + + /** + * @dev Remove entry from the list of convertible LP-tokens + */ + function removeLPToken(uint256 _idx) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + + delete lpTokensInfo[_idx]; + } + + /** + * @dev Change entry from the list of convertible LP-tokens + */ + function changeLPToken( + uint256 _idx, + address _token, + uint16 _tokenType + ) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + require(_token != address(0), "EmiVamp: token=0!"); + require(_tokenType < 2, "EmiVamp: wrong tokenType"); + + lpTokensInfo[_idx].lpToken = _token; + lpTokensInfo[_idx].tokenType = _tokenType; + } + + /** + * @dev Change emifactory address + */ + function changeFactory(address _newFactory) external onlyAdmin { + require( + _newFactory != address(0), + "EmiVamp: New factory address is wrong" + ); + ourFactory = _newFactory; + } + + /** + * @dev Change default referrer address + */ + function changeReferral(address _ref) external onlyAdmin { + defRef = _ref; + } + + // Deposit LP tokens to us + /** + * @dev Main function that converts third-party liquidity (represented by LP-tokens) to our own LP-tokens + */ + function deposit(uint256 _pid, uint256 _amount) public { + require(_pid < lpTokensInfo.length, "EmiVamp: pool idx is wrong"); + + if (lpTokensInfo[_pid].tokenType == 0) { + _depositUniswap(_pid, _amount); + } else if (lpTokensInfo[_pid].tokenType == 1) { + _depositMooniswap(_pid, _amount); + } else { + return; + } + emit Deposit(msg.sender, lpTokensInfo[_pid].lpToken, _amount); + } + + /** + * @dev Actual function that converts third-party Uniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositUniswap(uint256 _pid, uint256 _amount) internal { + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + + // check pair existance + IERC20 token0 = IERC20(lpToken.token0()); + IERC20 token1 = IERC20(lpToken.token1()); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(lpToken), + _amount + ); + + // get liquidity + (uint256 amountIn0, uint256 amountIn1) = lpToken.burn(address(this)); + + _addOurLiquidity( + address(token0), + address(token1), + amountIn0, + amountIn1, + msg.sender + ); + } + + function _addOurLiquidity( + address _token0, + address _token1, + uint256 _amount0, + uint256 _amount1, + address _to + ) internal { + (uint256 amountA, uint256 amountB) = + _addLiquidity(_token0, _token1, _amount0, _amount1); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools( + IERC20(_token0), + IERC20(_token1) + ); + + TransferHelper.safeApprove(_token0, address(pairContract), amountA); + TransferHelper.safeApprove(_token1, address(pairContract), amountB); + + uint256[] memory amounts; + amounts = new uint256[](2); + uint256[] memory minAmounts; + minAmounts = new uint256[](2); + + if (_token0 < _token1) { + amounts[0] = amountA; + amounts[1] = amountB; + } else { + amounts[0] = amountB; + amounts[1] = amountA; + } + + uint256 liquidity = + IEmiswap(pairContract).deposit(amounts, minAmounts, defRef); + TransferHelper.safeTransfer(address(pairContract), _to, liquidity); + + // return the change + if (amountA < _amount0) { + // consumed less tokens 0 than given + TransferHelper.safeTransfer( + _token0, + address(msg.sender), + _amount0.sub(amountA) + ); + } + + if (amountB < _amount1) { + // consumed less tokens 1 than given + TransferHelper.safeTransfer( + _token1, + address(msg.sender), + _amount1.sub(amountB) + ); + } + } + + /** + * @dev Actual function that converts third-party Mooniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositMooniswap(uint256 _pid, uint256 _amount) internal { + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + + // check pair existance + IERC20 token0 = IERC20(t[0]); + IERC20 token1 = IERC20(t[1]); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(this), + _amount + ); + + uint256 amountBefore0 = token0.balanceOf(address(this)); + uint256 amountBefore1 = token1.balanceOf(address(this)); + + uint256[] memory minVals = new uint256[](2); + + lpToken.withdraw(_amount, minVals); + + // get liquidity + uint256 amount0 = token0.balanceOf(address(this)).sub(amountBefore0); + uint256 amount1 = token1.balanceOf(address(this)).sub(amountBefore1); + + _addOurLiquidity( + address(token0), + address(token1), + amount0, + amount1, + msg.sender + ); + } + + /** + @dev Function check for LP token pair availability. Return _pid or 0 if none exists + */ + function isPairAvailable(address _token0, address _token1) + public + view + returns (uint16) + { + require(_token0 != address(0), "EmiVamp: wrong token0 address"); + require(_token1 != address(0), "EmiVamp: wrong token1 address"); + + for (uint16 i = 0; i < lpTokensInfo.length; i++) { + address t0 = address(0); + address t1 = address(0); + + if (lpTokensInfo[i].tokenType == 0) { + IUniswapV2Pair lpt = IUniswapV2Pair(lpTokensInfo[i].lpToken); + t0 = lpt.token0(); + t1 = lpt.token1(); + } else if (lpTokensInfo[i].tokenType == 1) { + IMooniswap lpToken = IMooniswap(lpTokensInfo[i].lpToken); + + IERC20[] memory t = lpToken.getTokens(); + + t0 = address(t[0]); + t1 = address(t[1]); + } else { + return 0; + } + + if ( + (t0 == _token0 && t1 == _token1) || + (t1 == _token0 && t0 == _token1) + ) { + return 1; + } + } + return 0; + } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired + ) internal returns (uint256 amountA, uint256 amountB) { + IERC20 ERC20tokenA = IERC20(tokenA); + IERC20 ERC20tokenB = IERC20(tokenB); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools(ERC20tokenA, ERC20tokenB); + // create the pair if it doesn't exist yet + if (pairContract == IEmiswap(0)) { + pairContract = IEmiswapRegistry(ourFactory).deploy( + ERC20tokenA, + ERC20tokenB + ); + } + + uint256 reserveA = pairContract.getBalanceForAddition(ERC20tokenA); + uint256 reserveB = pairContract.getBalanceForRemoval(ERC20tokenB); + + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint256 amountBOptimal = + EmiswapLib.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require( + amountBOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_B_AMOUNT" + ); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint256 amountAOptimal = + EmiswapLib.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require( + amountAOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_A_AMOUNT" + ); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "EmiVamp: Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} diff --git a/package.json b/package.json index 99edd37..9f18934 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", "dist:emivamp": "node update-version.js && truffle-flattener ./contracts/EmiVamp.sol > ./flat/EmiVamp.Full.sol", "dist:emivamp-kucoin": "truffle-flattener ./contracts/EmiVamp-kucoin.sol > ./flat/EmiVamp-kucoin.Full.sol", + "dist:emivamp-polygon": "truffle-flattener ./contracts/EmiVamp-polygon.sol > ./flat/EmiVamp-polygon.Full.sol", "dist:votableproxyadmin": "node update-version.js && truffle-flattener ./contracts/VotableProxyAdmin.sol > ./flat/VotableProxyAdmin.Full.sol", "dist:emifactory": "node update-version.js && truffle-flattener ./contracts/EmiFactory.sol > ./flat/EmiFactory.Full.sol", "dist:emirouter": "node update-version.js && truffle-flattener ./contracts/EmiRouter.sol > ./flat/EmiRouter.Full.sol", From b6de5c8fb8a015c3f824b35e219eeca78c1843b7 Mon Sep 17 00:00:00 2001 From: Maksim Date: Thu, 7 Oct 2021 15:17:40 +0200 Subject: [PATCH 19/24] Added function transferAnyERC20Token --- contracts/ESW.sol | 334 +++++++++++++++-- .../uniswapv2/libraries/UniswapV2Library.sol | 3 +- flat/ESW.full.sol | 349 ++++++++++++++++-- test/EmiPrice2.test.js | 2 +- 4 files changed, 611 insertions(+), 77 deletions(-) diff --git a/contracts/ESW.sol b/contracts/ESW.sol index 083c273..b86fe3f 100644 --- a/contracts/ESW.sol +++ b/contracts/ESW.sol @@ -8,7 +8,222 @@ import "./libraries/Priviledgeable.sol"; import "./libraries/ProxiedERC20.sol"; import "./libraries/OracleSign.sol"; -contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { +// Exempt from the original UniswapV2Library. +library UniswapV2Library { + // returns sorted token addresses, used to handle return values from pairs sorted in this order + function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { + require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); + (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); + require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); + } + + // calculates the CREATE2 address for a pair without making any external calls + function pairFor(bytes32 initCodeHash, address factory, address tokenA, address tokenB) internal pure returns (address pair) { + (address token0, address token1) = sortTokens(tokenA, tokenB); + pair = address(uint(keccak256(abi.encodePacked( + hex'ff', + factory, + keccak256(abi.encodePacked(token0, token1)), + initCodeHash // init code hash + )))); + } +} + +pragma solidity ^0.6.0; + +/// @notice based on https://github.com/Uniswap/uniswap-v3-periphery/blob/v1.0.0/contracts/libraries/PoolAddress.sol +/// @notice changed compiler version and lib name. + +/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee +library UniswapV3Library { + bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54; + + /// @notice The identifying key of the pool + struct PoolKey { + address token0; + address token1; + uint24 fee; + } + + /// @notice Returns PoolKey: the ordered tokens with the matched fee levels + /// @param tokenA The first token of a pool, unsorted + /// @param tokenB The second token of a pool, unsorted + /// @param fee The fee level of the pool + /// @return Poolkey The pool details with ordered token0 and token1 assignments + function getPoolKey( + address tokenA, + address tokenB, + uint24 fee + ) internal pure returns (PoolKey memory) { + if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); + return PoolKey({token0: tokenA, token1: tokenB, fee: fee}); + } + + /// @notice Deterministically computes the pool address given the factory and PoolKey + /// @param factory The Uniswap V3 factory contract address + /// @param key The PoolKey + /// @return pool The contract address of the V3 pool + function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) { + require(key.token0 < key.token1); + pool = address( + uint256( + keccak256( + abi.encodePacked( + hex'ff', + factory, + keccak256(abi.encode(key.token0, key.token1, key.fee)), + POOL_INIT_CODE_HASH + ) + ) + ) + ); + } +} + + +pragma solidity ^0.6.0; + +interface IPLPS { + function LiquidityProtection_beforeTokenTransfer( + address _pool, address _from, address _to, uint _amount) external; + function isBlocked(address _pool, address _who) external view returns(bool); + function unblock(address _pool, address _who) external; +} + + +pragma solidity ^0.6.0; + + +abstract contract UsingLiquidityProtectionService { + bool private protected = true; + uint64 internal constant HUNDRED_PERCENT = 1e18; + bytes32 internal constant UNISWAP = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f; + bytes32 internal constant PANCAKESWAP = 0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5; + + enum UniswapVersion { + V2, + V3 + } + + enum UniswapV3Fees { + _005, // 0.05% + _03, // 0.3% + _1 // 1% + } + + modifier onlyProtectionAdmin() { + protectionAdminCheck(); + _; + } + + function token_transfer(address from, address to, uint amount) internal virtual; + function token_balanceOf(address holder) internal view virtual returns(uint); + function protectionAdminCheck() internal view virtual; + function liquidityProtectionService() internal pure virtual returns(address); + function uniswapVariety() internal pure virtual returns(bytes32); + function uniswapVersion() internal pure virtual returns(UniswapVersion); + function uniswapFactory() internal pure virtual returns(address); + function counterToken() internal pure virtual returns(address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH + } + function uniswapV3Fee() internal pure virtual returns(UniswapV3Fees) { + return UniswapV3Fees._03; + } + function protectionChecker() internal view virtual returns(bool) { + return ProtectionSwitch_manual(); + } + + function lps() private pure returns(IPLPS) { + return IPLPS(liquidityProtectionService()); + } + + function LiquidityProtection_beforeTokenTransfer(address _from, address _to, uint _amount) internal virtual { + if (protectionChecker()) { + if (!protected) { + return; + } + lps().LiquidityProtection_beforeTokenTransfer(getLiquidityPool(), _from, _to, _amount); + } + } + + function revokeBlocked(address[] calldata _holders, address _revokeTo) external onlyProtectionAdmin() { + require(protectionChecker(), 'UsingLiquidityProtectionService: protection removed'); + protected = false; + address pool = getLiquidityPool(); + for (uint i = 0; i < _holders.length; i++) { + address holder = _holders[i]; + if (lps().isBlocked(pool, holder)) { + token_transfer(holder, _revokeTo, token_balanceOf(holder)); + } + } + protected = true; + } + + function LiquidityProtection_unblock(address[] calldata _holders) external onlyProtectionAdmin() { + require(protectionChecker(), 'UsingLiquidityProtectionService: protection removed'); + address pool = getLiquidityPool(); + for (uint i = 0; i < _holders.length; i++) { + lps().unblock(pool, _holders[i]); + } + } + + function disableProtection() external onlyProtectionAdmin() { + protected = false; + } + + function isProtected() public view returns(bool) { + return protected; + } + + function ProtectionSwitch_manual() internal view returns(bool) { + return protected; + } + + function ProtectionSwitch_timestamp(uint _timestamp) internal view returns(bool) { + return not(passed(_timestamp)); + } + + function ProtectionSwitch_block(uint _block) internal view returns(bool) { + return not(blockPassed(_block)); + } + + function blockPassed(uint _block) internal view returns(bool) { + return _block < block.number; + } + + function passed(uint _timestamp) internal view returns(bool) { + return _timestamp < block.timestamp; + } + + function not(bool _condition) internal pure returns(bool) { + return !_condition; + } + + function feeToUint24(UniswapV3Fees _fee) internal pure returns(uint24) { + if (_fee == UniswapV3Fees._03) return 3000; + if (_fee == UniswapV3Fees._005) return 500; + return 10000; + } + + function getLiquidityPool() public view returns(address) { + if (uniswapVersion() == UniswapVersion.V2) { + return UniswapV2Library.pairFor(uniswapVariety(), uniswapFactory(), address(this), counterToken()); + } + require(uniswapVariety() == UNISWAP, 'LiquidityProtection: uniswapVariety() can only be UNISWAP for V3.'); + return UniswapV3Library.computeAddress(uniswapFactory(), + UniswapV3Library.getPoolKey(address(this), counterToken(), feeToUint24(uniswapV3Fee()))); + } +} + + + +// File: contracts/ESW.sol + +pragma solidity ^0.6.2; + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLiquidityProtectionService { address public dividendToken; address public vesting; uint256 internal _initialSupply; @@ -18,14 +233,14 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - string public codeVersion = "ESW v1.1-145-gf234c9e"; + string public codeVersion = "ESW v1.1-145-gf234c9e"; uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; bool public isFirstMinter = true; address public constant firstMinter = - 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle address public constant secondMinter = - 0x9Cf73e538acC5B2ea51396eA1a6DE505f6a68f2b; //set to EmiVesting + 0x9Cf73e538acC5B2ea51396eA1a6DE505f6a68f2b; //set to EmiVesting uint256 public minterChangeBlock; event MinterSwitch(address newMinter, uint256 afterBlock); @@ -42,8 +257,8 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { /*********************** admin functions *****************************/ function updateTokenName(string memory newName, string memory newSymbol) - public - onlyAdmin + public + onlyAdmin { _updateTokenName(newName, newSymbol); } @@ -73,22 +288,34 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { } function transfer(address recipient, uint256 amount) - public - virtual - override - returns (bool) + public + virtual + override + returns (bool) { super.transfer(recipient, amount); return true; } function setListAddress(address emiList) - public - onlyAdmin + public + onlyAdmin { _emiList = emiList; // can be NULL also to remove emiList functionality totally } + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin returns (bool success) { + require(tokenAddress != address(0), "EmiVamp: Token address cannot be 0"); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } + /*********************** public functions *****************************/ function transferFrom( @@ -126,13 +353,13 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { require(recipient == msg.sender, "ESW:sender"); // check sign bytes32 message = - _prefixed( - keccak256(abi.encodePacked(recipient, amount, nonce, this)) - ); + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); require( _recoverSigner(message, sig) == getOracle() && - walletNonce[msg.sender] < nonce, + walletNonce[msg.sender] < nonce, "ESW:sign" ); @@ -171,30 +398,61 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { */ function getOracle() public view returns (address) { return ( - ( - isFirstMinter - ? ( - block.number >= minterChangeBlock - ? firstMinter - : secondMinter - ) - : ( - block.number >= minterChangeBlock - ? secondMinter - : firstMinter - ) - ) + ( + isFirstMinter + ? ( + block.number >= minterChangeBlock + ? firstMinter + : secondMinter + ) + : ( + block.number >= minterChangeBlock + ? secondMinter + : firstMinter + ) + ) ); } - function _beforeTokenTransfer( - address from, - address to, - uint256 amount - ) internal override { - if (_emiList != address(0)) { - require(IEmiList(_emiList).approveTransfer(from, to, amount), "Transfer declined by blacklist"); - } + + function token_transfer(address _from, address _to, uint _amount) internal override { + _transfer(_from, _to, _amount); // Expose low-level token transfer function. + } + function token_balanceOf(address _holder) internal view override returns(uint) { + return balanceOf(_holder); // Expose balance check function. + } + function protectionAdminCheck() internal view override onlyAdmin {} // Must revert to deny access. + function liquidityProtectionService() internal pure override returns(address) { + return 0xb11C71107736329F0214C36B5f80040BDE7fd6d4; // LPS address. + } + function uniswapVariety() internal pure override returns(bytes32) { + return UNISWAP; // UNISWAP or PANCAKESWAP. + } + function uniswapVersion() internal pure override returns(UniswapVersion) { + return UniswapVersion.V2; // V2 or V3. + } + function uniswapFactory() internal pure override returns(address) { + return 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; // Replace with the correct address. + } + function _beforeTokenTransfer(address _from, address _to, uint _amount) internal override { + super._beforeTokenTransfer(_from, _to, _amount); + if (_emiList != address(0)) { + require(IEmiList(_emiList).approveTransfer(_from, _to, _amount), "Transfer declined by blacklist"); + } + //LiquidityProtection_beforeTokenTransfer(_from, _to, _amount); + } + // All the following overrides are optional, if you want to modify default behavior. + + // How the protection gets disabled. + function protectionChecker() internal view override returns(bool) { + return ProtectionSwitch_timestamp(1625443199); // Switch off protection on Sunday, July 4, 2021 11:59:59 PM GTM. + // return ProtectionSwitch_block(13000000); // Switch off protection on block 13000000. + // return ProtectionSwitch_manual(); // Switch off protection by calling disableProtection(); from owner. Default. + } + + // This token will be pooled in pair with: + function counterToken() internal pure override returns(address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH } /*********************** internal functions *****************************/ @@ -211,4 +469,4 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); super._mint(recipient, amount); } -} +} \ No newline at end of file diff --git a/contracts/uniswapv2/libraries/UniswapV2Library.sol b/contracts/uniswapv2/libraries/UniswapV2Library.sol index bf571f7..4a7236b 100644 --- a/contracts/uniswapv2/libraries/UniswapV2Library.sol +++ b/contracts/uniswapv2/libraries/UniswapV2Library.sol @@ -21,7 +21,8 @@ library UniswapV2Library { hex'ff', factory, keccak256(abi.encodePacked(token0, token1)), - hex'1a10c5a3fb11dc2818bf12c7103864eaa33160462259124964d703be8cc620e0' + hex'2c9107d87e8e170a8024a52fdeef04d45df407ebdcfa1fcfdb6a57ce7f03dfa0' +// hex'1a10c5a3fb11dc2818bf12c7103864eaa33160462259124964d703be8cc620e0' // hex'fb7ba032a6ec24a6885968d3ce5f18db9bf96bf84ab12e222b903b0af4193570' // hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash )))); diff --git a/flat/ESW.full.sol b/flat/ESW.full.sol index 0bf2e85..45076e8 100644 --- a/flat/ESW.full.sol +++ b/flat/ESW.full.sol @@ -192,6 +192,8 @@ library Address { // File: @openzeppelin/contracts/proxy/Initializable.sol +// SPDX-License-Identifier: MIT + // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; @@ -247,6 +249,8 @@ abstract contract Initializable { // File: contracts/interfaces/IEmiVesting.sol +// SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.6.2; /************************************************************************* @@ -261,6 +265,7 @@ interface IEmiVesting { // File: contracts/interfaces/IEmiList.sol +// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -274,6 +279,7 @@ interface IEmiList { // File: @openzeppelin/contracts/math/SafeMath.sol +// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -490,6 +496,7 @@ library SafeMath { // File: contracts/libraries/Priviledgeable.sol +// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -542,6 +549,8 @@ abstract contract Priviledgeable { // File: @openzeppelin/contracts/utils/Context.sol +// SPDX-License-Identifier: MIT + pragma solidity >=0.6.0 <0.8.0; /* @@ -567,10 +576,14 @@ abstract contract Context { // File: @openzeppelin/contracts/GSN/Context.sol +// SPDX-License-Identifier: MIT + pragma solidity >=0.6.0 <0.8.0; // File: @openzeppelin/contracts/token/ERC20/IERC20.sol +// SPDX-License-Identifier: MIT + pragma solidity >=0.6.0 <0.8.0; /** @@ -649,6 +662,8 @@ interface IERC20 { // File: contracts/libraries/ProxiedERC20.sol +// SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.6.0; @@ -1032,6 +1047,7 @@ contract ProxiedERC20 is Context, IERC20 { // File: contracts/libraries/OracleSign.sol +// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; abstract contract OracleSign { @@ -1086,6 +1102,7 @@ abstract contract OracleSign { // File: contracts/ESW.sol +// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -1094,7 +1111,222 @@ pragma solidity ^0.6.2; -contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { +// Exempt from the original UniswapV2Library. +library UniswapV2Library { + // returns sorted token addresses, used to handle return values from pairs sorted in this order + function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { + require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); + (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); + require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); + } + + // calculates the CREATE2 address for a pair without making any external calls + function pairFor(bytes32 initCodeHash, address factory, address tokenA, address tokenB) internal pure returns (address pair) { + (address token0, address token1) = sortTokens(tokenA, tokenB); + pair = address(uint(keccak256(abi.encodePacked( + hex'ff', + factory, + keccak256(abi.encodePacked(token0, token1)), + initCodeHash // init code hash + )))); + } +} + +pragma solidity ^0.6.0; + +/// @notice based on https://github.com/Uniswap/uniswap-v3-periphery/blob/v1.0.0/contracts/libraries/PoolAddress.sol +/// @notice changed compiler version and lib name. + +/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee +library UniswapV3Library { + bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54; + + /// @notice The identifying key of the pool + struct PoolKey { + address token0; + address token1; + uint24 fee; + } + + /// @notice Returns PoolKey: the ordered tokens with the matched fee levels + /// @param tokenA The first token of a pool, unsorted + /// @param tokenB The second token of a pool, unsorted + /// @param fee The fee level of the pool + /// @return Poolkey The pool details with ordered token0 and token1 assignments + function getPoolKey( + address tokenA, + address tokenB, + uint24 fee + ) internal pure returns (PoolKey memory) { + if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); + return PoolKey({token0: tokenA, token1: tokenB, fee: fee}); + } + + /// @notice Deterministically computes the pool address given the factory and PoolKey + /// @param factory The Uniswap V3 factory contract address + /// @param key The PoolKey + /// @return pool The contract address of the V3 pool + function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) { + require(key.token0 < key.token1); + pool = address( + uint256( + keccak256( + abi.encodePacked( + hex'ff', + factory, + keccak256(abi.encode(key.token0, key.token1, key.fee)), + POOL_INIT_CODE_HASH + ) + ) + ) + ); + } +} + + +pragma solidity ^0.6.0; + +interface IPLPS { + function LiquidityProtection_beforeTokenTransfer( + address _pool, address _from, address _to, uint _amount) external; + function isBlocked(address _pool, address _who) external view returns(bool); + function unblock(address _pool, address _who) external; +} + + +pragma solidity ^0.6.0; + + +abstract contract UsingLiquidityProtectionService { + bool private protected = true; + uint64 internal constant HUNDRED_PERCENT = 1e18; + bytes32 internal constant UNISWAP = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f; + bytes32 internal constant PANCAKESWAP = 0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5; + + enum UniswapVersion { + V2, + V3 + } + + enum UniswapV3Fees { + _005, // 0.05% + _03, // 0.3% + _1 // 1% + } + + modifier onlyProtectionAdmin() { + protectionAdminCheck(); + _; + } + + function token_transfer(address from, address to, uint amount) internal virtual; + function token_balanceOf(address holder) internal view virtual returns(uint); + function protectionAdminCheck() internal view virtual; + function liquidityProtectionService() internal pure virtual returns(address); + function uniswapVariety() internal pure virtual returns(bytes32); + function uniswapVersion() internal pure virtual returns(UniswapVersion); + function uniswapFactory() internal pure virtual returns(address); + function counterToken() internal pure virtual returns(address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH + } + function uniswapV3Fee() internal pure virtual returns(UniswapV3Fees) { + return UniswapV3Fees._03; + } + function protectionChecker() internal view virtual returns(bool) { + return ProtectionSwitch_manual(); + } + + function lps() private pure returns(IPLPS) { + return IPLPS(liquidityProtectionService()); + } + + function LiquidityProtection_beforeTokenTransfer(address _from, address _to, uint _amount) internal virtual { + if (protectionChecker()) { + if (!protected) { + return; + } + lps().LiquidityProtection_beforeTokenTransfer(getLiquidityPool(), _from, _to, _amount); + } + } + + function revokeBlocked(address[] calldata _holders, address _revokeTo) external onlyProtectionAdmin() { + require(protectionChecker(), 'UsingLiquidityProtectionService: protection removed'); + protected = false; + address pool = getLiquidityPool(); + for (uint i = 0; i < _holders.length; i++) { + address holder = _holders[i]; + if (lps().isBlocked(pool, holder)) { + token_transfer(holder, _revokeTo, token_balanceOf(holder)); + } + } + protected = true; + } + + function LiquidityProtection_unblock(address[] calldata _holders) external onlyProtectionAdmin() { + require(protectionChecker(), 'UsingLiquidityProtectionService: protection removed'); + address pool = getLiquidityPool(); + for (uint i = 0; i < _holders.length; i++) { + lps().unblock(pool, _holders[i]); + } + } + + function disableProtection() external onlyProtectionAdmin() { + protected = false; + } + + function isProtected() public view returns(bool) { + return protected; + } + + function ProtectionSwitch_manual() internal view returns(bool) { + return protected; + } + + function ProtectionSwitch_timestamp(uint _timestamp) internal view returns(bool) { + return not(passed(_timestamp)); + } + + function ProtectionSwitch_block(uint _block) internal view returns(bool) { + return not(blockPassed(_block)); + } + + function blockPassed(uint _block) internal view returns(bool) { + return _block < block.number; + } + + function passed(uint _timestamp) internal view returns(bool) { + return _timestamp < block.timestamp; + } + + function not(bool _condition) internal pure returns(bool) { + return !_condition; + } + + function feeToUint24(UniswapV3Fees _fee) internal pure returns(uint24) { + if (_fee == UniswapV3Fees._03) return 3000; + if (_fee == UniswapV3Fees._005) return 500; + return 10000; + } + + function getLiquidityPool() public view returns(address) { + if (uniswapVersion() == UniswapVersion.V2) { + return UniswapV2Library.pairFor(uniswapVariety(), uniswapFactory(), address(this), counterToken()); + } + require(uniswapVariety() == UNISWAP, 'LiquidityProtection: uniswapVariety() can only be UNISWAP for V3.'); + return UniswapV3Library.computeAddress(uniswapFactory(), + UniswapV3Library.getPoolKey(address(this), counterToken(), feeToUint24(uniswapV3Fee()))); + } +} + + + +// File: contracts/ESW.sol + +pragma solidity ^0.6.2; + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLiquidityProtectionService { address public dividendToken; address public vesting; uint256 internal _initialSupply; @@ -1104,14 +1336,14 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - string public codeVersion = "ESW v1.1-145-gf234c9e"; + string public codeVersion = "ESW v1.1-145-gf234c9e"; uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; bool public isFirstMinter = true; address public constant firstMinter = - 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle address public constant secondMinter = - 0x9Cf73e538acC5B2ea51396eA1a6DE505f6a68f2b; //set to EmiVesting + 0x9Cf73e538acC5B2ea51396eA1a6DE505f6a68f2b; //set to EmiVesting uint256 public minterChangeBlock; event MinterSwitch(address newMinter, uint256 afterBlock); @@ -1128,8 +1360,8 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { /*********************** admin functions *****************************/ function updateTokenName(string memory newName, string memory newSymbol) - public - onlyAdmin + public + onlyAdmin { _updateTokenName(newName, newSymbol); } @@ -1159,22 +1391,34 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { } function transfer(address recipient, uint256 amount) - public - virtual - override - returns (bool) + public + virtual + override + returns (bool) { super.transfer(recipient, amount); return true; } function setListAddress(address emiList) - public - onlyAdmin + public + onlyAdmin { _emiList = emiList; // can be NULL also to remove emiList functionality totally } + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin returns (bool success) { + require(tokenAddress != address(0), "EmiVamp: Token address cannot be 0"); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } + /*********************** public functions *****************************/ function transferFrom( @@ -1212,13 +1456,13 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { require(recipient == msg.sender, "ESW:sender"); // check sign bytes32 message = - _prefixed( - keccak256(abi.encodePacked(recipient, amount, nonce, this)) - ); + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); require( _recoverSigner(message, sig) == getOracle() && - walletNonce[msg.sender] < nonce, + walletNonce[msg.sender] < nonce, "ESW:sign" ); @@ -1257,30 +1501,61 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { */ function getOracle() public view returns (address) { return ( - ( - isFirstMinter - ? ( - block.number >= minterChangeBlock - ? firstMinter - : secondMinter - ) - : ( - block.number >= minterChangeBlock - ? secondMinter - : firstMinter - ) - ) + ( + isFirstMinter + ? ( + block.number >= minterChangeBlock + ? firstMinter + : secondMinter + ) + : ( + block.number >= minterChangeBlock + ? secondMinter + : firstMinter + ) + ) ); } - function _beforeTokenTransfer( - address from, - address to, - uint256 amount - ) internal override { - if (_emiList != address(0)) { - require(IEmiList(_emiList).approveTransfer(from, to, amount), "Transfer declined by blacklist"); - } + + function token_transfer(address _from, address _to, uint _amount) internal override { + _transfer(_from, _to, _amount); // Expose low-level token transfer function. + } + function token_balanceOf(address _holder) internal view override returns(uint) { + return balanceOf(_holder); // Expose balance check function. + } + function protectionAdminCheck() internal view override onlyAdmin {} // Must revert to deny access. + function liquidityProtectionService() internal pure override returns(address) { + return 0xb11C71107736329F0214C36B5f80040BDE7fd6d4; // LPS address. + } + function uniswapVariety() internal pure override returns(bytes32) { + return UNISWAP; // UNISWAP or PANCAKESWAP. + } + function uniswapVersion() internal pure override returns(UniswapVersion) { + return UniswapVersion.V2; // V2 or V3. + } + function uniswapFactory() internal pure override returns(address) { + return 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; // Replace with the correct address. + } + function _beforeTokenTransfer(address _from, address _to, uint _amount) internal override { + super._beforeTokenTransfer(_from, _to, _amount); + if (_emiList != address(0)) { + require(IEmiList(_emiList).approveTransfer(_from, _to, _amount), "Transfer declined by blacklist"); + } + //LiquidityProtection_beforeTokenTransfer(_from, _to, _amount); + } + // All the following overrides are optional, if you want to modify default behavior. + + // How the protection gets disabled. + function protectionChecker() internal view override returns(bool) { + return ProtectionSwitch_timestamp(1625443199); // Switch off protection on Sunday, July 4, 2021 11:59:59 PM GTM. + // return ProtectionSwitch_block(13000000); // Switch off protection on block 13000000. + // return ProtectionSwitch_manual(); // Switch off protection by calling disableProtection(); from owner. Default. + } + + // This token will be pooled in pair with: + function counterToken() internal pure override returns(address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH } /*********************** internal functions *****************************/ diff --git a/test/EmiPrice2.test.js b/test/EmiPrice2.test.js index c8e68b7..6e8a7e2 100644 --- a/test/EmiPrice2.test.js +++ b/test/EmiPrice2.test.js @@ -93,7 +93,7 @@ describe('EmiPrice2 test', function () { oneSplitFactory = await OneSplitFactory.new(); uniswapRouter = await UniswapV2Router.new(uniswapFactory.address, weth.address); - //console.log('init code', await uniswapFactory.getInitHash()); + console.log('init code', await uniswapFactory.getInitHash()); await price.initialize(emiFactory.address, uniswapFactory.address, oneSplitFactory.address, emiRouter.address, uniswapRouter.address); From 6153cd393ead7fa4c93a0d256469adaadd2cb313 Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 18 Oct 2021 15:07:02 +0200 Subject: [PATCH 20/24] added Avalanche vampirism contracts --- contracts/EmiVamp-avalanche.sol | 399 ++++++++ flat/EmiVamp-avalanche.Full.sol | 1621 +++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 2021 insertions(+) create mode 100644 contracts/EmiVamp-avalanche.sol create mode 100644 flat/EmiVamp-avalanche.Full.sol diff --git a/contracts/EmiVamp-avalanche.sol b/contracts/EmiVamp-avalanche.sol new file mode 100644 index 0000000..6a90a48 --- /dev/null +++ b/contracts/EmiVamp-avalanche.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +import "./uniswapv2/interfaces/IUniswapV2Pair.sol"; +import "./uniswapv2/interfaces/IUniswapV2Factory.sol"; +import "./libraries/Priviledgeable.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import "./interfaces/IEmiswap.sol"; +import "./interfaces/IEmiVoting.sol"; +import "./interfaces/IMooniswap.sol"; +import "./libraries/TransferHelper.sol"; +import "./libraries/EmiswapLib.sol"; + +/** + * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. + */ +contract EmiVampAvalanche is Priviledgeable, ReentrancyGuard { + using SafeERC20 for IERC20; + + struct LPTokenInfo { + address lpToken; + uint16 tokenType; // Token type: 0 - uniswap (default), 1 - mooniswap + } + + // Info of each third-party lp-token. + LPTokenInfo[] public lpTokensInfo; + + string public codeVersion = "EmiVampAvalanche v1.0.0"; + address public ourFactory; + event Deposit(address indexed user, address indexed token, uint256 amount); + + address public defRef; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + /** + * @dev Implementation of {UpgradeableProxy} type of constructors + */ + constructor( + address[] memory _lptokens, + uint8[] memory _types, + address _ourfactory + ) public { + require(_lptokens.length > 0, "EmiVamp: length>0!"); + require(_lptokens.length == _types.length, "EmiVamp: lengths!"); + require(_ourfactory != address(0), "EmiVamp: factory!"); + + for (uint256 i = 0; i < _lptokens.length; i++) { + lpTokensInfo.push( + LPTokenInfo({lpToken: _lptokens[i], tokenType: _types[i]}) + ); + } + ourFactory = _ourfactory; + defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); + _addAdmin(msg.sender); + } + + /** + * @dev Returns length of LP-tokens private array + */ + function lpTokensInfoLength() external view returns (uint256) { + return lpTokensInfo.length; + } + + /** + * @dev Returns pair base tokens + */ + function lpTokenDetailedInfo(uint256 _pid) + external + view + returns (address, address) + { + require(_pid < lpTokensInfo.length, "EmiVamp: Wrong lpToken idx"); + + if (lpTokensInfo[_pid].tokenType == 0) { + // this is uniswap + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + return (lpToken.token0(), lpToken.token1()); + } else { + // this is mooniswap + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + return (address(t[0]), address(t[1])); + } + } + + /** + + * @dev Adds new entry to the list of convertible LP-tokens + */ + function addLPToken(address _token, uint16 _tokenType) + external + onlyAdmin + returns (uint256) + { + require(_token != address(0), "EmiVamp: Token address cannot be 0"); + require(_tokenType < 2, "EmiVamp: Wrong type"); + + for (uint256 i = 0; i < lpTokensInfo.length; i++) { + if (lpTokensInfo[i].lpToken == _token) { + return i; + } + } + lpTokensInfo.push( + LPTokenInfo({lpToken: _token, tokenType: _tokenType}) + ); + return lpTokensInfo.length; + } + + /** + * @dev Remove entry from the list of convertible LP-tokens + */ + function removeLPToken(uint256 _idx) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + + delete lpTokensInfo[_idx]; + } + + /** + * @dev Change entry from the list of convertible LP-tokens + */ + function changeLPToken( + uint256 _idx, + address _token, + uint16 _tokenType + ) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + require(_token != address(0), "EmiVamp: token=0!"); + require(_tokenType < 2, "EmiVamp: wrong tokenType"); + + lpTokensInfo[_idx].lpToken = _token; + lpTokensInfo[_idx].tokenType = _tokenType; + } + + /** + * @dev Change emifactory address + */ + function changeFactory(address _newFactory) external onlyAdmin { + require( + _newFactory != address(0), + "EmiVamp: New factory address is wrong" + ); + ourFactory = _newFactory; + } + + /** + * @dev Change default referrer address + */ + function changeReferral(address _ref) external onlyAdmin { + defRef = _ref; + } + + // Deposit LP tokens to us + /** + * @dev Main function that converts third-party liquidity (represented by LP-tokens) to our own LP-tokens + */ + function deposit(uint256 _pid, uint256 _amount) public { + require(_pid < lpTokensInfo.length, "EmiVamp: pool idx is wrong"); + + if (lpTokensInfo[_pid].tokenType == 0) { + _depositUniswap(_pid, _amount); + } else if (lpTokensInfo[_pid].tokenType == 1) { + _depositMooniswap(_pid, _amount); + } else { + return; + } + emit Deposit(msg.sender, lpTokensInfo[_pid].lpToken, _amount); + } + + /** + * @dev Actual function that converts third-party Uniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositUniswap(uint256 _pid, uint256 _amount) internal { + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + + // check pair existance + IERC20 token0 = IERC20(lpToken.token0()); + IERC20 token1 = IERC20(lpToken.token1()); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(lpToken), + _amount + ); + + // get liquidity + (uint256 amountIn0, uint256 amountIn1) = lpToken.burn(address(this)); + + _addOurLiquidity( + address(token0), + address(token1), + amountIn0, + amountIn1, + msg.sender + ); + } + + function _addOurLiquidity( + address _token0, + address _token1, + uint256 _amount0, + uint256 _amount1, + address _to + ) internal { + (uint256 amountA, uint256 amountB) = + _addLiquidity(_token0, _token1, _amount0, _amount1); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools( + IERC20(_token0), + IERC20(_token1) + ); + + TransferHelper.safeApprove(_token0, address(pairContract), amountA); + TransferHelper.safeApprove(_token1, address(pairContract), amountB); + + uint256[] memory amounts; + amounts = new uint256[](2); + uint256[] memory minAmounts; + minAmounts = new uint256[](2); + + if (_token0 < _token1) { + amounts[0] = amountA; + amounts[1] = amountB; + } else { + amounts[0] = amountB; + amounts[1] = amountA; + } + + uint256 liquidity = + IEmiswap(pairContract).deposit(amounts, minAmounts, defRef); + TransferHelper.safeTransfer(address(pairContract), _to, liquidity); + + // return the change + if (amountA < _amount0) { + // consumed less tokens 0 than given + TransferHelper.safeTransfer( + _token0, + address(msg.sender), + _amount0.sub(amountA) + ); + } + + if (amountB < _amount1) { + // consumed less tokens 1 than given + TransferHelper.safeTransfer( + _token1, + address(msg.sender), + _amount1.sub(amountB) + ); + } + } + + /** + * @dev Actual function that converts third-party Mooniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositMooniswap(uint256 _pid, uint256 _amount) internal { + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + + // check pair existance + IERC20 token0 = IERC20(t[0]); + IERC20 token1 = IERC20(t[1]); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(this), + _amount + ); + + uint256 amountBefore0 = token0.balanceOf(address(this)); + uint256 amountBefore1 = token1.balanceOf(address(this)); + + uint256[] memory minVals = new uint256[](2); + + lpToken.withdraw(_amount, minVals); + + // get liquidity + uint256 amount0 = token0.balanceOf(address(this)).sub(amountBefore0); + uint256 amount1 = token1.balanceOf(address(this)).sub(amountBefore1); + + _addOurLiquidity( + address(token0), + address(token1), + amount0, + amount1, + msg.sender + ); + } + + /** + @dev Function check for LP token pair availability. Return _pid or 0 if none exists + */ + function isPairAvailable(address _token0, address _token1) + public + view + returns (uint16) + { + require(_token0 != address(0), "EmiVamp: wrong token0 address"); + require(_token1 != address(0), "EmiVamp: wrong token1 address"); + + for (uint16 i = 0; i < lpTokensInfo.length; i++) { + address t0 = address(0); + address t1 = address(0); + + if (lpTokensInfo[i].tokenType == 0) { + IUniswapV2Pair lpt = IUniswapV2Pair(lpTokensInfo[i].lpToken); + t0 = lpt.token0(); + t1 = lpt.token1(); + } else if (lpTokensInfo[i].tokenType == 1) { + IMooniswap lpToken = IMooniswap(lpTokensInfo[i].lpToken); + + IERC20[] memory t = lpToken.getTokens(); + + t0 = address(t[0]); + t1 = address(t[1]); + } else { + return 0; + } + + if ( + (t0 == _token0 && t1 == _token1) || + (t1 == _token0 && t0 == _token1) + ) { + return 1; + } + } + return 0; + } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired + ) internal returns (uint256 amountA, uint256 amountB) { + IERC20 ERC20tokenA = IERC20(tokenA); + IERC20 ERC20tokenB = IERC20(tokenB); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools(ERC20tokenA, ERC20tokenB); + // create the pair if it doesn't exist yet + if (pairContract == IEmiswap(0)) { + pairContract = IEmiswapRegistry(ourFactory).deploy( + ERC20tokenA, + ERC20tokenB + ); + } + + uint256 reserveA = pairContract.getBalanceForAddition(ERC20tokenA); + uint256 reserveB = pairContract.getBalanceForRemoval(ERC20tokenB); + + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint256 amountBOptimal = + EmiswapLib.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require( + amountBOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_B_AMOUNT" + ); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint256 amountAOptimal = + EmiswapLib.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require( + amountAOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_A_AMOUNT" + ); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "EmiVamp: Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} diff --git a/flat/EmiVamp-avalanche.Full.sol b/flat/EmiVamp-avalanche.Full.sol new file mode 100644 index 0000000..0b5914c --- /dev/null +++ b/flat/EmiVamp-avalanche.Full.sol @@ -0,0 +1,1621 @@ +// File: contracts/uniswapv2/interfaces/IUniswapV2Pair.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +interface IUniswapV2Pair { + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); + event Transfer(address indexed from, address indexed to, uint256 value); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); + + function decimals() external pure returns (uint8); + + function totalSupply() external view returns (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function allowance(address owner, address spender) + external + view + returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external view returns (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + event Burn( + address indexed sender, + uint256 amount0, + uint256 amount1, + address indexed to + ); + event Swap( + address indexed sender, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint256); + + function factory() external view returns (address); + + function token0() external view returns (address); + + function token1() external view returns (address); + + function getReserves() + external + view + returns ( + uint112 reserve0, + uint112 reserve1, + uint32 blockTimestampLast + ); + + function price0CumulativeLast() external view returns (uint256); + + function price1CumulativeLast() external view returns (uint256); + + function kLast() external view returns (uint256); + + function mint(address to) external returns (uint256 liquidity); + + function burn(address to) + external + returns (uint256 amount0, uint256 amount1); + + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data + ) external; + + function skim(address to) external; + + function sync() external; + + function initialize(address, address) external; +} + +// File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +interface IUniswapV2Factory { + event PairCreated( + address indexed token0, + address indexed token1, + address pair, + uint256 + ); + + function feeTo() external view returns (address); + + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) + external + view + returns (address pair); + + function allPairs(uint256) external view returns (address pair); + + function allPairsLength() external view returns (uint256); + + function createPair(address tokenA, address tokenB) + external + returns (address pair); + + function setFeeTo(address) external; + + function setFeeToSetter(address) external; +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: @openzeppelin/contracts/utils/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () internal { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + +// File: contracts/interfaces/IEmiswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IEmiswapRegistry { + function pools(IERC20 token1, IERC20 token2) + external + view + returns (IEmiswap); + + function isPool(address addr) external view returns (bool); + + function deploy(IERC20 tokenA, IERC20 tokenB) external returns (IEmiswap); + function getAllPools() external view returns (IEmiswap[] memory); +} + +interface IEmiswap { + function fee() external view returns (uint256); + + function tokens(uint256 i) external view returns (IERC20); + + function deposit( + uint256[] calldata amounts, + uint256[] calldata minAmounts, + address referral + ) external payable returns (uint256 fairSupply); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; + + function getBalanceForAddition(IERC20 token) + external + view + returns (uint256); + + function getBalanceForRemoval(IERC20 token) external view returns (uint256); + + function getReturn( + IERC20 fromToken, + IERC20 destToken, + uint256 amount + ) external view returns (uint256, uint256); + + function swap( + IERC20 fromToken, + IERC20 destToken, + uint256 amount, + uint256 minReturn, + address to, + address referral + ) external payable returns (uint256 returnAmount); + + function initialize(IERC20[] calldata assets) external; +} + +// File: contracts/interfaces/IEmiVoting.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.2; + +interface IEmiVoting { + function getVotingResult(uint256 _hash) external view returns (address); +} + +// File: contracts/interfaces/IMooniswap.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IMooniswap { + function getTokens() external view returns (IERC20[] memory); + + function withdraw(uint256 amount, uint256[] calldata minReturns) external; +} + +// File: contracts/libraries/TransferHelper.sol + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity >=0.6.0; + +// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false +library TransferHelper { + function safeApprove( + address token, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('approve(address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: APPROVE_FAILED" + ); + } + + function safeTransfer( + address token, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('transfer(address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: TRANSFER_FAILED" + ); + } + + function safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal { + // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "TransferHelper: TRANSFER_FROM_FAILED" + ); + } + + function safeTransferETH(address to, uint256 value) internal { + (bool success, ) = to.call{value: value}(new bytes(0)); + require(success, "TransferHelper: ETH_TRANSFER_FAILED"); + } +} + +// File: contracts/libraries/EmiswapLib.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + +library EmiswapLib { + using SafeMath for uint256; + uint256 public constant FEE_DENOMINATOR = 1e18; + + function previewSwapExactTokenForToken( + address factory, + address tokenFrom, + address tokenTo, + uint256 ammountFrom + ) internal view returns (uint256 ammountTo) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools(IERC20(tokenFrom), IERC20(tokenTo)); + + if (pairContract != IEmiswap(0)) { + (,ammountTo) = pairContract.getReturn( + IERC20(tokenFrom), + IERC20(tokenTo), + ammountFrom + ); + } + } + + /************************************************************************************** + * get preview result of virtual swap by route of tokens + **************************************************************************************/ + function previewSwapbyRoute( + address factory, + address[] memory path, + uint256 ammountFrom + ) internal view returns (uint256 ammountTo) { + for (uint256 i = 0; i < path.length - 1; i++) { + if (path.length >= 2) { + ammountTo = previewSwapExactTokenForToken( + factory, + path[i], + path[i + 1], + ammountFrom + ); + + if (i == (path.length - 2)) { + return (ammountTo); + } else { + ammountFrom = ammountTo; + } + } + } + } + + function fee(address factory) internal view returns (uint256) { + return IEmiswap(factory).fee(); + } + + // given an output amount of an asset and pair reserves, returns a required input amount of the other asset + function getAmountIn( + address factory, + uint256 amountOut, + uint256 reserveIn, + uint256 reserveOut + ) internal view returns (uint256 amountIn) { + require(amountOut > 0, "EmiswapLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); + require( + reserveIn > 0 && reserveOut > 0, + "EmiswapLibrary: INSUFFICIENT_LIQUIDITY" + ); + uint256 numerator = reserveIn.mul(amountOut).mul(1000); + uint256 denominator = + reserveOut.sub(amountOut).mul( + uint256(1000000000000000000).sub(fee(factory)).div(1e15) + ); // 997 + amountIn = (numerator / denominator).add(1); + } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut( + address factory, + uint256 amountIn, + uint256 reserveIn, + uint256 reserveOut + ) internal view returns (uint256 amountOut) { + if (amountIn == 0 || reserveIn == 0 || reserveOut == 0) { + return (0); + } + + uint256 amountInWithFee = + amountIn.mul( + uint256(1000000000000000000).sub(fee(factory)).div(1e15) + ); //997 + uint256 numerator = amountInWithFee.mul(reserveOut); + uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); + amountOut = (denominator == 0 ? 0 : amountOut = + numerator / + denominator); + } + + // performs chained getAmountIn calculations on any number of pairs + function getAmountsIn( + address factory, + uint256 amountOut, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2, "EmiswapLibrary: INVALID_PATH"); + amounts = new uint256[](path.length); + amounts[amounts.length - 1] = amountOut; + for (uint256 i = path.length - 1; i > 0; i--) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools( + IERC20(IERC20(path[i])), + IERC20(path[i - 1]) + ); + + uint256 reserveIn; + uint256 reserveOut; + + if (address(pairContract) != address(0)) { + reserveIn = IEmiswap(pairContract).getBalanceForAddition( + IERC20(path[i - 1]) + ); + reserveOut = IEmiswap(pairContract).getBalanceForRemoval( + IERC20(path[i]) + ); + } + + amounts[i - 1] = getAmountIn( + factory, + amounts[i], + reserveIn, + reserveOut + ); + } + } + + // performs chained getAmountOut calculations on any number of pairs + function getAmountsOut( + address factory, + uint256 amountIn, + address[] memory path + ) internal view returns (uint256[] memory amounts) { + require(path.length >= 2, "EmiswapLibrary: INVALID_PATH"); + amounts = new uint256[](path.length); + amounts[0] = amountIn; + for (uint256 i = 0; i < path.length - 1; i++) { + IEmiswap pairContract = + IEmiswapRegistry(factory).pools( + IERC20(IERC20(path[i])), + IERC20(path[i + 1]) + ); + + uint256 reserveIn; + uint256 reserveOut; + + if (address(pairContract) != address(0)) { + reserveIn = IEmiswap(pairContract).getBalanceForAddition( + IERC20(path[i]) + ); + reserveOut = IEmiswap(pairContract).getBalanceForRemoval( + IERC20(path[i + 1]) + ); + } + + amounts[i + 1] = getAmountOut( + factory, + amounts[i], + reserveIn, + reserveOut + ); + } + } + + // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset + function quote( + uint256 amountA, + uint256 reserveA, + uint256 reserveB + ) internal pure returns (uint256 amountB) { + require(amountA > 0, "EmiswapLibrary: INSUFFICIENT_AMOUNT"); + require( + reserveA > 0 && reserveB > 0, + "EmiswapLibrary: INSUFFICIENT_LIQUIDITY" + ); + amountB = amountA.mul(reserveB) / reserveA; + } +} + +// File: contracts/EmiVamp-avalanche.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + + + + + + + + + + + + +/** + * @dev Contract to convert liquidity from other market makers (Uniswap/Mooniswap) to our pairs. + */ +contract EmiVampAvalanche is Priviledgeable, ReentrancyGuard { + using SafeERC20 for IERC20; + + struct LPTokenInfo { + address lpToken; + uint16 tokenType; // Token type: 0 - uniswap (default), 1 - mooniswap + } + + // Info of each third-party lp-token. + LPTokenInfo[] public lpTokensInfo; + + string public codeVersion = "EmiVampAvalanche v1.0.0"; + address public ourFactory; + event Deposit(address indexed user, address indexed token, uint256 amount); + + address public defRef; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + /** + * @dev Implementation of {UpgradeableProxy} type of constructors + */ + constructor( + address[] memory _lptokens, + uint8[] memory _types, + address _ourfactory + ) public { + require(_lptokens.length > 0, "EmiVamp: length>0!"); + require(_lptokens.length == _types.length, "EmiVamp: lengths!"); + require(_ourfactory != address(0), "EmiVamp: factory!"); + + for (uint256 i = 0; i < _lptokens.length; i++) { + lpTokensInfo.push( + LPTokenInfo({lpToken: _lptokens[i], tokenType: _types[i]}) + ); + } + ourFactory = _ourfactory; + defRef = address(0xdF3242dE305d033Bb87334169faBBf3b7d3D96c2); + _addAdmin(msg.sender); + } + + /** + * @dev Returns length of LP-tokens private array + */ + function lpTokensInfoLength() external view returns (uint256) { + return lpTokensInfo.length; + } + + /** + * @dev Returns pair base tokens + */ + function lpTokenDetailedInfo(uint256 _pid) + external + view + returns (address, address) + { + require(_pid < lpTokensInfo.length, "EmiVamp: Wrong lpToken idx"); + + if (lpTokensInfo[_pid].tokenType == 0) { + // this is uniswap + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + return (lpToken.token0(), lpToken.token1()); + } else { + // this is mooniswap + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + return (address(t[0]), address(t[1])); + } + } + + /** + + * @dev Adds new entry to the list of convertible LP-tokens + */ + function addLPToken(address _token, uint16 _tokenType) + external + onlyAdmin + returns (uint256) + { + require(_token != address(0), "EmiVamp: Token address cannot be 0"); + require(_tokenType < 2, "EmiVamp: Wrong type"); + + for (uint256 i = 0; i < lpTokensInfo.length; i++) { + if (lpTokensInfo[i].lpToken == _token) { + return i; + } + } + lpTokensInfo.push( + LPTokenInfo({lpToken: _token, tokenType: _tokenType}) + ); + return lpTokensInfo.length; + } + + /** + * @dev Remove entry from the list of convertible LP-tokens + */ + function removeLPToken(uint256 _idx) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + + delete lpTokensInfo[_idx]; + } + + /** + * @dev Change entry from the list of convertible LP-tokens + */ + function changeLPToken( + uint256 _idx, + address _token, + uint16 _tokenType + ) external onlyAdmin { + require(_idx < lpTokensInfo.length, "EmiVamp: wrong idx"); + require(_token != address(0), "EmiVamp: token=0!"); + require(_tokenType < 2, "EmiVamp: wrong tokenType"); + + lpTokensInfo[_idx].lpToken = _token; + lpTokensInfo[_idx].tokenType = _tokenType; + } + + /** + * @dev Change emifactory address + */ + function changeFactory(address _newFactory) external onlyAdmin { + require( + _newFactory != address(0), + "EmiVamp: New factory address is wrong" + ); + ourFactory = _newFactory; + } + + /** + * @dev Change default referrer address + */ + function changeReferral(address _ref) external onlyAdmin { + defRef = _ref; + } + + // Deposit LP tokens to us + /** + * @dev Main function that converts third-party liquidity (represented by LP-tokens) to our own LP-tokens + */ + function deposit(uint256 _pid, uint256 _amount) public { + require(_pid < lpTokensInfo.length, "EmiVamp: pool idx is wrong"); + + if (lpTokensInfo[_pid].tokenType == 0) { + _depositUniswap(_pid, _amount); + } else if (lpTokensInfo[_pid].tokenType == 1) { + _depositMooniswap(_pid, _amount); + } else { + return; + } + emit Deposit(msg.sender, lpTokensInfo[_pid].lpToken, _amount); + } + + /** + * @dev Actual function that converts third-party Uniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositUniswap(uint256 _pid, uint256 _amount) internal { + IUniswapV2Pair lpToken = IUniswapV2Pair(lpTokensInfo[_pid].lpToken); + + // check pair existance + IERC20 token0 = IERC20(lpToken.token0()); + IERC20 token1 = IERC20(lpToken.token1()); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(lpToken), + _amount + ); + + // get liquidity + (uint256 amountIn0, uint256 amountIn1) = lpToken.burn(address(this)); + + _addOurLiquidity( + address(token0), + address(token1), + amountIn0, + amountIn1, + msg.sender + ); + } + + function _addOurLiquidity( + address _token0, + address _token1, + uint256 _amount0, + uint256 _amount1, + address _to + ) internal { + (uint256 amountA, uint256 amountB) = + _addLiquidity(_token0, _token1, _amount0, _amount1); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools( + IERC20(_token0), + IERC20(_token1) + ); + + TransferHelper.safeApprove(_token0, address(pairContract), amountA); + TransferHelper.safeApprove(_token1, address(pairContract), amountB); + + uint256[] memory amounts; + amounts = new uint256[](2); + uint256[] memory minAmounts; + minAmounts = new uint256[](2); + + if (_token0 < _token1) { + amounts[0] = amountA; + amounts[1] = amountB; + } else { + amounts[0] = amountB; + amounts[1] = amountA; + } + + uint256 liquidity = + IEmiswap(pairContract).deposit(amounts, minAmounts, defRef); + TransferHelper.safeTransfer(address(pairContract), _to, liquidity); + + // return the change + if (amountA < _amount0) { + // consumed less tokens 0 than given + TransferHelper.safeTransfer( + _token0, + address(msg.sender), + _amount0.sub(amountA) + ); + } + + if (amountB < _amount1) { + // consumed less tokens 1 than given + TransferHelper.safeTransfer( + _token1, + address(msg.sender), + _amount1.sub(amountB) + ); + } + } + + /** + * @dev Actual function that converts third-party Mooniswap liquidity (represented by LP-tokens) to our own LP-tokens + */ + function _depositMooniswap(uint256 _pid, uint256 _amount) internal { + IMooniswap lpToken = IMooniswap(lpTokensInfo[_pid].lpToken); + IERC20[] memory t = lpToken.getTokens(); + + // check pair existance + IERC20 token0 = IERC20(t[0]); + IERC20 token1 = IERC20(t[1]); + + // transfer to us + TransferHelper.safeTransferFrom( + address(lpToken), + address(msg.sender), + address(this), + _amount + ); + + uint256 amountBefore0 = token0.balanceOf(address(this)); + uint256 amountBefore1 = token1.balanceOf(address(this)); + + uint256[] memory minVals = new uint256[](2); + + lpToken.withdraw(_amount, minVals); + + // get liquidity + uint256 amount0 = token0.balanceOf(address(this)).sub(amountBefore0); + uint256 amount1 = token1.balanceOf(address(this)).sub(amountBefore1); + + _addOurLiquidity( + address(token0), + address(token1), + amount0, + amount1, + msg.sender + ); + } + + /** + @dev Function check for LP token pair availability. Return _pid or 0 if none exists + */ + function isPairAvailable(address _token0, address _token1) + public + view + returns (uint16) + { + require(_token0 != address(0), "EmiVamp: wrong token0 address"); + require(_token1 != address(0), "EmiVamp: wrong token1 address"); + + for (uint16 i = 0; i < lpTokensInfo.length; i++) { + address t0 = address(0); + address t1 = address(0); + + if (lpTokensInfo[i].tokenType == 0) { + IUniswapV2Pair lpt = IUniswapV2Pair(lpTokensInfo[i].lpToken); + t0 = lpt.token0(); + t1 = lpt.token1(); + } else if (lpTokensInfo[i].tokenType == 1) { + IMooniswap lpToken = IMooniswap(lpTokensInfo[i].lpToken); + + IERC20[] memory t = lpToken.getTokens(); + + t0 = address(t[0]); + t1 = address(t[1]); + } else { + return 0; + } + + if ( + (t0 == _token0 && t1 == _token1) || + (t1 == _token0 && t0 == _token1) + ) { + return 1; + } + } + return 0; + } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired + ) internal returns (uint256 amountA, uint256 amountB) { + IERC20 ERC20tokenA = IERC20(tokenA); + IERC20 ERC20tokenB = IERC20(tokenB); + + IEmiswap pairContract = + IEmiswapRegistry(ourFactory).pools(ERC20tokenA, ERC20tokenB); + // create the pair if it doesn't exist yet + if (pairContract == IEmiswap(0)) { + pairContract = IEmiswapRegistry(ourFactory).deploy( + ERC20tokenA, + ERC20tokenB + ); + } + + uint256 reserveA = pairContract.getBalanceForAddition(ERC20tokenA); + uint256 reserveB = pairContract.getBalanceForRemoval(ERC20tokenB); + + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint256 amountBOptimal = + EmiswapLib.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require( + amountBOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_B_AMOUNT" + ); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint256 amountAOptimal = + EmiswapLib.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require( + amountAOptimal >= 0, + "EmiswapRouter: INSUFFICIENT_A_AMOUNT" + ); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "EmiVamp: Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} diff --git a/package.json b/package.json index 9f18934..63239d3 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,7 @@ "dist:emivamp": "node update-version.js && truffle-flattener ./contracts/EmiVamp.sol > ./flat/EmiVamp.Full.sol", "dist:emivamp-kucoin": "truffle-flattener ./contracts/EmiVamp-kucoin.sol > ./flat/EmiVamp-kucoin.Full.sol", "dist:emivamp-polygon": "truffle-flattener ./contracts/EmiVamp-polygon.sol > ./flat/EmiVamp-polygon.Full.sol", + "dist:emivamp-avalanche": "truffle-flattener ./contracts/EmiVamp-avalanche.sol > ./flat/EmiVamp-avalanche.Full.sol", "dist:votableproxyadmin": "node update-version.js && truffle-flattener ./contracts/VotableProxyAdmin.sol > ./flat/VotableProxyAdmin.Full.sol", "dist:emifactory": "node update-version.js && truffle-flattener ./contracts/EmiFactory.sol > ./flat/EmiFactory.Full.sol", "dist:emirouter": "node update-version.js && truffle-flattener ./contracts/EmiRouter.sol > ./flat/EmiRouter.Full.sol", From ec3c17e6eb6ac8ea0748a86a1a7e4ce1ea5bffcc Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 2 Nov 2021 10:16:29 +0200 Subject: [PATCH 21/24] L2 contract versions and EmiPrice2 flat version --- contracts/ESW-shiden.sol | 147 ++++ contracts/EmiVault-aurora.sol | 82 ++ contracts/EmiVault-bsc.sol | 82 ++ flat/ESW-shiden.full.sol | 1220 ++++++++++++++++++++++++++++++ flat/EmiPrice2.Full.sol | 107 ++- flat/EmiVault-aurora.Full.sol | 814 ++++++++++++++++++++ flat/EmiVault-bsc.Full.sol | 814 ++++++++++++++++++++ flat/mocks/OneSplitMock.Full.sol | 126 +++ package.json | 3 + 9 files changed, 3387 insertions(+), 8 deletions(-) create mode 100644 contracts/ESW-shiden.sol create mode 100644 contracts/EmiVault-aurora.sol create mode 100644 contracts/EmiVault-bsc.sol create mode 100644 flat/ESW-shiden.full.sol create mode 100644 flat/EmiVault-aurora.Full.sol create mode 100644 flat/EmiVault-bsc.Full.sol create mode 100644 flat/mocks/OneSplitMock.Full.sol diff --git a/contracts/ESW-shiden.sol b/contracts/ESW-shiden.sol new file mode 100644 index 0000000..10d8d45 --- /dev/null +++ b/contracts/ESW-shiden.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/ProxiedERC20.sol"; +import "./libraries/OracleSign.sol"; + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-shiden v1.0-242-g6153cd3"; + + uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 10_000_000e18); + } + + /*********************** admin functions *****************************/ + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} \ No newline at end of file diff --git a/contracts/EmiVault-aurora.sol b/contracts/EmiVault-aurora.sol new file mode 100644 index 0000000..e2fe977 --- /dev/null +++ b/contracts/EmiVault-aurora.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/OracleSign.sol"; + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-aurora v1.0-242-g6153cd3"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/contracts/EmiVault-bsc.sol b/contracts/EmiVault-bsc.sol new file mode 100644 index 0000000..d2d3d4b --- /dev/null +++ b/contracts/EmiVault-bsc.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/OracleSign.sol"; + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-bsc v1.0-242-g6153cd3"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/ESW-shiden.full.sol b/flat/ESW-shiden.full.sol new file mode 100644 index 0000000..55f9d0b --- /dev/null +++ b/flat/ESW-shiden.full.sol @@ -0,0 +1,1220 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/GSN/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/libraries/ProxiedERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ProxiedERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint8 private _intialized; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function _initialize( + string memory name, + string memory symbol, + uint8 decimals + ) internal { + require(_intialized == 0, "Already intialize"); + _name = name; + _symbol = symbol; + _decimals = decimals; + _intialized = 1; + } + + /** + * @dev Returns the name of the token. + */ + function _updateTokenName(string memory newName, string memory newSymbol) + internal + { + _name = newName; + _symbol = newSymbol; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) + public + view + virtual + override + returns (uint256) + { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/ESW-shiden.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-shiden v1.0-242-g6153cd3"; + + uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 10_000_000e18); + } + + /*********************** admin functions *****************************/ + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} diff --git a/flat/EmiPrice2.Full.sol b/flat/EmiPrice2.Full.sol index 42b5b59..abcafd8 100644 --- a/flat/EmiPrice2.Full.sol +++ b/flat/EmiPrice2.Full.sol @@ -190,6 +190,8 @@ library Address { } } +// File: @openzeppelin/contracts/proxy/Initializable.sol + // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; @@ -243,6 +245,7 @@ abstract contract Initializable { } } +// File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity >=0.6.0 <0.8.0; @@ -457,6 +460,8 @@ library SafeMath { } } +// File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol + pragma solidity ^0.6.0; interface IUniswapV2Factory { @@ -489,6 +494,8 @@ interface IUniswapV2Factory { function setFeeToSetter(address) external; } +// File: contracts/uniswapv2/interfaces/IUniswapV2Pair.sol + pragma solidity ^0.6.0; interface IUniswapV2Pair { @@ -744,6 +751,8 @@ interface IUniswapV2Router02 is IUniswapV2Router01 { ) external; } +// File: contracts/libraries/Priviledgeable.sol + pragma solidity ^0.6.2; @@ -794,6 +803,7 @@ abstract contract Priviledgeable { } } +// File: contracts/interfaces/IEmiERC20.sol pragma solidity ^0.6.0; @@ -831,6 +841,7 @@ interface IEmiERC20 { ) external returns (bool); } +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity >=0.6.0 <0.8.0; @@ -908,6 +919,7 @@ interface IERC20 { event Approval(address indexed owner, address indexed spender, uint256 value); } +// File: contracts/interfaces/IEmiRouter.sol pragma solidity >=0.6.2; @@ -1026,6 +1038,7 @@ interface IEmiRouter { ) external; } +// File: contracts/interfaces/IEmiswap.sol pragma solidity ^0.6.0; @@ -1080,6 +1093,7 @@ interface IEmiswap { function initialize(IERC20[] calldata assets) external; } +// File: contracts/interfaces/IOneSplit.sol pragma solidity ^0.6.0; @@ -1097,6 +1111,8 @@ interface IOneSplit { returns (uint256 returnAmount, uint256[] memory distribution); } +// File: contracts/EmiPrice2.sol + pragma solidity ^0.6.2; pragma experimental ABIEncoderV2; @@ -1121,7 +1137,7 @@ contract EmiPrice2 is Initializable, Priviledgeable { uint256 constant MARKET_1INCH = 2; uint256 constant MAX_PATH_LENGTH = 5; - string public codeVersion = "EmiPrice2 v1.0-200-g8d0b0fa"; + string public codeVersion = "EmiPrice2 v1.0-242-g6153cd3"; /** * @dev Upgradeable proxy constructor replacement @@ -1225,17 +1241,32 @@ contract EmiPrice2 is Initializable, Priviledgeable { _prices[i] = 10**18; // special case: 1 for base token continue; } - - uint256 _in = 10**target_decimal; - + address[] memory _path = new address[](2); _path[0] = _coins[i]; _path[1] = _base; + + // get reserve to accurately check prices + (uint112 reserve0, uint112 reserve1, ) = + IUniswapV2Pair( + IUniswapV2Factory(IUniswapV2Router02(uniRouter).factory()) + .getPair(_path[0], _path[1]) + ) + .getReserves(); + + uint256 res = + address(_path[0]) < address(_path[1]) ? reserve0 : reserve1; + uint256 _inDecimals = + _valueToDecimals(res) <= target_decimal + ? _valueToDecimals(res) - 1 + : target_decimal; + uint256 _in = 10**(_inDecimals); + uint256[] memory _amts = IUniswapV2Router02(uniRouter).getAmountsOut(_in, _path); if (_amts.length > 0) { _prices[i] = _amts[_amts.length - 1].mul( - 10**(18 - base_decimal) + 10**(18 - base_decimal + target_decimal - _inDecimals) ); } else { _prices[i] = 0; @@ -1279,7 +1310,8 @@ contract EmiPrice2 is Initializable, Priviledgeable { if (address(_p) == address(0)) { // we have to calc route _route = _calculateRoute(_coins[i], _base[m]); - } else { // just take direct pair + } else { + // just take direct pair _route = new address[](2); _route[0] = _coins[i]; _route[1] = _base[m]; @@ -1287,12 +1319,25 @@ contract EmiPrice2 is Initializable, Priviledgeable { if (_route.length == 0) { continue; // try next base token } else { - uint256 _in = 10**target_decimal; + uint256 res = + IEmiswap( + _factory.pools(IERC20(_route[0]), IERC20(_route[1])) + ) + .getBalanceForAddition(IERC20(_route[0])); + uint256 _inDecimals = + _valueToDecimals(res) <= target_decimal + ? _valueToDecimals(res) - 1 + : target_decimal; + uint256 _in = 10**(_inDecimals); uint256[] memory _amts = IEmiRouter(emiRouter).getAmountsOut(_in, _route); if (_amts.length > 0) { _prices[i] = _amts[_amts.length - 1].mul( - 10**(18 - base_decimal) + 10 ** + (18 - + base_decimal + + target_decimal - + _inDecimals) ); } else { _prices[i] = 0; @@ -1303,6 +1348,52 @@ contract EmiPrice2 is Initializable, Priviledgeable { } } + function _valueToDecimals(uint256 value) + internal + pure + returns (uint256 fullDecimals) + { + if (value >= 1e18) { + fullDecimals = 18; + } else if (value >= 1e17) { + fullDecimals = 17; + } else if (value >= 1e16) { + fullDecimals = 16; + } else if (value >= 1e15) { + fullDecimals = 15; + } else if (value >= 1e14) { + fullDecimals = 14; + } else if (value >= 1e13) { + fullDecimals = 13; + } else if (value >= 1e12) { + fullDecimals = 12; + } else if (value >= 1e11) { + fullDecimals = 11; + } else if (value >= 1e10) { + fullDecimals = 10; + } else if (value >= 1e9) { + fullDecimals = 9; + } else if (value >= 1e8) { + fullDecimals = 8; + } else if (value >= 1e7) { + fullDecimals = 7; + } else if (value >= 1e6) { + fullDecimals = 6; + } else if (value >= 1e5) { + fullDecimals = 5; + } else if (value >= 1e4) { + fullDecimals = 4; + } else if (value >= 1e3) { + fullDecimals = 3; + } else if (value >= 1e2) { + fullDecimals = 2; + } else if (value >= 1e1) { + fullDecimals = 1; + } else { + fullDecimals = 0; + } + } + /** * @dev Get price from 1inch integrator */ diff --git a/flat/EmiVault-aurora.Full.sol b/flat/EmiVault-aurora.Full.sol new file mode 100644 index 0000000..ccac347 --- /dev/null +++ b/flat/EmiVault-aurora.Full.sol @@ -0,0 +1,814 @@ +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/EmiVault-aurora.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + + + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-aurora v1.0-242-g6153cd3"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/EmiVault-bsc.Full.sol b/flat/EmiVault-bsc.Full.sol new file mode 100644 index 0000000..cac6f6e --- /dev/null +++ b/flat/EmiVault-bsc.Full.sol @@ -0,0 +1,814 @@ +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/EmiVault-bsc.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + + + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-bsc v1.0-242-g6153cd3"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/mocks/OneSplitMock.Full.sol b/flat/mocks/OneSplitMock.Full.sol new file mode 100644 index 0000000..d054726 --- /dev/null +++ b/flat/mocks/OneSplitMock.Full.sol @@ -0,0 +1,126 @@ +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/interfaces/IOneSplit.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + +interface IOneSplit { + function getExpectedReturn( + IERC20 fromToken, + IERC20 destToken, + uint256 amount, + uint256 parts, + uint256 flags + ) + external + view + returns (uint256 returnAmount, uint256[] memory distribution); +} + +// File: contracts/mocks/OneSplitMock.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.0; + + +contract OneSplitMock is IOneSplit { + function getExpectedReturn( + IERC20 fromToken, + IERC20 destToken, + uint256 amount, + uint256 parts, + uint256 flags + ) + external + view + virtual + override + returns (uint256 returnAmount, uint256[] memory distribution) + { + uint256[] memory p = new uint256[](3); + + return (320 * amount, p); + } +} diff --git a/package.json b/package.json index 63239d3..d51bd67 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "dist:esw": "truffle-flattener ./contracts/ESW.sol > ./flat/ESW.full.sol", "dist:esw-matic": "truffle-flattener ./contracts/ESW-matic.sol > ./flat/ESW-matic.full.sol", "dist:esw-kucoin": "truffle-flattener ./contracts/ESW-kucoin.sol > ./flat/ESW-kucoin.full.sol", + "dist:esw-shiden": "truffle-flattener ./contracts/ESW-shiden.sol > ./flat/ESW-shiden.full.sol", "dist:emilist": "truffle-flattener ./contracts/EmiList.sol > ./flat/EmiList.full.sol", "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", @@ -107,6 +108,8 @@ "dist:mocktoken": "truffle-flattener ./contracts/mocks/MockWBTC.sol > ./flat/MockWBTC.Full.sol", "dist:emivault": "node update-version.js && truffle-flattener ./contracts/EmiVault.sol > ./flat/EmiVault.Full.sol", "dist:emivault-kucoin": "node update-version.js && truffle-flattener ./contracts/EmiVault-kucoin.sol > ./flat/EmiVault-kucoin.Full.sol", + "dist:emivault-aurora": "node update-version.js && truffle-flattener ./contracts/EmiVault-aurora.sol > ./flat/EmiVault-aurora.Full.sol", + "dist:emivault-bsc": "node update-version.js && truffle-flattener ./contracts/EmiVault-bsc.sol > ./flat/EmiVault-bsc.Full.sol", "dist:emiprice": "node update-version.js && truffle-flattener ./contracts/EmiPrice.sol > ./flat/EmiPrice.Full.sol", "dist:emiprice2": "node update-version.js && truffle-flattener ./contracts/EmiPrice2.sol > ./flat/EmiPrice2.Full.sol", "dist:emiprice2-kucoin": "truffle-flattener ./contracts/EmiPrice2-kucoin.sol > ./flat/EmiPrice2-kucoin.Full.sol", From 12a4a3c8cf3af9dc827f395f9c2b2798a182e486 Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 29 Nov 2021 20:41:35 +0200 Subject: [PATCH 22/24] Added admin function transferAnyERC20Token --- flat/ESW.full.sol | 178 ++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/flat/ESW.full.sol b/flat/ESW.full.sol index 45076e8..315b5bd 100644 --- a/flat/ESW.full.sol +++ b/flat/ESW.full.sol @@ -1,3 +1,11 @@ +/** + *Submitted for verification at Etherscan.io on 2021-11-29 +*/ + +/** + *Submitted for verification at Etherscan.io on 2021-07-01 +*/ + // File: @openzeppelin/contracts/utils/Address.sol // SPDX-License-Identifier: MIT @@ -79,7 +87,7 @@ library Address { * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCall(target, data, "Address: low-level call failed"); + return functionCall(target, data, "Address: low-level call failed"); } /** @@ -192,7 +200,6 @@ library Address { // File: @openzeppelin/contracts/proxy/Initializable.sol -// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; @@ -249,7 +256,6 @@ abstract contract Initializable { // File: contracts/interfaces/IEmiVesting.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -265,7 +271,6 @@ interface IEmiVesting { // File: contracts/interfaces/IEmiList.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -279,7 +284,6 @@ interface IEmiList { // File: @openzeppelin/contracts/math/SafeMath.sol -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -496,7 +500,6 @@ library SafeMath { // File: contracts/libraries/Priviledgeable.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.2; @@ -549,7 +552,6 @@ abstract contract Priviledgeable { // File: @openzeppelin/contracts/utils/Context.sol -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -576,13 +578,11 @@ abstract contract Context { // File: @openzeppelin/contracts/GSN/Context.sol -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; // File: @openzeppelin/contracts/token/ERC20/IERC20.sol -// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; @@ -662,7 +662,6 @@ interface IERC20 { // File: contracts/libraries/ProxiedERC20.sol -// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.6.0; @@ -734,7 +733,7 @@ contract ProxiedERC20 is Context, IERC20 { * @dev Returns the name of the token. */ function _updateTokenName(string memory newName, string memory newSymbol) - internal + internal { _name = newName; _symbol = newSymbol; @@ -783,11 +782,11 @@ contract ProxiedERC20 is Context, IERC20 { * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) - public - view - virtual - override - returns (uint256) + public + view + virtual + override + returns (uint256) { return _balances[account]; } @@ -801,10 +800,10 @@ contract ProxiedERC20 is Context, IERC20 { * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) - public - virtual - override - returns (bool) + public + virtual + override + returns (bool) { _transfer(_msgSender(), recipient, amount); return true; @@ -814,11 +813,11 @@ contract ProxiedERC20 is Context, IERC20 { * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) - public - view - virtual - override - returns (uint256) + public + view + virtual + override + returns (uint256) { return _allowances[owner][spender]; } @@ -831,10 +830,10 @@ contract ProxiedERC20 is Context, IERC20 { * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) - public - virtual - override - returns (bool) + public + virtual + override + returns (bool) { _approve(_msgSender(), spender, amount); return true; @@ -882,9 +881,9 @@ contract ProxiedERC20 is Context, IERC20 { * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) - public - virtual - returns (bool) + public + virtual + returns (bool) { _approve( _msgSender(), @@ -909,9 +908,9 @@ contract ProxiedERC20 is Context, IERC20 { * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) - public - virtual - returns (bool) + public + virtual + returns (bool) { _approve( _msgSender(), @@ -1047,18 +1046,17 @@ contract ProxiedERC20 is Context, IERC20 { // File: contracts/libraries/OracleSign.sol -// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; abstract contract OracleSign { function _splitSignature(bytes memory sig) - internal - pure - returns ( - uint8, - bytes32, - bytes32 - ) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) { require(sig.length == 65, "Incorrect signature length"); @@ -1067,11 +1065,11 @@ abstract contract OracleSign { uint8 v; assembly { - //first 32 bytes, after the length prefix + //first 32 bytes, after the length prefix r := mload(add(sig, 0x20)) - //next 32 bytes + //next 32 bytes s := mload(add(sig, 0x40)) - //final byte, first of next 32 bytes + //final byte, first of next 32 bytes v := byte(0, mload(add(sig, 0x60))) } @@ -1079,9 +1077,9 @@ abstract contract OracleSign { } function _recoverSigner(bytes32 message, bytes memory sig) - internal - pure - returns (address) + internal + pure + returns (address) { uint8 v; bytes32 r; @@ -1094,22 +1092,14 @@ abstract contract OracleSign { function _prefixed(bytes32 hash) internal pure returns (bytes32) { return - keccak256( - abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) - ); + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); } } -// File: contracts/ESW.sol - -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.6.2; - - - - - +pragma solidity ^0.6.0; // Exempt from the original UniswapV2Library. library UniswapV2Library { @@ -1333,8 +1323,6 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLi mapping(address => uint256) internal _mintLimit; mapping(address => bool) internal _mintGranted; // <-- been used in previouse implementation, now just reserved at proxy storage - // !!!In updates to contracts set new variables strictly below this line!!! - //----------------------------------------------------------------------------------- string public codeVersion = "ESW v1.1-145-gf234c9e"; @@ -1352,6 +1340,34 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLi address private _emiList; + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + uint256 private _status; + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } + function initialize() public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); _addAdmin(msg.sender); @@ -1407,18 +1423,6 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLi _emiList = emiList; // can be NULL also to remove emiList functionality totally } - /** - * @dev Owner can transfer out any accidentally sent ERC20 tokens - */ - function transferAnyERC20Token( - address tokenAddress, - address beneficiary, - uint256 tokens - ) external onlyAdmin returns (bool success) { - require(tokenAddress != address(0), "EmiVamp: Token address cannot be 0"); - return IERC20(tokenAddress).transfer(beneficiary, tokens); - } - /*********************** public functions *****************************/ function transferFrom( @@ -1542,7 +1546,7 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLi if (_emiList != address(0)) { require(IEmiList(_emiList).approveTransfer(_from, _to, _amount), "Transfer declined by blacklist"); } - //LiquidityProtection_beforeTokenTransfer(_from, _to, _amount); + LiquidityProtection_beforeTokenTransfer(_from, _to, _amount); } // All the following overrides are optional, if you want to modify default behavior. @@ -1572,4 +1576,24 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLi _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); super._mint(recipient, amount); } -} + + /*********************** admin functions *****************************/ + function reentrancyGuard_init() external onlyAdmin { + _status = _NOT_ENTERED; + } + + /** + * @dev Owner can transfer out any accidentally sent ERC20 tokens + */ + function transferAnyERC20Token( + address tokenAddress, + address beneficiary, + uint256 tokens + ) external onlyAdmin nonReentrant() returns (bool success) { + require( + tokenAddress != address(0), + "Token address cannot be 0" + ); + return IERC20(tokenAddress).transfer(beneficiary, tokens); + } +} \ No newline at end of file From 13c703d691566293577e8419b52e0ea5b1ead3be Mon Sep 17 00:00:00 2001 From: Maksim Date: Sun, 27 Feb 2022 14:25:07 +0200 Subject: [PATCH 23/24] Added contracts for new chains, modified matic, shiden ESW contracts --- contracts/ESW-astar.sol | 185 +++++ contracts/ESW-aurora.sol | 185 +++++ contracts/ESW-matic.sol | 12 +- contracts/ESW-shiden.sol | 48 +- contracts/EmiVault-astar.sol | 82 +++ contracts/EmiVault-shiden.sol | 82 +++ flat/ESW-astar.full.sol | 1258 +++++++++++++++++++++++++++++++++ flat/ESW-aurora.full.sol | 1258 +++++++++++++++++++++++++++++++++ flat/ESW-matic.full.sol | 12 +- flat/ESW-shiden.full.sol | 48 +- flat/EmiVault-astar.Full.sol | 814 +++++++++++++++++++++ flat/EmiVault-shiden.Full.sol | 814 +++++++++++++++++++++ package.json | 4 + 13 files changed, 4788 insertions(+), 14 deletions(-) create mode 100644 contracts/ESW-astar.sol create mode 100644 contracts/ESW-aurora.sol create mode 100644 contracts/EmiVault-astar.sol create mode 100644 contracts/EmiVault-shiden.sol create mode 100644 flat/ESW-astar.full.sol create mode 100644 flat/ESW-aurora.full.sol create mode 100644 flat/EmiVault-astar.Full.sol create mode 100644 flat/EmiVault-shiden.Full.sol diff --git a/contracts/ESW-astar.sol b/contracts/ESW-astar.sol new file mode 100644 index 0000000..72592dd --- /dev/null +++ b/contracts/ESW-astar.sol @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/ProxiedERC20.sol"; +import "./libraries/OracleSign.sol"; + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-astar v1.0-244-g12a4a3c"; + + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 30_000_000e18); + } + + /*********************** admin functions *****************************/ + + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} \ No newline at end of file diff --git a/contracts/ESW-aurora.sol b/contracts/ESW-aurora.sol new file mode 100644 index 0000000..e7719b8 --- /dev/null +++ b/contracts/ESW-aurora.sol @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/ProxiedERC20.sol"; +import "./libraries/OracleSign.sol"; + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-aurora v1.0-244-g12a4a3c"; + + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 30_000_000e18); + } + + /*********************** admin functions *****************************/ + + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} \ No newline at end of file diff --git a/contracts/ESW-matic.sol b/contracts/ESW-matic.sol index 80975fd..03852fb 100644 --- a/contracts/ESW-matic.sol +++ b/contracts/ESW-matic.sol @@ -8,11 +8,11 @@ import "./libraries/ProxiedERC20.sol"; contract ESW is ProxiedERC20, Initializable, Priviledgeable { - uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; address private _emiList; - string public codeVersion = "ESW-matic v1.0"; + string public codeVersion = "ESW-matic v1.0-244-g12a4a3c"; // keeping it for checking, whether deposit being called by valid address or not address public childChainManagerProxy; @@ -85,4 +85,12 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable { childChainManagerProxy = newChildChainManagerProxy; } + + function mint(address walletTo, uint256 amount) public onlyAdmin { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW-matic:supply_exceeded" + ); + super._mint(walletTo, amount); + } } \ No newline at end of file diff --git a/contracts/ESW-shiden.sol b/contracts/ESW-shiden.sol index 10d8d45..c2e5660 100644 --- a/contracts/ESW-shiden.sol +++ b/contracts/ESW-shiden.sol @@ -13,9 +13,9 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - string public codeVersion = "ESW-shiden v1.0-242-g6153cd3"; + string public codeVersion = "ESW-shiden v1.0-244-g12a4a3c"; - uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; address public constant oracleMinter = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle @@ -24,14 +24,32 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { address private _emiList; + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + function initialize(address deployerAdmin) public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); _addAdmin(deployerAdmin); _mint(deployerAdmin, 10_000_000e18); - } + } /*********************** admin functions *****************************/ + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + function updateTokenName(string memory newName, string memory newSymbol) public onlyAdmin @@ -49,6 +67,28 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { _mintLimit[account] = amount; } + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + function transfer(address recipient, uint256 amount) public virtual @@ -58,8 +98,6 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { super.transfer(recipient, amount); return true; } - - /*********************** public functions *****************************/ function transferFrom( address sender, diff --git a/contracts/EmiVault-astar.sol b/contracts/EmiVault-astar.sol new file mode 100644 index 0000000..834856c --- /dev/null +++ b/contracts/EmiVault-astar.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/OracleSign.sol"; + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-astar v1.0-244-g12a4a3c"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/contracts/EmiVault-shiden.sol b/contracts/EmiVault-shiden.sol new file mode 100644 index 0000000..c4b77de --- /dev/null +++ b/contracts/EmiVault-shiden.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/OracleSign.sol"; + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-shiden v1.0-244-g12a4a3c"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/ESW-astar.full.sol b/flat/ESW-astar.full.sol new file mode 100644 index 0000000..aacf24e --- /dev/null +++ b/flat/ESW-astar.full.sol @@ -0,0 +1,1258 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/GSN/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/libraries/ProxiedERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ProxiedERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint8 private _intialized; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function _initialize( + string memory name, + string memory symbol, + uint8 decimals + ) internal { + require(_intialized == 0, "Already intialize"); + _name = name; + _symbol = symbol; + _decimals = decimals; + _intialized = 1; + } + + /** + * @dev Returns the name of the token. + */ + function _updateTokenName(string memory newName, string memory newSymbol) + internal + { + _name = newName; + _symbol = newSymbol; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) + public + view + virtual + override + returns (uint256) + { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/ESW-astar.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-astar v1.0-244-g12a4a3c"; + + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 30_000_000e18); + } + + /*********************** admin functions *****************************/ + + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} diff --git a/flat/ESW-aurora.full.sol b/flat/ESW-aurora.full.sol new file mode 100644 index 0000000..c25336d --- /dev/null +++ b/flat/ESW-aurora.full.sol @@ -0,0 +1,1258 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/GSN/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/libraries/ProxiedERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ProxiedERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint8 private _intialized; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function _initialize( + string memory name, + string memory symbol, + uint8 decimals + ) internal { + require(_intialized == 0, "Already intialize"); + _name = name; + _symbol = symbol; + _decimals = decimals; + _intialized = 1; + } + + /** + * @dev Returns the name of the token. + */ + function _updateTokenName(string memory newName, string memory newSymbol) + internal + { + _name = newName; + _symbol = newSymbol; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) + public + view + virtual + override + returns (uint256) + { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/ESW-aurora.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-aurora v1.0-244-g12a4a3c"; + + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 30_000_000e18); + } + + /*********************** admin functions *****************************/ + + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} diff --git a/flat/ESW-matic.full.sol b/flat/ESW-matic.full.sol index 84f768e..bed9663 100644 --- a/flat/ESW-matic.full.sol +++ b/flat/ESW-matic.full.sol @@ -1040,11 +1040,11 @@ pragma solidity ^0.6.2; contract ESW is ProxiedERC20, Initializable, Priviledgeable { - uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; address private _emiList; - string public codeVersion = "ESW-matic v1.0"; + string public codeVersion = "ESW-matic v1.1-244-g12a4a3c"; // keeping it for checking, whether deposit being called by valid address or not address public childChainManagerProxy; @@ -1117,4 +1117,12 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable { childChainManagerProxy = newChildChainManagerProxy; } + + function mint(address walletTo, uint256 amount) public onlyAdmin { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW-matic:supply_exceeded" + ); + super._mint(walletTo, amount); + } } diff --git a/flat/ESW-shiden.full.sol b/flat/ESW-shiden.full.sol index 55f9d0b..bf9e953 100644 --- a/flat/ESW-shiden.full.sol +++ b/flat/ESW-shiden.full.sol @@ -1086,9 +1086,9 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { // !!!In updates to contracts set new variables strictly below this line!!! //----------------------------------------------------------------------------------- - string public codeVersion = "ESW-shiden v1.0-242-g6153cd3"; + string public codeVersion = "ESW-shiden v1.0-244-g12a4a3c"; - uint256 public constant MAXIMUM_SUPPLY = 20_000_000e18; + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; address public constant oracleMinter = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle @@ -1097,14 +1097,32 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { address private _emiList; + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + function initialize(address deployerAdmin) public virtual initializer { _initialize("EmiDAO Token", "ESW", 18); _addAdmin(deployerAdmin); _mint(deployerAdmin, 10_000_000e18); - } + } /*********************** admin functions *****************************/ + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + function updateTokenName(string memory newName, string memory newSymbol) public onlyAdmin @@ -1122,6 +1140,28 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { _mintLimit[account] = amount; } + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + function transfer(address recipient, uint256 amount) public virtual @@ -1131,8 +1171,6 @@ contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { super.transfer(recipient, amount); return true; } - - /*********************** public functions *****************************/ function transferFrom( address sender, diff --git a/flat/EmiVault-astar.Full.sol b/flat/EmiVault-astar.Full.sol new file mode 100644 index 0000000..0a5f10c --- /dev/null +++ b/flat/EmiVault-astar.Full.sol @@ -0,0 +1,814 @@ +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/EmiVault-astar.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + + + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-astar v1.0-244-g12a4a3c"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/EmiVault-shiden.Full.sol b/flat/EmiVault-shiden.Full.sol new file mode 100644 index 0000000..0a5fba8 --- /dev/null +++ b/flat/EmiVault-shiden.Full.sol @@ -0,0 +1,814 @@ +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/EmiVault-shiden.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + + + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-shiden v1.0-244-g12a4a3c"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/package.json b/package.json index d51bd67..845af28 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,8 @@ "dist:esw-matic": "truffle-flattener ./contracts/ESW-matic.sol > ./flat/ESW-matic.full.sol", "dist:esw-kucoin": "truffle-flattener ./contracts/ESW-kucoin.sol > ./flat/ESW-kucoin.full.sol", "dist:esw-shiden": "truffle-flattener ./contracts/ESW-shiden.sol > ./flat/ESW-shiden.full.sol", + "dist:esw-aurora": "truffle-flattener ./contracts/ESW-aurora.sol > ./flat/ESW-aurora.full.sol", + "dist:esw-astar": "truffle-flattener ./contracts/ESW-astar.sol > ./flat/ESW-astar.full.sol", "dist:emilist": "truffle-flattener ./contracts/EmiList.sol > ./flat/EmiList.full.sol", "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", @@ -109,6 +111,8 @@ "dist:emivault": "node update-version.js && truffle-flattener ./contracts/EmiVault.sol > ./flat/EmiVault.Full.sol", "dist:emivault-kucoin": "node update-version.js && truffle-flattener ./contracts/EmiVault-kucoin.sol > ./flat/EmiVault-kucoin.Full.sol", "dist:emivault-aurora": "node update-version.js && truffle-flattener ./contracts/EmiVault-aurora.sol > ./flat/EmiVault-aurora.Full.sol", + "dist:emivault-shiden": "node update-version.js && truffle-flattener ./contracts/EmiVault-shiden.sol > ./flat/EmiVault-shiden.Full.sol", + "dist:emivault-astar": "node update-version.js && truffle-flattener ./contracts/EmiVault-astar.sol > ./flat/EmiVault-astar.Full.sol", "dist:emivault-bsc": "node update-version.js && truffle-flattener ./contracts/EmiVault-bsc.sol > ./flat/EmiVault-bsc.Full.sol", "dist:emiprice": "node update-version.js && truffle-flattener ./contracts/EmiPrice.sol > ./flat/EmiPrice.Full.sol", "dist:emiprice2": "node update-version.js && truffle-flattener ./contracts/EmiPrice2.sol > ./flat/EmiPrice2.Full.sol", From b6d7b8cfaf0dbaa2efdd80030333bf22ec1e7f4e Mon Sep 17 00:00:00 2001 From: Maksim Date: Sat, 19 Mar 2022 01:48:11 +0200 Subject: [PATCH 24/24] Added contracts for gatechain --- contracts/ESW-gatechain.sol | 185 +++++ contracts/EmiVault-gatechain.sol | 82 ++ flat/ESW-gatechain.full.sol | 1258 ++++++++++++++++++++++++++++++ flat/EmiVault-gatechain.Full.sol | 814 +++++++++++++++++++ package.json | 2 + 5 files changed, 2341 insertions(+) create mode 100644 contracts/ESW-gatechain.sol create mode 100644 contracts/EmiVault-gatechain.sol create mode 100644 flat/ESW-gatechain.full.sol create mode 100644 flat/EmiVault-gatechain.Full.sol diff --git a/contracts/ESW-gatechain.sol b/contracts/ESW-gatechain.sol new file mode 100644 index 0000000..ed30a80 --- /dev/null +++ b/contracts/ESW-gatechain.sol @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/ProxiedERC20.sol"; +import "./libraries/OracleSign.sol"; + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-gatechain v1.0-245-g13c703d"; + + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 10_000_000e18); + } + + /*********************** admin functions *****************************/ + + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} \ No newline at end of file diff --git a/contracts/EmiVault-gatechain.sol b/contracts/EmiVault-gatechain.sol new file mode 100644 index 0000000..5d83856 --- /dev/null +++ b/contracts/EmiVault-gatechain.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./libraries/Priviledgeable.sol"; +import "./libraries/OracleSign.sol"; + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-gatechain v1.0-245-g13c703d"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/flat/ESW-gatechain.full.sol b/flat/ESW-gatechain.full.sol new file mode 100644 index 0000000..3cf45d5 --- /dev/null +++ b/flat/ESW-gatechain.full.sol @@ -0,0 +1,1258 @@ +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + +// SPDX-License-Identifier: MIT + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: contracts/libraries/Priviledgeable.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/GSN/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/libraries/ProxiedERC20.sol + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.6.0; + + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ProxiedERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint8 private _intialized; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function _initialize( + string memory name, + string memory symbol, + uint8 decimals + ) internal { + require(_intialized == 0, "Already intialize"); + _name = name; + _symbol = symbol; + _decimals = decimals; + _intialized = 1; + } + + /** + * @dev Returns the name of the token. + */ + function _updateTokenName(string memory newName, string memory newSymbol) + internal + { + _name = newName; + _symbol = newSymbol; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) + public + view + virtual + override + returns (uint256) + { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + view + virtual + override + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + +// File: contracts/libraries/OracleSign.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/ESW-gatechain.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.2; + + + + + +contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign { + uint256 internal _initialSupply; + mapping(address => uint256) internal _mintLimit; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + string public codeVersion = "ESW-gatechain v1.0-245-g13c703d"; + + uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18; + + address public constant oracleMinter = + 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle + + mapping(address => uint256) public walletNonce; + + address private _emiList; + + address public bridgeWallet; + + modifier onlyBridge() { + require(msg.sender == bridgeWallet, "Bridge wallet needed"); + _; + } + + function initialize(address deployerAdmin) public virtual initializer { + _initialize("EmiDAO Token", "ESW", 18); + _addAdmin(deployerAdmin); + _mint(deployerAdmin, 10_000_000e18); + } + + /*********************** admin functions *****************************/ + + function adminMint(address wallet, uint256 amount) + public + onlyAdmin + { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mint(wallet, amount); + } + + function updateTokenName(string memory newName, string memory newSymbol) + public + onlyAdmin + { + _updateTokenName(newName, newSymbol); + } + + /** + * set mint limit for exact contract wallets + * @param account - wallet to set mint limit + * @param amount - mint limit value + */ + + function setMintLimit(address account, uint256 amount) public onlyAdmin { + _mintLimit[account] = amount; + } + + function setBridgeWallet(address newBridgeWallet) public onlyAdmin { + require(newBridgeWallet != address(0), "Bridge address needed!"); + bridgeWallet = newBridgeWallet; + } + + /*********************** bridge functions *****************************/ + + function mint(address to, uint256 amount) external onlyBridge returns (bool) + { + _mint(to, amount); + return true; + } + + function burn(address from, uint256 amount) external onlyBridge returns (bool) + { + require(from != address(0), "AnyswapV3ERC20: address(0x0)"); + _burn(from, amount); + return true; + } + + /*********************** public functions *****************************/ + + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + super.transfer(recipient, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + super.transferFrom(sender, recipient, amount); + return true; + } + + function burn(uint256 amount) public { + super._burn(msg.sender, amount); + } + + /** + * mintSigned - oracle signed function allow user to mint ESW tokens + * @param recipient - user's wallet for receiving tokens + * @param amount - amount to mint + * @param nonce - user's mint request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to mint tokens + */ + + function mintSigned( + address recipient, + uint256 amount, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "ESW:sender"); + // check sign + bytes32 message = + _prefixed( + keccak256(abi.encodePacked(recipient, amount, nonce, this)) + ); + + require( + _recoverSigner(message, sig) == oracleMinter && + walletNonce[msg.sender] < nonce, + "ESW:sign" + ); + + walletNonce[msg.sender] = nonce; + + _mintAllowed(oracleMinter, recipient, amount); + } + + /*********************** view functions *****************************/ + + function initialSupply() public view returns (uint256) { + return _initialSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return super.balanceOf(account); + } + + /** + * getMintLimit - read mint limit for wallets + * @param account - wallet address + * @return - mintlimit for requested wallet + */ + + function getMintLimit(address account) public view returns (uint256) { + return _mintLimit[account]; + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /*********************** internal functions *****************************/ + + function _mintAllowed( + address allowedMinter, + address recipient, + uint256 amount + ) internal { + require( + totalSupply().add(amount) <= MAXIMUM_SUPPLY, + "ESW:supply_exceeded" + ); + _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount); + super._mint(recipient, amount); + } +} diff --git a/flat/EmiVault-gatechain.Full.sol b/flat/EmiVault-gatechain.Full.sol new file mode 100644 index 0000000..3aeb110 --- /dev/null +++ b/flat/EmiVault-gatechain.Full.sol @@ -0,0 +1,814 @@ +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + + + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/proxy/Initializable.sol + + + +// solhint-disable-next-line compiler-version +pragma solidity >=0.4.24 <0.8.0; + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function _isConstructor() private view returns (bool) { + return !Address.isContract(address(this)); + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + + + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol + + + +pragma solidity >=0.6.0 <0.8.0; + + + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).add(value); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { + uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); + if (returndata.length > 0) { // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} + +// File: contracts/libraries/Priviledgeable.sol + + +pragma solidity ^0.6.2; + + +abstract contract Priviledgeable { + using SafeMath for uint256; + using SafeMath for uint256; + + event PriviledgeGranted(address indexed admin); + event PriviledgeRevoked(address indexed admin); + + modifier onlyAdmin() { + require( + _priviledgeTable[msg.sender], + "Priviledgeable: caller is not the owner" + ); + _; + } + + mapping(address => bool) private _priviledgeTable; + + constructor() internal { + _priviledgeTable[msg.sender] = true; + } + + function addAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + return _addAdmin(_admin); + } + + function removeAdmin(address _admin) external onlyAdmin returns (bool) { + require(_admin != address(0), "Admin address cannot be 0"); + _priviledgeTable[_admin] = false; + emit PriviledgeRevoked(_admin); + + return true; + } + + function isAdmin(address _who) external view returns (bool) { + return _priviledgeTable[_who]; + } + + //----------- + // internals + //----------- + function _addAdmin(address _admin) internal returns (bool) { + _priviledgeTable[_admin] = true; + emit PriviledgeGranted(_admin); + } +} + +// File: contracts/libraries/OracleSign.sol + + +pragma solidity ^0.6.2; + +abstract contract OracleSign { + function _splitSignature(bytes memory sig) + internal + pure + returns ( + uint8, + bytes32, + bytes32 + ) + { + require(sig.length == 65, "Incorrect signature length"); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + //first 32 bytes, after the length prefix + r := mload(add(sig, 0x20)) + //next 32 bytes + s := mload(add(sig, 0x40)) + //final byte, first of next 32 bytes + v := byte(0, mload(add(sig, 0x60))) + } + + return (v, r, s); + } + + function _recoverSigner(bytes32 message, bytes memory sig) + internal + pure + returns (address) + { + uint8 v; + bytes32 r; + bytes32 s; + + (v, r, s) = _splitSignature(sig); + + return ecrecover(message, v, r, s); + } + + function _prefixed(bytes32 hash) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + } +} + +// File: contracts/EmiVault-gatechain.sol + + + +pragma solidity ^0.6.0; + + + + + + + +contract EmiVault is Initializable, Priviledgeable, OracleSign { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + + string public codeVersion = "EmiVault-gatechain v1.0-245-g13c703d"; + + // !!!In updates to contracts set new variables strictly below this line!!! + //----------------------------------------------------------------------------------- + + address public constant ORACLE = 0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; + mapping(address => uint256) public walletNonce; + + function initialize(address deployerAdmin) public initializer { + _addAdmin(deployerAdmin); + } + + function getWalletNonce() public view returns (uint256) { + return walletNonce[msg.sender]; + } + + /** + * withdrawTokens - oracle signed function allow user to withdraw dividend tokens + * @param tokenAddresses - array of token addresses to withdraw + * @param amounts - array of token amounts to withdraw + * @param recipient - user's wallet for receiving tokens + * @param nonce - user's withdraw request number, for security purpose + * @param sig - oracle signature, oracle allowance for user to withdraw tokens + */ + + function withdrawTokens( + address[] memory tokenAddresses, + uint256[] memory amounts, + address recipient, + uint256 nonce, + bytes memory sig + ) public { + require(recipient == msg.sender, "EmiVault:sender"); + require( + tokenAddresses.length > 0 && + tokenAddresses.length == amounts.length && + tokenAddresses.length <= 60, + "EmiVault:length" + ); + // check sign + bytes32 message = + _prefixed( + keccak256( + abi.encodePacked( + tokenAddresses, + amounts, + recipient, + nonce, + this + ) + ) + ); + + require( + _recoverSigner(message, sig) == ORACLE && + walletNonce[msg.sender] < nonce, + "EmiVault:sign" + ); + + walletNonce[msg.sender] = nonce; + + for (uint256 index = 0; index < tokenAddresses.length; index++) { + IERC20(tokenAddresses[index]).transfer(recipient, amounts[index]); + } + } +} diff --git a/package.json b/package.json index 845af28..288bd88 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "dist:esw-shiden": "truffle-flattener ./contracts/ESW-shiden.sol > ./flat/ESW-shiden.full.sol", "dist:esw-aurora": "truffle-flattener ./contracts/ESW-aurora.sol > ./flat/ESW-aurora.full.sol", "dist:esw-astar": "truffle-flattener ./contracts/ESW-astar.sol > ./flat/ESW-astar.full.sol", + "dist:esw-gatechain": "truffle-flattener ./contracts/ESW-gatechain.sol > ./flat/ESW-gatechain.full.sol", "dist:emilist": "truffle-flattener ./contracts/EmiList.sol > ./flat/EmiList.full.sol", "dist:crowdsale": "node update-version.js && truffle-flattener ./contracts/CrowdSale.sol > ./flat/CrowdSale.Full.sol", "dist:emivesting": "node update-version.js && truffle-flattener ./contracts/EmiVesting.sol > ./flat/EmiVesting.Full.sol", @@ -113,6 +114,7 @@ "dist:emivault-aurora": "node update-version.js && truffle-flattener ./contracts/EmiVault-aurora.sol > ./flat/EmiVault-aurora.Full.sol", "dist:emivault-shiden": "node update-version.js && truffle-flattener ./contracts/EmiVault-shiden.sol > ./flat/EmiVault-shiden.Full.sol", "dist:emivault-astar": "node update-version.js && truffle-flattener ./contracts/EmiVault-astar.sol > ./flat/EmiVault-astar.Full.sol", + "dist:emivault-gatechain": "node update-version.js && truffle-flattener ./contracts/EmiVault-gatechain.sol > ./flat/EmiVault-gatechain.Full.sol", "dist:emivault-bsc": "node update-version.js && truffle-flattener ./contracts/EmiVault-bsc.sol > ./flat/EmiVault-bsc.Full.sol", "dist:emiprice": "node update-version.js && truffle-flattener ./contracts/EmiPrice.sol > ./flat/EmiPrice.Full.sol", "dist:emiprice2": "node update-version.js && truffle-flattener ./contracts/EmiPrice2.sol > ./flat/EmiPrice2.Full.sol",