// SPDX-License-Identifier: MITpragmasolidity ^0.8.9;import"./interfaces/IERC20.sol";
import"./utils/TransferHelper.sol";
import"./libs/SafeMath.sol";
import"./libs/SignedSafeMath.sol";
/**
* @title EVMBridge
* @author Jeremy Guyet (@jguyet)
* @dev
* Smart Contract for manage the transfers between two blockchains
* who respect the Ethereum Virtual Machine normal. This Smart contract
* contains the list of the chains accepted and list all transactions initialized
* with their hash proof from the destination chain. this smart contract is decentralized
* but managed by one wallet address (The owner wallet of the Graphlinq project).
* This contract is managed by API in Nodejs and we wait 100 block before transfer anything.
*/contractEVMBridge{
usingSafeMathforuint256;
usingSignedSafeMathforint256;
addresspublic token;
addresspublic owner;
addresspublic program;
stringpublic chain;
uint256public feesInDollar;
uint256public defaultFeesInETH;
uint256public minimumTransferQuantity;
//event emitted when new transfer on GLQ bridgeeventBridgeTransfer(uint256 amount,
string toChain
);
mapping(address=>mapping(uint256=>bool)) transfers;
// Private dex informationaddressprivate dex_in;
addressprivate dex_out;
addressprivate dex_pool;
boolinternal paused;
boolinternal locked;
constructor(stringmemory _bridgeChain,
address _token,
uint256 _feesInDollar,
uint256 _minimumTransferQuantity) {
require(msg.sender!=address(0), "ABORT sender - address(0)");
token = _token;
owner =msg.sender;
program =msg.sender;
chain = _bridgeChain;
feesInDollar = _feesInDollar;
minimumTransferQuantity = _minimumTransferQuantity;
defaultFeesInETH =0;
}
modifieronlyOwner() {
require(msg.sender== owner, "Only the owner can do this action");
_;
}
modifieronlyProgramOrOwner() {
require(msg.sender== program ||msg.sender== owner, "Only program or Owner");
_;
}
modifieractivated() {
require(paused ==false, "Bridge actually paused");
_;
}
modifiernoReentrant() {
require(!locked, "No re-entrancy");
locked =true;
_;
locked =false;
}
functiongetFeesInDollar() publicviewreturns (uint256) {
return feesInDollar;
}
functionsetFeesInDollar(uint256 cost) publiconlyOwner{
feesInDollar = cost;
}
functionsetDefaultFeesInETH(uint256 cost) publiconlyOwner{
defaultFeesInETH = cost;
}
functiongetFeesInETH() publicviewreturns (uint256) {
if (dex_pool !=address(0)) {
uint256 oneDollar = getTokenPriceOutFromPoolBalance(dex_in, dex_out, dex_pool);
return oneDollar.mul(1ether).div(feesInDollar).mul(100); // multiplication 1 ether pour decaler les decimals.
}
return defaultFeesInETH;
}
functioninitTransfer(uint256 quantity, stringcalldata toChain) publicpayablenoReentrantactivated{
require(quantity >= minimumTransferQuantity,
"INSUFISANT_QUANTITY"
);
require(msg.value>= getFeesInETH().mul(90).div(100),
"PAYMENT_ABORT"// 90% of the fees minimum
);
require(IERC20(token).balanceOf(msg.sender) >= quantity, "INSUFISANT_BALANCE");
require(IERC20(token).allowance(msg.sender, address(this)) >= quantity, "INSUFISANT_ALLOWANCE");
TransferHelper.safeTransferFrom(token, msg.sender, address(this), quantity);
emit BridgeTransfer(quantity, toChain);
}
functiondeposit(address coin, uint256 quantity) publiconlyOwnernoReentrant{
require(IERC20(coin).balanceOf(msg.sender) >= quantity, "INSUFISANT_BALANCE");
require(IERC20(coin).allowance(msg.sender, address(this)) >= quantity, "INSUFISANT_ALLOWANCE");
TransferHelper.safeTransferFrom(coin, msg.sender, address(this), quantity);
}
functionbalance() publicviewreturns (uint256){
returnpayable(address(this)).balance;
}
functiongetFees() publicviewreturns (uint256) {
return balance();
}
functionclaimFees() publiconlyOwnernoReentrant{
(bool success,)=owner.call{value:balance()}("");
require(success, "BridgeTransfer failed!");
}
functionsetTransferProcessed(address sender, uint256 transferBn) private{
transfers[sender][transferBn] =true;
}
functionisTransferProcessed(address sender, uint256 transferBn) publicviewreturns (bool) {
return transfers[sender][transferBn];
}
functionaddTransferFrom(address to, uint256 amount, uint256 bn) publiconlyProgramOrOwner{
require(isTransferProcessed(to, bn) ==false, "Bridge request already processed.");
setTransferProcessed(to, bn);
TransferHelper.safeTransfer(token, to, amount);
}
functiongetDex() publicviewreturns (address, address, address) {
return (dex_in, dex_out, dex_pool);
}
/**
* Only 18 decimals tokens.
*/functionsetDex(address _in, address _out, address _pool) publiconlyOwner{
dex_in = _in;
dex_out = _out;
dex_pool = _pool;
}
functiongetTokenPriceOutFromPoolBalance(address _in, address _out, address _pool) publicviewreturns (uint256) {
uint256 balanceIn = IERC20(_in).balanceOf(_pool);
uint256 balanceOut = IERC20(_out).balanceOf(_pool);
require(balanceOut >0);
return balanceIn.mul(1ether).div(balanceOut);
// ex: in=USDC,out=ETH = price of ETH in USDC// ex: in=ETH,out=USDC = price of USDC in ETH
}
functionupdateTransferCost(uint256 _feesInDollar) publiconlyOwner{
feesInDollar = _feesInDollar;
}
functionisPaused() publicviewreturns (bool) {
return paused;
}
functionsetPaused(bool p) publiconlyOwner{
paused = p;
}
functionsetMinimumTransferQuantity(uint256 quantity) publiconlyOwner{
minimumTransferQuantity = quantity;
}
functionchangeOwner(address newOwner) publiconlyOwner{
require(newOwner !=address(0), "No zero address");
owner = newOwner;
}
functionchangeProgram(address newProgram) publiconlyOwner{
require(newProgram !=address(0), "No zero address");
program = newProgram;
}
function_getHash(uint256 timestamp, uint256 nonce, address addr) privatepurereturns (bytes32) {
returnkeccak256(abi.encodePacked(timestamp, addr, nonce));
}
}
Contract Source Code
File 2 of 5: IERC20.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.9;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
functionname() externalviewreturns (stringmemory);
functionsymbol() externalviewreturns (stringmemory);
functiondecimals() externalviewreturns (uint8);
functiontotalSupply() externalviewreturns (uint256);
functionbalanceOf(address account) externalviewreturns (uint256);
functiontransfer(address recipient, uint256 amount) externalreturns (bool);
functionallowance(address owner, address spender) externalviewreturns (uint256);
functionapprove(address spender, uint256 amount) externalreturns (bool);
functiontransferFrom(address sender, address recipient, uint256 amount) externalreturns (bool);
eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
eventApproval(addressindexed owner, addressindexed spender, uint256 value);
}
Contract Source Code
File 3 of 5: SafeMath.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/librarySafeMath{
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontryAdd(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontrySub(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
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._
*/functiontryMul(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
// 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/522if (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._
*/functiontryDiv(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
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._
*/functiontryMod(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
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.
*/functionadd(uint256 a, uint256 b) internalpurereturns (uint256) {
return a + b;
}
/**
* @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.
*/functionsub(uint256 a, uint256 b) internalpurereturns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/functionmul(uint256 a, uint256 b) internalpurereturns (uint256) {
return a * b;
}
/**
* @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.
*
* Requirements:
*
* - The divisor cannot be zero.
*/functiondiv(uint256 a, uint256 b) internalpurereturns (uint256) {
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.
*/functionmod(uint256 a, uint256 b) internalpurereturns (uint256) {
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.
*/functionsub(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
unchecked {
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.
*
* 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.
*/functiondiv(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
unchecked {
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.
*/functionmod(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
unchecked {
require(b >0, errorMessage);
return a % b;
}
}
}
Contract Source Code
File 4 of 5: SignedSafeMath.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)pragmasolidity ^0.8.0;librarySignedSafeMath{
functionmul(int256 a, int256 b) internalpurereturns (int256) {
return a * b;
}
functiondiv(int256 a, int256 b) internalpurereturns (int256) {
return a / b;
}
functionsub(int256 a, int256 b) internalpurereturns (int256) {
return a - b;
}
functionadd(int256 a, int256 b) internalpurereturns (int256) {
return a + b;
}
}
Contract Source Code
File 5 of 5: TransferHelper.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.9;// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/falselibraryTransferHelper{
functionsafeTransfer(address token, address to, uint value) internal{
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytesmemory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length==0||abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
functionsafeTransferFrom(address token, addressfrom, address to, uint value) internal{
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytesmemory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length==0||abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
}