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

feat(vault): <- adds EthPNT handling... #40

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bee2d34
feat(test-constants): <- adds zero address to those
gskapka Sep 27, 2022
a40d67c
feat(vault): <- adds PNT address to that & fxn to change it
gskapka Sep 27, 2022
d413303
chore(package.json): <- adds `ENDPOINT` env var to compile cmd in that
gskapka Sep 27, 2022
299aa21
feat(vault): <- adds ETHPNT address to that & fxn to change it
gskapka Sep 27, 2022
476000e
feat(contracts): <- adds special handling to that for ETHPNT tokens o…
gskapka Sep 27, 2022
786d0d4
chore(linting): <- adds check for `only` in tests to that
gskapka Sep 27, 2022
7f3241d
ref(contract): <- improve new constants' names in that
gskapka Sep 27, 2022
6e49ecd
feat(contract): <- adds logic to handle ETHPNT peg ins & tests
gskapka Sep 27, 2022
18ee773
feat(ethpnt-pegins): <- adds check to normalized peg in address to that
gskapka Sep 27, 2022
18b938e
feat(tests): <- adds test for normalized PNT address being zero address
gskapka Sep 27, 2022
3b1284d
feat(contract): <- adds function to handle peg out token transfers
gskapka Sep 27, 2022
cd199e9
feat(contract): <- adds special handling for PNT token peg outs
gskapka Sep 27, 2022
e8199d5
ref(contract): <- simplify logic during pegouts
gskapka Sep 27, 2022
a283ed5
fix(pnt-peg-out): <- use correct EthPNT calculation in that
gskapka Sep 27, 2022
ff8e5a8
feat(ethpnt): <- adds tests for that
gskapka Sep 27, 2022
5200e03
fix(contract): <- update error message in that for accuracy
gskapka Sep 28, 2022
808cb43
feat(contract): <- the PNT is ERC777, so use the send with `userData`…
gskapka Sep 28, 2022
f8e5c55
feat(contract & tests): <- rm setters for PNT & EthPNT addresses
gskapka Sep 28, 2022
df4e648
chore(packages & linting): <- adds one of those to warn about skipped…
gskapka Sep 28, 2022
ac30a76
chore(tests): <- adds skips to those & note as to why
gskapka Sep 28, 2022
a7313ec
feat(contract): <- hardcode `PNT` and `EthPNT` addresses as constants…
gskapka Sep 28, 2022
a6e081d
chore(contract): <- elucidate notes in that
gskapka Sep 28, 2022
085ccd3
feat(existing-contracts): <- update eth mainnet one of that
gskapka Sep 28, 2022
ce85429
fix(vault): <- use correct `ethPNT` address in there
gskapka Sep 28, 2022
8766d8a
chore(package.json): <- bump minor version number in that
gskapka Sep 28, 2022
91a71c6
feat(vault): <- adds custom handling for GALA peg outs
gskapka May 16, 2023
ce5374a
feat(scripts): <- adds one of those to show storage slot layout
gskapka May 17, 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
8 changes: 7 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ module.exports = {
"ethers": false,
"upgrades": false,
},
plugins: [
'no-only-tests',
'no-skip-tests',
],
rules: {
"max-len": ["error", 120, 2, {
'no-skip-tests/no-skip-tests': 'warn',
'no-only-tests/no-only-tests': 'warn',
'max-len': ["error", 120, 2, {
ignoreUrls: true,
ignoreComments: false,
ignoreRegExpLiterals: true,
Expand Down
123 changes: 106 additions & 17 deletions contracts/Erc20Vault.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// SPDX-License-Identifier: MIT

// NOTE: This special version of the pTokens-erc20-vault is for ETH mainnet, and includes custom
// logic to handle ETHPNT<->PNT fungibility, as well as custom logic to handle GALA tokens after
// they upgraded from v1 to v2.

pragma solidity ^0.8.0;

import "./wEth/IWETH.sol";
Expand Down Expand Up @@ -30,6 +35,8 @@ contract Erc20Vault is
IWETH public weth;
bytes4 public ORIGIN_CHAIN_ID;
address private wEthUnwrapperAddress;
address public constant PNT_TOKEN_ADDRESS = 0x89Ab32156e46F46D02ade3FEcbe5Fc4243B9AAeD;
address public constant ETHPNT_TOKEN_ADDRESS = 0xf4eA6B892853413bD9d9f1a5D3a620A0ba39c5b2;

event PegIn(
address _tokenAddress,
Expand Down Expand Up @@ -146,15 +153,26 @@ contract Erc20Vault is
{
require(_tokenAmount > 0, "Token amount must be greater than zero!");
IERC20Upgradeable(_tokenAddress).safeTransferFrom(msg.sender, address(this), _tokenAmount);

// NOTE: This is the special handling of the EthPNT token, where a peg in of EthPNT will
// result in an event which will mint a PNT pToken on the other side of the bridge, thus
// making fungible the PNT & EthPNT tokens.
address normalizedTokenAddress = _tokenAddress == ETHPNT_TOKEN_ADDRESS
? PNT_TOKEN_ADDRESS
: _tokenAddress;

require(normalizedTokenAddress != address(0), "`normalizedTokenAddress` is set to zero address!");

emit PegIn(
_tokenAddress,
normalizedTokenAddress,
msg.sender,
_tokenAmount,
_destinationAddress,
_userData,
ORIGIN_CHAIN_ID,
_destinationChainId
);

return true;
}

Expand Down Expand Up @@ -263,14 +281,11 @@ contract Erc20Vault is
)
public
onlyPNetwork
returns (bool)
returns (bool success)
{
if (_tokenAddress == address(weth)) {
pegOutWeth(_tokenRecipient, _tokenAmount, "");
} else {
IERC20Upgradeable(_tokenAddress).safeTransfer(_tokenRecipient, _tokenAmount);
}
return true;
return _tokenAddress == address(weth)
? pegOutWeth(_tokenRecipient, _tokenAmount, "")
: pegOutTokens(_tokenAddress, _tokenRecipient, _tokenAmount, "");
}

function pegOut(
Expand All @@ -283,17 +298,91 @@ contract Erc20Vault is
onlyPNetwork
returns (bool success)
{
if (_tokenAddress == address(weth)) {
pegOutWeth(_tokenRecipient, _tokenAmount, _userData);
return _tokenAddress == address(weth)
? pegOutWeth(_tokenRecipient, _tokenAmount, _userData)
: pegOutTokens(_tokenAddress, _tokenRecipient, _tokenAmount, _userData);
}

function pegOutTokens(
address _tokenAddress,
address _tokenRecipient,
uint256 _tokenAmount,
bytes memory _userData
)
internal
returns (bool success)
{
if (_tokenAddress == PNT_TOKEN_ADDRESS) {
return handlePntPegOut(_tokenRecipient, _tokenAmount, _userData);
}

if (_tokenAddress == 0x15D4c048F83bd7e37d49eA4C83a07267Ec4203dA) { // NOTE: Gala v1
return handleGalaV1PegOut(_tokenRecipient, _tokenAmount);
}

if (tokenIsErc777(_tokenAddress)) {
// NOTE: This is an ERC777 token, so let's use its `send` function so that hooks are called...
IERC777Upgradeable(_tokenAddress).send(_tokenRecipient, _tokenAmount, _userData);
} else {
address erc777Address = _erc1820.getInterfaceImplementer(_tokenAddress, Erc777Token_INTERFACE_HASH);
if (erc777Address == address(0)) {
return pegOut(_tokenRecipient, _tokenAddress, _tokenAmount);
} else {
IERC777Upgradeable(erc777Address).send(_tokenRecipient, _tokenAmount, _userData);
return true;
}
// NOTE: Otherwise, we use standard ERC20 transfer function instead.
IERC20Upgradeable(_tokenAddress).safeTransfer(_tokenRecipient, _tokenAmount);
}

return true;
}

function tokenIsErc777(address _tokenAddress) view internal returns (bool) {
return _erc1820.getInterfaceImplementer(_tokenAddress, Erc777Token_INTERFACE_HASH) != address(0);
}

function handleGalaV1PegOut(
address _tokenRecipient,
uint256 _tokenAmount
)
internal
returns (bool success)
{
// NOTE: Neither Gala tokens implement hooks so we use a basic ERC20 transfer.

IERC20Upgradeable(0x15D4c048F83bd7e37d49eA4C83a07267Ec4203dA) // NOTE Gala v1
.safeTransfer(_tokenRecipient, _tokenAmount);

IERC20Upgradeable(0xd1d2Eb1B1e90B638588728b4130137D262C87cae) // NOTE Gala v2
.safeTransfer(_tokenRecipient, _tokenAmount);

return true;
}

function handlePntPegOut(
address _tokenRecipient,
uint256 _tokenAmount,
bytes memory _userData
)
internal
returns (bool success)
{
// NOTE: The PNT contract is ERC777...
IERC777Upgradeable pntContract = IERC777Upgradeable(PNT_TOKEN_ADDRESS);
// NOTE: Whilst the EthPNT contract is ERC20.
IERC20Upgradeable ethPntContract = IERC20Upgradeable(ETHPNT_TOKEN_ADDRESS);

// NOTE: First we need to know how much PNT this vault holds...
uint256 vaultPntTokenBalance = pntContract.balanceOf(address(this));

if (_tokenAmount <= vaultPntTokenBalance) {
// NOTE: If we can peg out _entirely_ with PNT tokens, we do so...
pntContract.send(_tokenRecipient, _tokenAmount, _userData);
} else if (vaultPntTokenBalance == 0) {
// NOTE: Here we must peg out entirely with ETHPNT tokens instead...
ethPntContract.safeTransfer(_tokenRecipient, _tokenAmount);
} else {
// NOTE: And so here we must peg out the total using as much PNT as possible, with
// the remainder being sent as EthPNT...
pntContract.send(_tokenRecipient, vaultPntTokenBalance, _userData);
ethPntContract.safeTransfer(_tokenRecipient, _tokenAmount - vaultPntTokenBalance);
}

return true;
}

receive() external payable { }
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
const { assoc } = require('ramda')

require('hardhat-erc1820')
require('hardhat-storage-layout')
require('@nomiclabs/hardhat-waffle')
require('@nomiclabs/hardhat-etherscan')
require('@openzeppelin/hardhat-upgrades')
Expand Down
2 changes: 1 addition & 1 deletion lib/show-existing-contract-addresses.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const EXISTING_LOGIC_CONTRACT_ADDRESSES = [
{ 'version': 'v2', 'chain': 'ropsten', 'address': '0x2Ea67a02058c3A0CE5f774949b6E8741B8D0a399' },
{ 'version': 'v2', 'chain': 'rinkeby', 'address': '0x6819bbFdf803B8b87850916d3eEB3642DdE6C24F' },
{ 'version': 'v2', 'chain': 'interim', 'address': '0xeEa7CE353a076898E35E82609e45918B5e4d0e0A' },
{ 'version': 'v2', 'chain': 'ethereum', 'address': '0xE01a9c36170b8Fa163C6a54D7aB3015C85e0186c' },
{ 'version': 'v2', 'chain': 'ethereum', 'address': '0xfbc347975C48578F4A25ECeEB61BC16356abE8a2' },
{ 'version': 'v2', 'chain': 'goerli', 'address': '0xEa1FFBf0715FE7ccaae5d57dC698550f23581a27' },
{ 'version': 'v2', 'chain': 'sepolia', 'address': '0x9fdbc63D5250Aa59cb6d5382eF4e92113fE1FC35' },
]
Expand Down
88 changes: 86 additions & 2 deletions package-lock.json

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

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "ptokens-erc20-vault-smart-contract",
"version": "2.7.0",
"version": "2.8.0",
"description": "The pToken ERC20 vault smart-contract & CLI",
"main": "cli.js",
"scripts": {
"lint": "npx eslint .",
"test": "npm run tests",
"tests": "ENDPOINT=http://localhost:8545 npx hardhat test",
"compile": "npx hardhat compile",
"lint": "npx eslint ."
"compile": "ENDPOINT=http://localhost:8545 npx hardhat compile",
"showStorage": "ENDPOINT=http://localhost:8545 node ./scripts/show-storage-layout.js"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -45,10 +46,13 @@
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-mocha": "^5.3.0",
"eslint-plugin-no-only-tests": "^3.0.0",
"eslint-plugin-no-skip-tests": "^1.1.0",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-standard": "^4.1.0",
"ethereum-waffle": "^3.4.4",
"hardhat-storage-layout": "^0.1.7",
"mocha": "^6.2.3"
}
}
Loading