Skip to content

Commit

Permalink
batch payments contract
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcos20 committed Sep 16, 2024
1 parent cbe3a1e commit a0ab110
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 0 deletions.
37 changes: 37 additions & 0 deletions contracts/rewards/BatchPayments.sol
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

Check notice

Code scanning / Slither

Calls inside a loop Low


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

}
110 changes: 110 additions & 0 deletions test/unit/rewards/BatchPayments.test.js
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]));
});



});

0 comments on commit a0ab110

Please sign in to comment.