Skip to content

Commit

Permalink
Merge pull request #12 from provable-things/peg-in-user-data
Browse files Browse the repository at this point in the history
feat(user-data): <- adds field for that on peg ins
  • Loading branch information
gskapka authored Mar 26, 2021
2 parents fad4b0b + e870d43 commit 7ecc833
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 24 deletions.
37 changes: 33 additions & 4 deletions contracts/PERC20OnEosVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ contract PERC20OnEosVault is Withdrawable, IERC777Recipient {
address public PNETWORK;
IWETH public weth;

event PegIn(address _tokenAddress, address _tokenSender, uint256 _tokenAmount, string _destinationAddress);
event PegIn(
address _tokenAddress,
address _tokenSender,
uint256 _tokenAmount,
string _destinationAddress,
bytes _userData
);

constructor(
address _weth,
Expand Down Expand Up @@ -97,11 +103,23 @@ contract PERC20OnEosVault is Withdrawable, IERC777Recipient {
)
external
returns (bool)
{
return pegIn(_tokenAmount, _tokenAddress, _destinationAddress, "");
}

function pegIn(
uint256 _tokenAmount,
address _tokenAddress,
string memory _destinationAddress,
bytes memory _userData
)
public
returns (bool)
{
require(supportedTokens.contains(_tokenAddress), "Token at supplied address is NOT supported!");
require(_tokenAmount > 0, "Token amount must be greater than zero!");
IERC20(_tokenAddress).safeTransferFrom(msg.sender, address(this), _tokenAmount);
emit PegIn(_tokenAddress, msg.sender, _tokenAmount, _destinationAddress);
emit PegIn(_tokenAddress, msg.sender, _tokenAmount, _destinationAddress, _userData);
return true;
}

Expand All @@ -123,19 +141,30 @@ contract PERC20OnEosVault is Withdrawable, IERC777Recipient {
require(amount > 0, "Token amount must be greater than zero!");
(bytes32 tag, string memory _destinationAddress) = abi.decode(userData, (bytes32, string));
require(tag == keccak256("ERC777-pegIn"), "Invalid tag for automatic pegIn on ERC777 send");
emit PegIn(_tokenAddress, from, amount, _destinationAddress);
emit PegIn(_tokenAddress, from, amount, _destinationAddress, userData);
}
}

function pegInEth(string calldata _destinationAddress)
external
payable
returns (bool)
{
return pegInEth(_destinationAddress, "");
}

function pegInEth(
string memory _destinationAddress,
bytes memory _userData
)
public
payable
returns (bool)
{
require(supportedTokens.contains(address(weth)), "WETH is NOT supported!");
require(msg.value > 0, "Ethers amount must be greater than zero!");
weth.deposit.value(msg.value)();
emit PegIn(address(weth), msg.sender, msg.value, _destinationAddress);
emit PegIn(address(weth), msg.sender, msg.value, _destinationAddress, _userData);
return true;
}

Expand Down
4 changes: 1 addition & 3 deletions migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ require('@openzeppelin/test-helpers/configure')({
})

module.exports = async (_deployer, _network, _accounts) => {
if (_network.includes('develop')) {
await singletons.ERC1820Registry(_accounts[0])
}
if (_network.includes('develop')) await singletons.ERC1820Registry(_accounts[0])
_deployer.deploy(artifacts.require('PERC20OnEosVault.sol'), '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', [])
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ptokens-perc20-smart-contract",
"version": "1.2.0",
"version": "1.4.0",
"description": "The pToken pERC20-on-EOS-vault smart-contract",
"main": "index.js",
"scripts": {
Expand Down
108 changes: 92 additions & 16 deletions test/ptokens-erc777-proxy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const WETH_ARTIFACT = artifacts.require('WETH')
const PERC20OnEosVaultArtifact = artifacts.require('PERC20OnEosVault')
const { expectRevert } = require('@openzeppelin/test-helpers')

const GAS_LIMIT = 3e6

const getContract = (_web3, _artifact, _constructorParams = []) =>
new Promise((resolve, reject) =>
_artifact
Expand All @@ -18,29 +20,49 @@ const getContract = (_web3, _artifact, _constructorParams = []) =>
const getRandomEthAddress = _web3 =>
_web3.utils.randomHex(20)

const addTokenSupport = (_pErc20Methods, _tokenAddress, _from, _gasLimit = 3e6) =>
const addTokenSupport = (_pErc20Methods, _tokenAddress, _from, _gasLimit = GAS_LIMIT) =>
_pErc20Methods.addSupportedToken(_tokenAddress).send({ from: _from, gas: _gasLimit })

const givePErc20Allowance = (_tokenMethods, _holderAddress, _spenderAddress, _tokenAmount, _gasLimit = 3e6) =>
const givePErc20Allowance = (_tokenMethods, _holderAddress, _spenderAddress, _tokenAmount, _gasLimit = GAS_LIMIT) =>
_tokenMethods.approve(_spenderAddress, _tokenAmount).send({ from: _holderAddress, gas: _gasLimit })

const assertPegInEvent = (_pegInEvent, _tokenAddress, _tokenSender, _tokenAmount, _destinationAddress) => {
const assertPegInEvent = (
_pegInEvent,
_tokenAddress,
_tokenSender,
_tokenAmount,
_destinationAddress,
_userData = null,
) => {
assert.strictEqual(_pegInEvent.returnValues._tokenAddress, _tokenAddress)
assert.strictEqual(_pegInEvent.returnValues._tokenSender, _tokenSender)
assert.strictEqual(_pegInEvent.returnValues._tokenAmount, `${_tokenAmount}`)
assert.strictEqual(_pegInEvent.returnValues._destinationAddress, _destinationAddress)
assert.strictEqual(_pegInEvent.returnValues._userData, _userData)
}

const pegIn = (_pErc20Methods, _tokenAddress, _tokenAmount, _tokenHolder, _destinationAddress, _gasLimit = 3e6) =>
const pegIn = (_pErc20Methods, _tokenAddress, _tokenAmount, _tokenHolder, _destinationAddress, _gasLimit = GAS_LIMIT) =>
_pErc20Methods
.pegIn(_tokenAmount, _tokenAddress, _destinationAddress)
.send({ from: _tokenHolder, gas: _gasLimit })

const pegInWithUserData = (
_pErc20Methods,
_tokenAddress,
_tokenAmount,
_tokenHolder,
_destinationAddress,
_userData,
_gasLimit = GAS_LIMIT
) =>
_pErc20Methods['pegIn(uint256,address,string,bytes)'](_tokenAmount, _tokenAddress, _destinationAddress, _userData)
.send({ from: _tokenHolder, gas: _gasLimit })

contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRESS, ...ACCOUNTS]) => {
const GAS_LIMIT = 3e6
const TOKEN_AMOUNT = 1337
const USER_DATA = '0x1337'
const TOKEN_HOLDER_BALANCE = 1e6
const DESTINATION_ADDRESS = 'EOS_ADDRESS'
const DESTINATION_ADDRESS = 'aneosaddress'
const NON_PNETWORK_ERR = 'Caller must be PNETWORK address!'
const MIGRATION_DESTINATION_ADDRESS = getRandomEthAddress(web3)
const INSUFFICIENT_BALANCE_ERR = 'ERC20: transfer amount exceeds balance'
Expand Down Expand Up @@ -201,7 +223,11 @@ contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRES

it('Token addresses sent to constructor should be supported', async () => {
const supportedTokenAddresses = [getRandomEthAddress(web3), getRandomEthAddress(web3)]
const newContract = await getContract(web3, PERC20OnEosVaultArtifact, [weth.options.address, supportedTokenAddresses])
const newContract = await getContract(
web3,
PERC20OnEosVaultArtifact,
[weth.options.address, supportedTokenAddresses]
)
const tokensAreSupportedBools = await Promise.all(
supportedTokenAddresses.map(_address => newContract.methods.IS_TOKEN_SUPPORTED(_address))
)
Expand All @@ -218,7 +244,9 @@ contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRES
const pErc20TokenBalanceAfterPegIn = await tokenMethods.balanceOf(PERC20_ADDRESS).call()
assert.strictEqual(parseInt(pErc20TokenBalanceAfterPegIn), parseInt(pErc20TokenBalanceBeforePegIn) + TOKEN_AMOUNT)
assert.strictEqual(parseInt(migratedAddressTokenBalanceBefore), 0)
await pErc20Methods.migrateSingle(MIGRATION_DESTINATION_ADDRESS, TOKEN_ADDRESS).send({ from: PNETWORK_ADDRESS, gas: GAS_LIMIT })
await pErc20Methods
.migrateSingle(MIGRATION_DESTINATION_ADDRESS, TOKEN_ADDRESS)
.send({ from: PNETWORK_ADDRESS, gas: GAS_LIMIT })
const migratedAddressTokenBalanceAfter = await tokenMethods.balanceOf(MIGRATION_DESTINATION_ADDRESS).call()
assert.strictEqual(parseInt(migratedAddressTokenBalanceAfter), TOKEN_AMOUNT)
})
Expand Down Expand Up @@ -260,7 +288,13 @@ contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRES
await pErc20Methods.addSupportedToken(erc777.options.address).send({ from: PNETWORK_ADDRESS, gas: GAS_LIMIT })

await erc777.methods.approve(PERC20_ADDRESS, TOKEN_AMOUNT).send({ from: TOKEN_HOLDER_ADDRESS })
const tx = await pegIn(pErc20Methods, erc777.options.address, TOKEN_AMOUNT, TOKEN_HOLDER_ADDRESS, DESTINATION_ADDRESS)
const tx = await pegIn(
pErc20Methods,
erc777.options.address,
TOKEN_AMOUNT,
TOKEN_HOLDER_ADDRESS,
DESTINATION_ADDRESS
)
assertPegInEvent(tx.events.PegIn, erc777.options.address, TOKEN_HOLDER_ADDRESS, TOKEN_AMOUNT, DESTINATION_ADDRESS)
})

Expand All @@ -270,7 +304,13 @@ contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRES
await givePErc20Allowance(erc777.methods, TOKEN_HOLDER_ADDRESS, PERC20_ADDRESS, TOKEN_AMOUNT)
const migratedAddressTokenBalanceBefore = await erc777.methods.balanceOf(MIGRATION_DESTINATION_ADDRESS).call()
const pErc20TokenBalanceBeforePegIn = await erc777.methods.balanceOf(PERC20_ADDRESS).call()
const tx = await pegIn(pErc20Methods, erc777.options.address, TOKEN_AMOUNT, TOKEN_HOLDER_ADDRESS, DESTINATION_ADDRESS)
const tx = await pegIn(
pErc20Methods,
erc777.options.address,
TOKEN_AMOUNT,
TOKEN_HOLDER_ADDRESS,
DESTINATION_ADDRESS
)
assertPegInEvent(tx.events.PegIn, erc777.options.address, TOKEN_HOLDER_ADDRESS, TOKEN_AMOUNT, DESTINATION_ADDRESS)
const pErc20TokenBalanceAfterPegIn = await erc777.methods.balanceOf(PERC20_ADDRESS).call()
assert.strictEqual(parseInt(pErc20TokenBalanceAfterPegIn), parseInt(pErc20TokenBalanceBeforePegIn) + TOKEN_AMOUNT)
Expand All @@ -282,9 +322,9 @@ contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRES

it('Should peg in weth', async () => {
await addTokenSupport(pErc20Methods, weth.options.address, PNETWORK_ADDRESS)

const tx = await pErc20Methods.pegInEth(DESTINATION_ADDRESS).send({ from: TOKEN_HOLDER_ADDRESS, value: TOKEN_AMOUNT })

const tx = await pErc20Methods
.pegInEth(DESTINATION_ADDRESS)
.send({ from: TOKEN_HOLDER_ADDRESS, value: TOKEN_AMOUNT })
assertPegInEvent(tx.events.PegIn, weth.options.address, TOKEN_HOLDER_ADDRESS, TOKEN_AMOUNT, DESTINATION_ADDRESS)
assert.strictEqual(await weth.methods.balanceOf(PERC20_ADDRESS).call(), TOKEN_AMOUNT.toString())
assert.strictEqual(await web3.eth.getBalance(PERC20_ADDRESS), '0', 'eth balance must be 0')
Expand All @@ -294,12 +334,48 @@ contract('PERC20', ([PNETWORK_ADDRESS, NON_PNETWORK_ADDRESS, TOKEN_HOLDER_ADDRES
await addTokenSupport(pErc20Methods, weth.options.address, PNETWORK_ADDRESS)
await pErc20Methods.pegInEth(DESTINATION_ADDRESS).send({ from: TOKEN_HOLDER_ADDRESS, value: TOKEN_AMOUNT })
const ethBalanceBefore = await web3.eth.getBalance(TOKEN_HOLDER_ADDRESS)

await pErc20Methods.pegOut(TOKEN_HOLDER_ADDRESS, weth.options.address, TOKEN_AMOUNT).send({ from: PNETWORK_ADDRESS })

await pErc20Methods
.pegOut(TOKEN_HOLDER_ADDRESS, weth.options.address, TOKEN_AMOUNT)
.send({ from: PNETWORK_ADDRESS })
assert.strictEqual(await weth.methods.balanceOf(PERC20_ADDRESS).call(), '0')
assert.strictEqual(await web3.eth.getBalance(PERC20_ADDRESS), '0', 'eth balance must be 0')
const expectedEthBalance = web3.utils.toBN(ethBalanceBefore).add(web3.utils.toBN(TOKEN_AMOUNT)).toString()
assert.strictEqual(await web3.eth.getBalance(TOKEN_HOLDER_ADDRESS), expectedEthBalance)
})

it('Should peg in with user data', async () => {
await addTokenSupport(pErc20Methods, TOKEN_ADDRESS, PNETWORK_ADDRESS)
await givePErc20Allowance(tokenMethods, TOKEN_HOLDER_ADDRESS, PERC20_ADDRESS, TOKEN_AMOUNT)
const tokenHolderBalanceBeforePegIn = await tokenMethods.balanceOf(TOKEN_HOLDER_ADDRESS).call()
const pErc20TokenBalanceBeforePegIn = await tokenMethods.balanceOf(PERC20_ADDRESS).call()
const tx = await pegInWithUserData(
pErc20Methods,
TOKEN_ADDRESS,
TOKEN_AMOUNT,
TOKEN_HOLDER_ADDRESS,
DESTINATION_ADDRESS,
USER_DATA,
)
assertPegInEvent(tx.events.PegIn, TOKEN_ADDRESS, TOKEN_HOLDER_ADDRESS, TOKEN_AMOUNT, DESTINATION_ADDRESS, USER_DATA)
const pErc20TokenBalanceAfterPegIn = await tokenMethods.balanceOf(PERC20_ADDRESS).call()
const tokenHolderBalanceAfterPegIn = await tokenMethods.balanceOf(TOKEN_HOLDER_ADDRESS).call()
assert.strictEqual(parseInt(pErc20TokenBalanceAfterPegIn), parseInt(pErc20TokenBalanceBeforePegIn) + TOKEN_AMOUNT)
assert.strictEqual(parseInt(tokenHolderBalanceAfterPegIn), parseInt(tokenHolderBalanceBeforePegIn) - TOKEN_AMOUNT)
})

it('Should peg in weth with user data', async () => {
await addTokenSupport(pErc20Methods, weth.options.address, PNETWORK_ADDRESS)
const tx = await pErc20Methods['pegInEth(string,bytes)'](DESTINATION_ADDRESS, USER_DATA)
.send({ from: TOKEN_HOLDER_ADDRESS, value: TOKEN_AMOUNT })
assertPegInEvent(
tx.events.PegIn,
weth.options.address,
TOKEN_HOLDER_ADDRESS,
TOKEN_AMOUNT,
DESTINATION_ADDRESS,
USER_DATA
)
assert.strictEqual(await weth.methods.balanceOf(PERC20_ADDRESS).call(), TOKEN_AMOUNT.toString())
assert.strictEqual(await web3.eth.getBalance(PERC20_ADDRESS), '0', 'eth balance must be 0')
})
})

0 comments on commit 7ecc833

Please sign in to comment.