Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New LockProxy #57

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2b1cbe0
add whiteList contract and method (#12)
KSlashh Aug 16, 2021
f377a69
fix bug
KSlashh Sep 14, 2021
6534bdb
new update template
KSlashh Sep 14, 2021
d885de6
new test
KSlashh Sep 15, 2021
c6b86da
Modification based on audit report
KSlashh Sep 24, 2021
5ab4f25
add whiteLister
KSlashh Sep 30, 2021
67ef302
update
KSlashh Oct 8, 2021
e32c5f4
update scripts
KSlashh Oct 11, 2021
2d3bd11
update config
KSlashh Oct 11, 2021
909afc0
update test cases
KSlashh Nov 8, 2021
bfd39da
update
KSlashh Nov 11, 2021
42e6992
Contracts for Testnet (#27)
KSlashh Dec 10, 2021
e19954d
new lockproxy that can add/remove liquidity
KSlashh Dec 14, 2021
2abb250
better bind function
KSlashh Dec 17, 2021
5854f67
bug fix: deposite should be payable
KSlashh Dec 21, 2021
099ab3e
tiny update
KSlashh Dec 27, 2021
4f8dbdd
Merge remote-tracking branch 'poly/testnet' into testnet
KSlashh Dec 27, 2021
783a362
config hardhat youself
KSlashh Dec 27, 2021
bd909c1
add gitignore
KSlashh Dec 27, 2021
9e371db
Add LockproxyWithLP (#31)
KSlashh Dec 27, 2021
2e2baee
Merge branch 'polynetwork:testnet' into testnet
KSlashh Apr 6, 2022
a0b9487
ccm for upgrade
KSlashh Apr 6, 2022
ab2fd6b
new LockProxyPip4 for customize deciamls
KSlashh Aug 19, 2022
2193644
add xrp lock-proxy
KSlashh Sep 28, 2022
1f5f4ba
Merge branch 'master' into testnet
KSlashh Sep 28, 2022
4a3973c
Merge branch 'master' into testnet
KSlashh Sep 28, 2022
ee86426
Merge pull request #7 from KSlashh/testnet
KSlashh Sep 28, 2022
7b6d14f
lockproxy add check for ripple
KSlashh Sep 28, 2022
44476d5
update scripts
Dec 12, 2022
ee93be8
Merge pull request #9 from KSlashh/testnet
KSlashh Dec 12, 2022
970063b
Merge remote-tracking branch 'poly/master'
Dec 12, 2022
40ed632
Merge branch 'polynetwork:master' into master
KSlashh Dec 12, 2022
6814e59
Merge pull request #11 from KSlashh/master
KSlashh Dec 12, 2022
91ebefc
clean up
KSlashh Feb 6, 2023
1b927aa
add LockProxyMintBurn
KSlashh Jun 15, 2023
948fb9f
bug fix
KSlashh Jun 21, 2023
bd8c0e2
add new LockProxy
KSlashh Aug 27, 2023
7bca146
bug fix : add return value for unlock function
KSlashh Aug 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions contracts/Migrations.sol

This file was deleted.

59 changes: 59 additions & 0 deletions contracts/core/lock_proxy/LockProxyLimited.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
pragma solidity ^0.5.0;

import "./LockProxyPausable.sol";

contract LockProxyLimited is LockProxyPausable {

mapping(address => uint) public quota;
mapping(address => uint) public usedQuota;
mapping(address => uint) public refreshPeriod;
mapping(address => uint) public refreshTimestamp;

function unlock(bytes memory argsBs, bytes memory fromContractAddr, uint64 fromChainId) onlyManagerContract whenNotPaused public returns (bool) {
TxArgs memory args = _deserializeTxArgs(argsBs);

require(fromContractAddr.length != 0, "from proxy contract address cannot be empty");
require(Utils.equalStorage(proxyHashMap[fromChainId], fromContractAddr), "From Proxy contract address error!");

require(args.toAssetHash.length != 0, "toAssetHash cannot be empty");
address toAsset = Utils.bytesToAddress(args.toAssetHash);
require(assetHashMap[toAsset][fromChainId].length != 0, "toAsset not bind");

require(args.toAddress.length != 0, "toAddress cannot be empty");
address toAddress = Utils.bytesToAddress(args.toAddress);

if (refreshPeriod[toAsset] != 0) {
_refreshQuota(toAsset);
require(usedQuota[toAsset] + args.amount <= quota[toAsset], "limit reached");
usedQuota[toAsset] += args.amount;
} else { // refreshPeriod = 0 means quota becomes single-time quota
refreshTimestamp[toAsset] = block.timestamp;
require(args.amount <= quota[toAsset], "limit reached");
}

require(_transferFromContract(toAsset, toAddress, args.amount), "transfer asset from lock_proxy contract to toAddress failed!");

emit UnlockEvent(toAsset, toAddress, args.amount);

return true;
}

function _refreshQuota(address asset) internal {
if (refreshTimestamp[asset] + refreshPeriod[asset] <= block.timestamp) {
refreshTimestamp[asset] = block.timestamp;
usedQuota[asset] = 0;
}
}

/*
admin functions
*/
function setQuota(address asset, uint _quota) public onlyOwner() {
quota[asset] = _quota;
}

function setRefreshPeriod(address asset, uint _refreshPeriod) public onlyOwner() {
refreshPeriod[asset] = _refreshPeriod;
_refreshQuota(asset);
}
}
229 changes: 229 additions & 0 deletions contracts/core/lock_proxy/LockProxyMintBurn.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
pragma solidity ^0.5.0;

import "./../../libs/ownership/Ownable.sol";
import "./../../libs/common/ZeroCopySource.sol";
import "./../../libs/common/ZeroCopySink.sol";
import "./../../libs/utils/Utils.sol";
import "./../../libs/token/ERC20/SafeERC20.sol";
import "./../../libs/token/ERC20/ERC20.sol";
import "./../../libs/token/ERC20/ERC20Detailed.sol";
import "./../cross_chain_manager/interface/IEthCrossChainManager.sol";
import "./../cross_chain_manager/interface/IEthCrossChainManagerProxy.sol";

contract bridgeAsset is Context, ERC20, ERC20Detailed {

address public theBridge;

constructor (string memory name, string memory symbol, uint8 decimals, address bridge_)
public ERC20Detailed(name, symbol, decimals) {
theBridge = bridge_;
}

modifier onlyBridge() {
require(_msgSender() == theBridge, "msgSender is not THE Bridge!");
_;
}

function isTheBridge(address _bridge) public view returns(bool) {
return _bridge == theBridge;
}

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

function burnFrom(address account, uint256 amount) public onlyBridge {
_burnFrom(account, amount);
}
}

contract LockProxyMintBurn is Ownable {
using SafeMath for uint;
using SafeERC20 for IERC20;

struct TxArgs {
bytes toAssetHash;
bytes toAddress;
uint256 amount;
}
address public managerProxyContract;
mapping(uint64 => bytes) public proxyHashMap;
mapping(address => mapping(uint64 => bytes)) public assetHashMap;

event SetManagerProxyEvent(address manager);
event BindProxyEvent(uint64 toChainId, bytes targetProxyHash);
event BindAssetEvent(address fromAssetHash, uint64 toChainId, bytes targetProxyHash, uint initialAmount);
event UnlockEvent(address toAssetHash, address toAddress, uint256 amount);
event LockEvent(address fromAssetHash, address fromAddress, uint64 toChainId, bytes toAssetHash, bytes toAddress, uint256 amount);


modifier onlyManagerContract() {
IEthCrossChainManagerProxy ieccmp = IEthCrossChainManagerProxy(managerProxyContract);
require(_msgSender() == ieccmp.getEthCrossChainManager(), "msgSender is not EthCrossChainManagerContract");
_;
}

function setManagerProxy(address ethCCMProxyAddr) onlyOwner public {
managerProxyContract = ethCCMProxyAddr;
emit SetManagerProxyEvent(managerProxyContract);
}

function bindProxyHash(uint64 toChainId, bytes memory targetProxyHash) onlyOwner public returns (bool) {
proxyHashMap[toChainId] = targetProxyHash;
emit BindProxyEvent(toChainId, targetProxyHash);
return true;
}

function bindAssetHash(address fromAssetHash, uint64 toChainId, bytes memory toAssetHash) onlyOwner public returns (bool) {
assetHashMap[fromAssetHash][toChainId] = toAssetHash;
emit BindAssetEvent(fromAssetHash, toChainId, toAssetHash, getBalanceFor(fromAssetHash));
return true;
}

/* @notice This function is meant to be invoked by the user,
* a certin amount teokens will be locked in the proxy contract the invoker/msg.sender immediately.
* Then the same amount of tokens will be unloked from target chain proxy contract at the target chain with chainId later.
* @param fromAssetHash The asset address in current chain, uniformly named as `fromAssetHash`
* @param toChainId The target chain id
*
* @param toAddress The address in bytes format to receive same amount of tokens in target chain
* @param amount The amount of tokens to be crossed from ethereum to the chain with chainId
*/
function lock(address fromAssetHash, uint64 toChainId, bytes memory toAddress, uint256 amount) public payable returns (bool) {
require(amount != 0, "amount cannot be zero!");

if (isBridgeAsset(fromAssetHash)) {
bridgeAsset(fromAssetHash).burnFrom(_msgSender(), amount);
} else {
require(_transferToContract(fromAssetHash, amount), "transfer asset from fromAddress to lock_proxy contract failed!");
}

bytes memory toAssetHash = assetHashMap[fromAssetHash][toChainId];
require(toAssetHash.length != 0, "empty illegal toAssetHash");

TxArgs memory txArgs = TxArgs({
toAssetHash: toAssetHash,
toAddress: toAddress,
amount: amount
});
bytes memory txData = _serializeTxArgs(txArgs);

IEthCrossChainManagerProxy eccmp = IEthCrossChainManagerProxy(managerProxyContract);
address eccmAddr = eccmp.getEthCrossChainManager();
IEthCrossChainManager eccm = IEthCrossChainManager(eccmAddr);

bytes memory toProxyHash = proxyHashMap[toChainId];
require(toProxyHash.length != 0, "empty illegal toProxyHash");
require(eccm.crossChain(toChainId, toProxyHash, "unlock", txData), "EthCrossChainManager crossChain executed error!");

emit LockEvent(fromAssetHash, _msgSender(), toChainId, toAssetHash, toAddress, amount);

return true;
}

// /* @notice This function is meant to be invoked by the ETH crosschain management contract,
// * then mint a certin amount of tokens to the designated address since a certain amount
// * was burnt from the source chain invoker.
// * @param argsBs The argument bytes recevied by the ethereum lock proxy contract, need to be deserialized.
// * based on the way of serialization in the source chain proxy contract.
// * @param fromContractAddr The source chain contract address
// * @param fromChainId The source chain id
// */
function unlock(bytes memory argsBs, bytes memory fromContractAddr, uint64 fromChainId) onlyManagerContract public returns (bool) {
TxArgs memory args = _deserializeTxArgs(argsBs);

require(fromContractAddr.length != 0, "from proxy contract address cannot be empty");
require(Utils.equalStorage(proxyHashMap[fromChainId], fromContractAddr), "From Proxy contract address error!");

require(args.toAddress.length != 0, "toAddress cannot be empty");
address toAddress = Utils.bytesToAddress(args.toAddress);

require(args.toAssetHash.length != 0, "toAssetHash cannot be empty");
address toAssetHash = Utils.bytesToAddress(args.toAssetHash);

if (isBridgeAsset(toAssetHash)) {
bridgeAsset(toAssetHash).mint(toAddress, args.amount);
} else {
require(_transferFromContract(toAssetHash, toAddress, args.amount), "transfer asset from lock_proxy contract to toAddress failed!");
}

emit UnlockEvent(toAssetHash, toAddress, args.amount);
return true;
}

function isBridgeAsset(address assetAddress) public view returns (bool) {
(bool success, bytes memory returnData) = assetAddress.staticcall(abi.encodeWithSignature("isTheBridge(address)", address(this)));
if (!success || returnData.length == 0) return false;
(bool res,) = ZeroCopySource.NextBool(returnData, 31);
return res;
}

function getBalanceFor(address fromAssetHash) public view returns (uint256) {
if (fromAssetHash == address(0)) {
// return address(this).balance; // this expression would result in error: Failed to decode output: Error: insufficient data for uint256 type
address selfAddr = address(this);
return selfAddr.balance;
} else {
IERC20 erc20Token = IERC20(fromAssetHash);
return erc20Token.balanceOf(address(this));
}
}
function _transferToContract(address fromAssetHash, uint256 amount) internal returns (bool) {
if (fromAssetHash == address(0)) {
// fromAssetHash === address(0) denotes user choose to lock ether
// passively check if the received msg.value equals amount
require(msg.value != 0, "transferred ether cannot be zero!");
require(msg.value == amount, "transferred ether is not equal to amount!");
} else {
// make sure lockproxy contract will decline any received ether
require(msg.value == 0, "there should be no ether transfer!");
// actively transfer amount of asset from msg.sender to lock_proxy contract
require(_transferERC20ToContract(fromAssetHash, _msgSender(), address(this), amount), "transfer erc20 asset to lock_proxy contract failed!");
}
return true;
}
function _transferFromContract(address toAssetHash, address toAddress, uint256 amount) internal returns (bool) {
if (toAssetHash == address(0x0000000000000000000000000000000000000000)) {
// toAssetHash === address(0) denotes contract needs to unlock ether to toAddress
// convert toAddress from 'address' type to 'address payable' type, then actively transfer ether
address(uint160(toAddress)).transfer(amount);
} else {
// actively transfer amount of asset from lock_proxy contract to toAddress
require(_transferERC20FromContract(toAssetHash, toAddress, amount), "transfer erc20 asset from lock_proxy contract to toAddress failed!");
}
return true;
}


function _transferERC20ToContract(address fromAssetHash, address fromAddress, address toAddress, uint256 amount) internal returns (bool) {
IERC20 erc20Token = IERC20(fromAssetHash);
// require(erc20Token.transferFrom(fromAddress, toAddress, amount), "trasnfer ERC20 Token failed!");
erc20Token.safeTransferFrom(fromAddress, toAddress, amount);
return true;
}
function _transferERC20FromContract(address toAssetHash, address toAddress, uint256 amount) internal returns (bool) {
IERC20 erc20Token = IERC20(toAssetHash);
// require(erc20Token.transfer(toAddress, amount), "trasnfer ERC20 Token failed!");
erc20Token.safeTransfer(toAddress, amount);
return true;
}

function _serializeTxArgs(TxArgs memory args) internal pure returns (bytes memory) {
bytes memory buff;
buff = abi.encodePacked(
ZeroCopySink.WriteVarBytes(args.toAssetHash),
ZeroCopySink.WriteVarBytes(args.toAddress),
ZeroCopySink.WriteUint255(args.amount)
);
return buff;
}

function _deserializeTxArgs(bytes memory valueBs) internal pure returns (TxArgs memory) {
TxArgs memory args;
uint256 off = 0;
(args.toAssetHash, off) = ZeroCopySource.NextVarBytes(valueBs, off);
(args.toAddress, off) = ZeroCopySource.NextVarBytes(valueBs, off);
(args.amount, off) = ZeroCopySource.NextUint255(valueBs, off);
return args;
}
}
Loading