Skip to content

Commit

Permalink
feat: ethereum fee proxy with transfer exact eth amount (#591)
Browse files Browse the repository at this point in the history
  • Loading branch information
vrolland committed Sep 24, 2021
1 parent 8607627 commit eb08b85
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 5 deletions.
44 changes: 39 additions & 5 deletions packages/smart-contracts/src/contracts/EthereumFeeProxy.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

/**
* @title EthereumFeeProxy
* @notice This contract performs an Ethereum transfer with a Fee sent to a third address and stores a reference
*/
contract EthereumFeeProxy {
contract EthereumFeeProxy is ReentrancyGuard{
// Event to declare a transfer with a reference
event TransferWithReferenceAndFee(
address to,
Expand All @@ -15,12 +17,12 @@ contract EthereumFeeProxy {
address feeAddress
);


// Fallback function returns funds to the sender
receive() external payable {
revert("not payable receive");
}


/**
* @notice Performs an Ethereum transfer with a reference
* @param _to Transfer recipient
Expand All @@ -37,8 +39,40 @@ contract EthereumFeeProxy {
external
payable
{
_to.transfer(msg.value - _feeAmount);
transferExactEthWithReferenceAndFee(
_to,
msg.value - _feeAmount,
_paymentReference,
_feeAmount,
_feeAddress
);
}


/**
* @notice Performs an Ethereum transfer with a reference with an exact amount of eth
* @param _to Transfer recipient
* @param _amount Amount to transfer
* @param _paymentReference Reference of the payment related
* @param _feeAmount The amount of the payment fee (part of the msg.value)
* @param _feeAddress The fee recipient
*/
function transferExactEthWithReferenceAndFee(
address payable _to,
uint256 _amount,
bytes calldata _paymentReference,
uint256 _feeAmount,
address payable _feeAddress
)
nonReentrant
public
payable
{
_to.transfer(_amount);
_feeAddress.transfer(_feeAmount);
emit TransferWithReferenceAndFee(_to, msg.value - _feeAmount, _paymentReference, _feeAmount, _feeAddress);
// transfer the remaining ethers to the sender
payable(msg.sender).transfer(msg.value - _amount - _feeAmount);

emit TransferWithReferenceAndFee(_to, _amount, _paymentReference, _feeAmount, _feeAddress);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,39 @@
"name": "TransferWithReferenceAndFee",
"type": "event"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_paymentReference",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_feeAmount",
"type": "uint256"
},
{
"internalType": "address payable",
"name": "_feeAddress",
"type": "address"
}
],
"name": "transferExactEthWithReferenceAndFee",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
Expand Down
21 changes: 21 additions & 0 deletions packages/smart-contracts/test/contracts/EthereumFeeProxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ describe('contract: EthereumFeeProxy', () => {
expect(contractBalance.toString()).to.equals("0");
});

it('allows to pays exact eth with a reference with extra msg.value', async () => {
const toOldBalance = await provider.getBalance(to);
const feeAddressOldBalance = await provider.getBalance(feeAddress);

await expect(
ethFeeProxy.transferExactEthWithReferenceAndFee(to, amount, referenceExample, feeAmount, feeAddress, {
value: amount.add(feeAmount).add('10000'),
}),
).to.emit(ethFeeProxy, 'TransferWithReferenceAndFee')
.withArgs(to, amount.toString(), ethers.utils.keccak256(referenceExample), feeAmount.toString(), feeAddress);

const toNewBalance = await provider.getBalance(to);
const feeAddressNewBalance = await provider.getBalance(feeAddress);
const contractBalance = await provider.getBalance(ethFeeProxy.address);

// Check balance changes
expect(toNewBalance.toString()).to.equals(toOldBalance.add(amount).toString());
expect(feeAddressNewBalance.toString()).to.equals(feeAddressOldBalance.add(feeAmount).toString());
expect(contractBalance.toString()).to.equals("0");
});

it('cannot transfer if msg.value is too low', async () => {
await expect(
ethFeeProxy.transferWithReferenceAndFee(to, referenceExample, amount, feeAddress, {
Expand Down

0 comments on commit eb08b85

Please sign in to comment.