Skip to content

Commit

Permalink
new behaviour for POL integration
Browse files Browse the repository at this point in the history
  • Loading branch information
simonDos committed Sep 18, 2023
1 parent f3af417 commit e041d76
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 26 deletions.
37 changes: 37 additions & 0 deletions contracts/common/tokens/TestToken.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
pragma solidity ^0.5.2;

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

contract TestToken is ERC20Mintable {
using Address for address;

// detailed ERC20
string public name;
string public symbol;
Expand All @@ -15,4 +18,38 @@ contract TestToken is ERC20Mintable {
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)));
}
}
}
41 changes: 29 additions & 12 deletions contracts/root/depositManager/DepositManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ 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");
// new: exception for POL token
require(registry.isTokenMapped(_token) || _token == registry.contractMap(keccak256("pol")), "TOKEN_NOT_SUPPORTED");
_;
}

Expand All @@ -39,6 +41,7 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
depositEther();
}

// new: governance function to migrate MATIC to POL
function migrateMatic(uint256 _amount) external onlyGovernance {
_migrateMatic(_amount);
}
Expand All @@ -47,7 +50,7 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
IERC20 matic = IERC20(registry.contractMap(keccak256("matic")));

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

// approve
matic.approve(registry.contractMap(keccak256("polygonMigration")), _amount);
Expand All @@ -64,13 +67,22 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder

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);

// so we don't assign to a function var
address memory token = _token;

// new: pay out POL when MATIC is withdrawn
if (_token == registry.contractMap(keccak256("matic"))) {
token = registry.contractMap(keccak256("pol"));
}

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");
require(IERC20(token).transfer(_user, _amountOrNFTId), "TRANSFER_FAILED");
}
}

Expand Down Expand Up @@ -124,11 +136,6 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
require(_amount <= maxErc20Deposit, "exceed maximum deposit amount");
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);

// new: auto-migrate MATIC to POL
if (_token == registry.contractMap(keccak256("matic"))) {
_migrateMatic(_amount);
}

_safeCreateDepositBlock(_user, _token, _amount);
}

Expand Down Expand Up @@ -156,6 +163,16 @@ contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder
}

function _createDepositBlock(address _user, address _token, uint256 _amountOrToken, uint256 _depositId) internal {
// new: auto-migrate MATIC to POL
if (_token == registry.contractMap(keccak256("matic"))) {
_migrateMatic(_amountOrToken);
}

// new: bridge POL as MATIC, child chain behaviour does not change
if(_token == registry.contractMap(keccak256("pol"))) {
_token == registry.contractMap(keccak256("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);
}
}
43 changes: 32 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@
"solidity-coverage": "^0.7.4",
"solium": "^1.1.8",
"truffle": "5.0.34",
"truffle-contract-size": "^1.0.1",
"web3": "^1.0.0-beta.33",
"web3-eth-abi": "^1.0.0-beta.51",
"truffle-contract-size": "^1.0.1"
"web3-eth-abi": "^1.0.0-beta.51"
},
"dependencies": {
"@truffle/hdwallet-provider": "^1.4.0",
Expand Down
1 change: 1 addition & 0 deletions test/helpers/artifacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const ExitNFT = artifacts.require('ExitNFT')
// Misc
export const GnosisSafeProxy = artifacts.require('GnosisSafeProxy')
export const GnosisSafe = artifacts.require('GnosisSafe')
export const PolygonMigrationTest = artifacts.require('PolygonMigrationTest')

// child chain
export const childContracts = {
Expand Down
Loading

0 comments on commit e041d76

Please sign in to comment.