Skip to content

Commit

Permalink
V1.0.0 (#1)
Browse files Browse the repository at this point in the history
* [REFACTOR] Compatibility changes to the contracts and configurations for compilation against solidity v0.6.2

* migration to @animoca/ethereum-contracts-core_library:1.0.0, added IERC20Detailed.sol and example migrations

* Rename ERC20Base to ERC20Full

* Added IERC20

* switch to public dependency registry for core_library

Co-authored-by: Jan-Paul Azucena <[email protected]>
Co-authored-by: Nathan Sala <[email protected]>
  • Loading branch information
3 people authored May 4, 2020
1 parent eb95f93 commit 332f776
Show file tree
Hide file tree
Showing 21 changed files with 1,752 additions and 929 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 1.0.0 (03/05/2020)

### Breaking changes
* Migration to `@animoca/ethereum-contracts-core_library:1.0.0` with `solc:0.6.x` and `@openzeppelin/contracts:3.x`.
* Moved `WhitelistedOperators.sol` to `@animoca/ethereum-contracts-core_library`.
* Renamed `ERC20Base` to `ERC20Full`.

### New features
* Added `ERC20.sol`, `IERC20.sol` and `IERC20Detailed.sol`.
* Added example migrations.

### Improvements
* `ERC20Fees` now inherits `PayoutWallet` contract.

## 0.0.2 (14/04/2020)

### Breaking changes
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Solidity ERC20 Base

* `ERC20Base.sol`: An ERC20 Implementation including whitelisted operators.
* `ERC20Full.sol`: An ERC20 Implementation with Detailed, ERC165 and operators whitelisting interfaces.
* `ERC20Fees.sol`: A contract to be inherited from for enabling ERC20-based GSN meta-transactions.
23 changes: 23 additions & 0 deletions contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity ^0.6.6;

contract Migrations {
address public owner;
uint public last_completed_migration;

constructor() public {
owner = msg.sender;
}

modifier restricted() {
if (msg.sender == owner) _;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}

function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
25 changes: 0 additions & 25 deletions contracts/access/WhitelistedOperators.sol

This file was deleted.

45 changes: 30 additions & 15 deletions contracts/metatx/ERC20Fees.sol
Original file line number Diff line number Diff line change
@@ -1,45 +1,38 @@
pragma solidity = 0.5.16;
pragma solidity ^0.6.6;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/GSN/GSNRecipient.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@animoca/ethereum-contracts-core_library/contracts/payment/PayoutWallet.sol";
import "../token/ERC20/IERC20.sol";

/**
@title ERC20Fees
@dev a GSNRecipient contract with support for ERC-20 fees
Note: .
*/
contract ERC20Fees is GSNRecipient, Ownable
abstract contract ERC20Fees is GSNRecipient, PayoutWallet
{
enum ErrorCodes {
INSUFFICIENT_BALANCE,
RESTRICTED_METHOD
}

IERC20 public _gasToken;
address public _payoutWallet;
uint public _gasPriceScaling = GAS_PRICE_SCALING_SCALE;

uint constant internal GAS_PRICE_SCALING_SCALE = 1000;

/**
* @dev Constructor function
*/
constructor(address gasTokenAddress, address payoutWallet) internal {
constructor(address gasTokenAddress, address payoutWallet) internal PayoutWallet(payoutWallet) {
setGasToken(gasTokenAddress);
setPayoutWallet(payoutWallet);
}

function setGasToken(address gasTokenAddress) public onlyOwner {
_gasToken = IERC20(gasTokenAddress);
}

function setPayoutWallet(address payoutWallet) public onlyOwner {
require(payoutWallet != address(this));
_payoutWallet = payoutWallet;
}

function setGasPrice(uint gasPriceScaling) public onlyOwner {
_gasPriceScaling = gasPriceScaling;
}
Expand Down Expand Up @@ -67,6 +60,8 @@ contract ERC20Fees is GSNRecipient, Ownable
uint256 maxPossibleCharge
)
public
virtual
override
view
returns (uint256, bytes memory)
{
Expand All @@ -83,7 +78,7 @@ contract ERC20Fees is GSNRecipient, Ownable
* actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder
* is returned to the user in {_postRelayedCall}.
*/
function _preRelayedCall(bytes memory context) internal returns (bytes32) {
function _preRelayedCall(bytes memory context) internal override returns (bytes32) {
(address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256));

// The maximum token charge is pre-charged from the user
Expand All @@ -93,17 +88,37 @@ contract ERC20Fees is GSNRecipient, Ownable
/**
* @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known.
*/
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal {
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal override {
(address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) =
abi.decode(context, (address, uint256, uint256, uint256));

// actualCharge is an _estimated_ charge, which assumes postRelayedCall will use all available gas.
// This implementation's gas cost can be roughly estimated as 10k gas, for the two SSTORE operations in an
// ERC20 transfer.
uint256 overestimation = _computeCharge(SafeMath.sub(POST_RELAYED_CALL_MAX_GAS, 10000), gasPrice, transactionFee);
uint256 overestimation = _computeCharge(SafeMath.sub(_POST_RELAYED_CALL_MAX_GAS, 10000), gasPrice, transactionFee);
actualCharge = SafeMath.sub(actualCharge, overestimation);

// After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
require(_gasToken.transferFrom(_payoutWallet, from, SafeMath.sub(maxPossibleCharge, actualCharge) * _gasPriceScaling / GAS_PRICE_SCALING_SCALE));
}

/**
* @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions,
* and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
*/
function _msgSender() internal virtual override(Context, GSNRecipient) view returns (address payable) {
return super._msgSender();
}

/**
* @dev Replacement for msg.data. Returns the actual calldata of a transaction: msg.data for regular transactions,
* and a reduced version for GSN relayed calls (where msg.data contains additional information).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead.
*/
function _msgData() internal virtual override(Context, GSNRecipient) view returns (bytes memory) {
return super._msgData();
}
}
28 changes: 0 additions & 28 deletions contracts/mocks/token/ERC20/ERC20BaseMock.sol

This file was deleted.

17 changes: 17 additions & 0 deletions contracts/mocks/token/ERC20/ERC20FullMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pragma solidity ^0.6.6;

import "../../../token/ERC20/ERC20Full.sol";
import "../../../token/ERC20/IERC20Detailed.sol";

contract ERC20FullMock is ERC20Full {

string public override name = "ERC20Full";
string public override symbol = "E2F";
uint8 public override decimals = 18;

constructor (uint256 initialBalance) public ERC20Full(initialBalance) {}

function underscoreApprove(address owner, address spender, uint256 value) public {
super._approve(owner, spender, value);
}
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
pragma solidity = 0.5.16;
pragma solidity ^0.6.6;

import "../../token/ERC20/ERC20Base.sol";
import "../../metatx/ERC20Fees.sol";
import "../../../token/ERC20/ERC20Full.sol";
import "../../../metatx/ERC20Fees.sol";

contract ERC20MetaMock is ERC20Base, ERC20Fees {
contract ERC20MetaMock is ERC20Full, ERC20Fees {

uint256 public _state = 0;

string public override name = "ERC20Meta";
string public override symbol = "E2M";
uint8 public override decimals = 18;

constructor (
uint256 initialBalance,
address gasTokenAddress,
address payoutWallet
) public ERC20Base(initialBalance) ERC20Fees(gasTokenAddress, payoutWallet) {}

function name() public view returns (string memory) {
return "ERC20Meta";
}

function symbol() public view returns (string memory) {
return "E2M";
}

function decimals() public view returns (uint8) {
return 18;
}
) public ERC20Full(initialBalance) ERC20Fees(gasTokenAddress, payoutWallet) {}

function anUnrelayableFunction() public returns (bytes4) {
_state = _state + 1;
// bytes4(keccak256("anUnrelayableFunction()")) == 0x2f398d8d
return bytes4(keccak256("anUnrelayableFunction()"));
}


///////////////////////// GSNRecipient implementation //////////////////////////


Expand All @@ -50,6 +41,7 @@ contract ERC20MetaMock is ERC20Base, ERC20Fees {
uint256 maxPossibleCharge
)
public
override
view
returns (uint256, bytes memory mem)
{
Expand Down Expand Up @@ -78,4 +70,24 @@ contract ERC20MetaMock is ERC20Base, ERC20Fees {
approvalData,
maxPossibleCharge);
}

/**
* @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions,
* and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
*/
function _msgSender() internal override(Context, ERC20Fees) view returns (address payable) {
return super._msgSender();
}

/**
* @dev Replacement for msg.data. Returns the actual calldata of a transaction: msg.data for regular transactions,
* and a reduced version for GSN relayed calls (where msg.data contains additional information).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead.
*/
function _msgData() internal override(Context, ERC20Fees) view returns (bytes memory) {
return super._msgData();
}
}
Loading

0 comments on commit 332f776

Please sign in to comment.