Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #497 from maticnetwork/plasma-bridge-update
Browse files Browse the repository at this point in the history
Plasma bridge update
  • Loading branch information
simonDos authored Dec 15, 2023
2 parents fa235fa + e6a5e74 commit fce9020
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 46 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test-blockchain/data
*.log

.DS_Store
.vscode
*.env

coverage/
Expand Down
2 changes: 1 addition & 1 deletion .soliumrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"no-unused-vars": 1,
"quotes": 1,
"error-reason": 0,
"indentation": ["error", 2],
"indentation": ["error", 4],
"arg-overflow": ["error", 8],
"whitespace": 1,
"deprecated-suicide": 1,
Expand Down
56 changes: 56 additions & 0 deletions contracts/common/tokens/POLTokenMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
pragma solidity ^0.5.2;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";
import "openzeppelin-solidity/contracts/utils/Address.sol";


contract POLTokenMock is ERC20Mintable {
using Address for address;

// detailed ERC20
string public name;
string public symbol;
uint8 public decimals = 18;

constructor(string memory _name, string memory _symbol) public {
name = _name;
symbol = _symbol;

uint256 value = 10**10 * (10**18);
mint(msg.sender, value);
}

function safeTransfer(IERC20 token, address to, uint256 value) public {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}

function safeTransferFrom(IERC20 token, address from, address to, uint256 value) public {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}

/**
* @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 equal true).
* @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.

// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.

require(address(token).isContract());

// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success);

if (returndata.length > 0) { // Return data is optional
require(abi.decode(returndata, (bool)));
}
}
}
83 changes: 54 additions & 29 deletions contracts/root/depositManager/DepositManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ import {StateSender} from "../stateSyncer/StateSender.sol";
import {GovernanceLockable} from "../../common/mixin/GovernanceLockable.sol";
import {RootChain} from "../RootChain.sol";

interface IPolygonMigration {
function migrate(uint256 amount) external;
}


contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder {
using SafeMath for uint256;
using SafeERC20 for IERC20;

modifier isTokenMapped(address _token) {
require(registry.isTokenMapped(_token), "TOKEN_NOT_SUPPORTED");
require(
registry.isTokenMapped(_token),
"TOKEN_NOT_SUPPORTED"
);
_;
}

Expand All @@ -36,25 +43,49 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
depositEther();
}

// new: governance function to migrate MATIC to POL
function migrateMatic(uint256 _amount) external onlyGovernance {
_migrateMatic(_amount);
}

function _migrateMatic(uint256 _amount) private {
IERC20 matic = IERC20(registry.contractMap(keccak256("matic")));
address polygonMigration = registry.contractMap(keccak256("polygonMigration"));

// check that _amount is not too high
require(matic.balanceOf(address(this)) >= _amount, "amount exceeds this contract's MATIC balance");

// approve
matic.approve(polygonMigration, _amount);

// call migrate function
IPolygonMigration(polygonMigration).migrate(_amount);
}

function updateMaxErc20Deposit(uint256 maxDepositAmount) public onlyGovernance {
require(maxDepositAmount != 0);
emit MaxErc20DepositUpdate(maxErc20Deposit, maxDepositAmount);
maxErc20Deposit = maxDepositAmount;
}

function transferAssets(
address _token,
address _user,
uint256 _amountOrNFTId
) external isPredicateAuthorized {
function transferAssets(address _token, address _user, uint256 _amountOrNFTId) external isPredicateAuthorized {
address wethToken = registry.getWethTokenAddress();

if (registry.isERC721(_token)) {
IERC721(_token).transferFrom(address(this), _user, _amountOrNFTId);
} else if (_token == wethToken) {
WETH t = WETH(_token);
t.withdraw(_amountOrNFTId, _user);
} else {
require(IERC20(_token).transfer(_user, _amountOrNFTId), "TRANSFER_FAILED");
// new: pay out POL when MATIC is withdrawn
if (_token == registry.contractMap(keccak256("matic"))) {
require(
IERC20(registry.contractMap(keccak256("pol"))).transfer(_user, _amountOrNFTId),
"TRANSFER_FAILED"
);
} else {
require(IERC20(_token).transfer(_user, _amountOrNFTId), "TRANSFER_FAILED");
}
}
}

Expand Down Expand Up @@ -104,21 +135,14 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
stateSender = StateSender(_stateSender);
}

function depositERC20ForUser(
address _token,
address _user,
uint256 _amount
) public {
function depositERC20ForUser(address _token, address _user, uint256 _amount) public {
require(_amount <= maxErc20Deposit, "exceed maximum deposit amount");
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);

_safeCreateDepositBlock(_user, _token, _amount);
}

function depositERC721ForUser(
address _token,
address _user,
uint256 _tokenId
) public {
function depositERC721ForUser(address _token, address _user, uint256 _tokenId) public {
require(registry.isTokenMappedAndIsErc721(_token), "not erc721");

_safeTransferERC721(msg.sender, _token, _tokenId);
Expand All @@ -138,20 +162,21 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
address _token,
uint256 _amountOrToken
) internal onlyWhenUnlocked isTokenMapped(_token) {
_createDepositBlock(
_user,
_token,
_amountOrToken,
rootChain.updateDepositId(1) /* returns _depositId */
);
_createDepositBlock(_user, _token, _amountOrToken, rootChain.updateDepositId(1)); // returns _depositId
}

function _createDepositBlock(
address _user,
address _token,
uint256 _amountOrToken,
uint256 _depositId
) internal {
function _createDepositBlock(address _user, address _token, uint256 _amountOrToken, uint256 _depositId) internal {
address matic = registry.contractMap(keccak256("matic"));

// new: auto-migrate MATIC to POL
if (_token == matic) {
_migrateMatic(_amountOrToken);
}
// new: bridge POL as MATIC, child chain behaviour does not change
else if (_token == registry.contractMap(keccak256("pol"))) {
_token = matic;
}

deposits[_depositId] = DepositBlock(keccak256(abi.encodePacked(_user, _token, _amountOrToken)), now);
stateSender.syncState(childChain, abi.encode(_user, _token, _amountOrToken, _depositId));
emit NewDepositBlock(_user, _token, _amountOrToken, _depositId);
Expand Down
34 changes: 34 additions & 0 deletions contracts/test/PolygonMigrationTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.2;

import {IERC20} from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";

// this impl was shortened for testing purposes
// full impl at https://github.com/0xPolygon/indicia/blob/main/src/PolygonMigration.sol
contract PolygonMigrationTest {
using SafeERC20 for IERC20;

event Migrated(address indexed account, uint256 amount);

IERC20 public polygon;
IERC20 public matic;

function setTokenAddresses(address matic_, address polygon_) external {
if (matic_ == address(0)) revert();
matic = IERC20(matic_);

if (polygon_ == address(0)) revert();
polygon = IERC20(polygon_);
}

/// @notice This function allows for migrating MATIC tokens to POL tokens
/// @dev The function does not do any validation since the migration is a one-way process
/// @param amount Amount of MATIC to migrate
function migrate(uint256 amount) external {
emit Migrated(msg.sender, amount);

matic.safeTransferFrom(msg.sender, address(this), amount);
polygon.safeTransfer(msg.sender, amount);
}
}
Loading

0 comments on commit fce9020

Please sign in to comment.