-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
147 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright BigchainDB GmbH and Ocean Protocol contributors | ||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) | ||
// Code is Apache-2.0 and docs are CC-BY-4.0 | ||
|
||
|
||
pragma solidity 0.8.12; | ||
|
||
|
||
interface IERC20 { | ||
function transfer(address to, uint256 value) external returns (bool); | ||
function transferFrom(address from, address to, uint256 value) external returns (bool); | ||
} | ||
|
||
|
||
contract BatchPayments { | ||
function sendEther(address[] memory list, uint256[] memory amounts) external payable { | ||
require(list.length == amounts.length,"Arrays must have same length"); | ||
for (uint256 i = 0; i < list.length; i++) | ||
payable(list[i]).transfer(amounts[i]); | ||
uint256 balance = address(this).balance; | ||
// make sure that we return any excess to the caller | ||
// Later TODO: Check for gas | ||
if (balance > 0) | ||
payable(msg.sender).transfer(balance); | ||
} | ||
Check failure Code scanning / Slither Functions that send Ether to arbitrary destinations High
BatchPayments.sendEther(address[],uint256[]) sends eth to arbitrary user
Dangerous calls: - address(list[i]).transfer(amounts[i]) - address(msg.sender).call{value: balance}() Check notice Code scanning / Slither Calls inside a loop Low
BatchPayments.sendEther(address[],uint256[]) has external calls inside a loop: address(list[i]).transfer(amounts[i])
|
||
|
||
function sendToken(IERC20 token, address[] memory list, uint256[] memory amounts) external { | ||
require(list.length == amounts.length,"Arrays must have same length"); | ||
uint256 total = 0; | ||
uint256 i; | ||
for (i = 0; i < list.length; i++) | ||
total += amounts[i]; | ||
require(token.transferFrom(msg.sender, address(this), total)); | ||
for (i = 0; i < list.length; i++) | ||
require(token.transfer(list[i], amounts[i])); | ||
} | ||
Check notice Code scanning / Slither Calls inside a loop Low
BatchPayments.sendToken(IERC20,address[],uint256[]) has external calls inside a loop: require(bool)(token.transfer(list[i],amounts[i]))
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
const { expect } = require('chai'); | ||
const { ethers } = require("hardhat"); | ||
const { json } = require('hardhat/internal/core/params/argumentTypes'); | ||
const { web3 } = require("@openzeppelin/test-helpers/src/setup"); | ||
|
||
// Start test block | ||
describe('Booster tests', function () { | ||
let Mock20Contract; | ||
let Mock20DecimalsContract; | ||
let BatchPaymentsContract; | ||
let signers; | ||
before(async function () { | ||
// Get the contractOwner and collector address | ||
signers = await ethers.getSigners(); | ||
const MockErc20 = await ethers.getContractFactory('MockERC20'); | ||
const MockErc20Decimals = await ethers.getContractFactory('MockERC20Decimals'); | ||
const BatchPayments = await ethers.getContractFactory('BatchPayments'); | ||
Mock20Contract = await MockErc20.deploy(signers[0].address,"MockERC20", 'MockERC20'); | ||
Mock20DecimalsContract = await MockErc20Decimals.deploy("Mock6Digits", 'Mock6Digits', 6); | ||
BatchPaymentsContract = await BatchPayments.deploy(); | ||
|
||
|
||
}); | ||
|
||
|
||
// Test cases | ||
it('Check contract deployment', async function () { | ||
expect(await BatchPaymentsContract.address).to.exist; | ||
|
||
}); | ||
|
||
it('Should transfer tokens in batch', async function () { | ||
const addresses = [signers[1].address, signers[2].address, signers[3].address]; | ||
const amounts = [web3.utils.toWei("100"), web3.utils.toWei("200"), web3.utils.toWei("300")]; | ||
|
||
// Approve the BatchPayments contract to transfer tokens | ||
await Mock20Contract.approve(BatchPaymentsContract.address, web3.utils.toWei("10000")); | ||
|
||
// Perform the batch transfer | ||
await BatchPaymentsContract.sendToken(Mock20Contract.address, addresses, amounts); | ||
|
||
// Check balances | ||
expect(await Mock20Contract.balanceOf(signers[1].address)).to.equal(web3.utils.toWei("100")); | ||
expect(await Mock20Contract.balanceOf(signers[2].address)).to.equal(web3.utils.toWei("200")); | ||
expect(await Mock20Contract.balanceOf(signers[3].address)).to.equal(web3.utils.toWei("300")); | ||
}); | ||
|
||
it('Should revert if arrays length mismatch', async function () { | ||
const addresses = [signers[1].address, signers[2].address]; | ||
const amounts = [web3.utils.toWei("100"), web3.utils.toWei("200"), web3.utils.toWei("300")]; | ||
|
||
// Approve the BatchPayments contract to transfer tokens | ||
await Mock20Contract.approve(BatchPaymentsContract.address, web3.utils.toWei("10000")); | ||
|
||
// Perform the batch transfer | ||
await expect(BatchPaymentsContract.sendToken(Mock20Contract.address, addresses, amounts)).to.be.revertedWith("Arrays must have same length"); | ||
|
||
}); | ||
|
||
it('Should revert if transfer fails', async function () { | ||
const addresses = [signers[1].address, signers[2].address, signers[3].address]; | ||
const amounts = [web3.utils.toWei("100"), web3.utils.toWei("200"), web3.utils.toWei("1300")]; | ||
|
||
// Approve the BatchPayments contract to transfer tokens - insufficient amount | ||
await Mock20Contract.approve(BatchPaymentsContract.address, web3.utils.toWei("1000")); | ||
|
||
// Perform the batch transfer | ||
await expect(BatchPaymentsContract.sendToken(Mock20Contract.address, addresses, amounts)).to.be.revertedWith("ERC20: insufficient allowance"); | ||
|
||
}); | ||
|
||
it('Should handle tokens with decimals correctly', async function () { | ||
const addresses = [signers[1].address, signers[2].address, signers[3].address]; | ||
const amounts = [ | ||
ethers.utils.parseUnits("100", 6), | ||
ethers.utils.parseUnits("200", 6), | ||
ethers.utils.parseUnits("300", 6) | ||
]; | ||
|
||
// Approve the BatchPayments contract to transfer tokens | ||
await Mock20DecimalsContract.approve(BatchPaymentsContract.address, ethers.utils.parseUnits("10000", 6)); | ||
|
||
// Perform the batch transfer | ||
await BatchPaymentsContract.sendToken(Mock20DecimalsContract.address, addresses, amounts); | ||
|
||
// Check balances | ||
expect(await Mock20DecimalsContract.balanceOf(signers[1].address)).to.equal(ethers.utils.parseUnits("100", 6)); | ||
expect(await Mock20DecimalsContract.balanceOf(signers[2].address)).to.equal(ethers.utils.parseUnits("200", 6)); | ||
expect(await Mock20DecimalsContract.balanceOf(signers[3].address)).to.equal(ethers.utils.parseUnits("300", 6)); | ||
}); | ||
|
||
it('Should transfer native ETH in batch', async function () { | ||
const addresses = [signers[1].address, signers[2].address, signers[3].address]; | ||
const amounts = [ethers.utils.parseEther("0.1"), ethers.utils.parseEther("0.2"), ethers.utils.parseEther("0.3")]; | ||
|
||
const initialBalances = await Promise.all(addresses.map(addr => ethers.provider.getBalance(addr))); | ||
|
||
// Perform the batch transfer | ||
await BatchPaymentsContract.sendEther(addresses, amounts, { value: ethers.utils.parseEther("0.6") }); | ||
|
||
// Check balances | ||
const finalBalances = await Promise.all(addresses.map(addr => ethers.provider.getBalance(addr))); | ||
expect(finalBalances[0]).to.equal(initialBalances[0].add(amounts[0])); | ||
expect(finalBalances[1]).to.equal(initialBalances[1].add(amounts[1])); | ||
expect(finalBalances[2]).to.equal(initialBalances[2].add(amounts[2])); | ||
}); | ||
|
||
|
||
|
||
}); |