Skip to content

Commit

Permalink
feat(ERC777): <- add custom function call when minting
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviera9 committed Jan 29, 2024
1 parent 3c13579 commit 37ac0d0
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 10 deletions.
16 changes: 16 additions & 0 deletions contracts/interfaces/IPReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pragma solidity ^0.6.2;

/**
* @title IPReceiver
* @author pNetwork
*
* @dev Interface for contracts excpecting cross-chain data
*/
interface IPReceiver {
/*
* @dev Function called when userData.length > 0 when minting the pToken
*
* @param userData
*/
function receiveUserData(bytes calldata userData) external;
}
6 changes: 6 additions & 0 deletions contracts/pToken.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pragma solidity ^0.6.2;

import {IPReceiver} from "./interfaces/IPReceiver.sol";
import "./ERC777GSN.sol";
import "./ERC777WithAdminOperatorUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
Expand Down Expand Up @@ -76,6 +77,11 @@ contract PToken is
"Recipient cannot be the token contract address!"
);
_mint(recipient, value, userData, operatorData);
if (userData.length > 0) {
// TODO: check if this is needed, and, eventually, replace .code with a function
// require(recipient.code.length > 0, "Recipient is not a contract");
try IPReceiver(recipient).receiveUserData(userData) {} catch {}
}
return true;
}

Expand Down
6 changes: 6 additions & 0 deletions contracts/pTokenNoGSN.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pragma solidity ^0.6.2;

import {IPReceiver} from "./interfaces/IPReceiver.sol";
import "./ERC777WithAdminOperatorUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
Expand Down Expand Up @@ -79,6 +80,11 @@ contract PTokenNoGSN is
"Recipient cannot be the token contract address!"
);
_mint(recipient, value, userData, operatorData);
if (userData.length > 0) {
// TODO: check if this is needed, and, eventually, replace .code with a function
// require(recipient.code.length > 0, "Recipient is not a contract");
try IPReceiver(recipient).receiveUserData(userData) {} catch {}
}
return true;
}

Expand Down
11 changes: 11 additions & 0 deletions contracts/test/PReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pragma solidity ^0.6.2;

import {IPReceiver} from "../interfaces/IPReceiver.sol";

contract PReceiver is IPReceiver {
event UserData(bytes data);

function receiveUserData(bytes calldata userData) external override {
emit UserData(userData);
}
}
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ptokens-erc777-smart-contract",
"version": "3.11.1",
"version": "3.12.0",
"description": "The pToken ERC777 smart-contract & CLI",
"main": "cli.js",
"scripts": {
Expand Down
34 changes: 27 additions & 7 deletions test/05-ptoken.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,20 +145,40 @@ USE_GSN.map(_useGSN =>
}
})

it('`mint()` w/ data should mint tokens & emit correct events', async () => {
it('`mint()` w/ data should revert if receiver is not a contract', async () => {
const data = '0xdead'
const expectedNumEvents = 2
const operatorData = '0xb33f'
const recipient = OTHERS[0].address
const recipientBalanceBefore = await getTokenBalance(recipient, CONTRACT)
const tx = await CONTRACT['mint(address,uint256,bytes,bytes)'](recipient, AMOUNT, data, operatorData)
try {
const tx = await CONTRACT['mint(address,uint256,bytes,bytes)'](recipient, AMOUNT, data, operatorData)
await tx.wait()
assert.fail('Should not succeed!')
} catch (_err) {
const expectedErr = 'Transaction reverted: function call to a non-contract account'
assert(_err.message.includes(expectedErr))
}
})

it('`mint()` w/ data should mint tokens & emit correct events', async () => {
const data = '0xdead'
const expectedNumEvents = 3
const operatorData = '0xb33f'
const recipientContract = await ethers
.getContractFactory('PReceiver')
.then(_factory => upgrades.deployProxy(_factory))

const recipientBalanceBefore = await getTokenBalance(recipientContract.address, CONTRACT)
const tx =
await CONTRACT['mint(address,uint256,bytes,bytes)'](recipientContract.address, AMOUNT, data, operatorData)
const { events } = await tx.wait()
const recipientBalanceAfter = await getTokenBalance(recipient, CONTRACT)
const recipientBalanceAfter = await getTokenBalance(recipientContract.address, CONTRACT)
assert(recipientBalanceBefore.eq(BigNumber.from(0)))
assert(recipientBalanceAfter.eq(BigNumber.from(AMOUNT)))
assert.strictEqual(events.length, expectedNumEvents)
assertTransferEvent(events, ZERO_ADDRESS, recipient, AMOUNT)
assertMintEvent(events, recipient, OWNER.address, AMOUNT, data, operatorData)
assertTransferEvent(events, ZERO_ADDRESS, recipientContract.address, AMOUNT)
assertMintEvent(events, recipientContract.address, OWNER.address, AMOUNT, data, operatorData)
const userDataevent = recipientContract.interface.parseLog(events.at(-1))
assert.strictEqual(userDataevent.args.data, data)
})

it('Should revert when minting tokens with the contract address as the recipient', async () => {
Expand Down

0 comments on commit 37ac0d0

Please sign in to comment.