Skip to content

Commit

Permalink
added WIP support for the redemption of multiple tokens from a single…
Browse files Browse the repository at this point in the history
… contract
  • Loading branch information
gtaschuk committed Nov 3, 2020
1 parent 4b8d8c0 commit 023a736
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 76 deletions.
67 changes: 40 additions & 27 deletions merkle/contracts/MerkleRedeem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,52 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MerkleRedeem is Ownable {

IERC20 public token;
//IERC20 public token;

event Claimed(address _claimant, uint256 _balance);
event Claimed(address _erc20, address _claimant, uint256 _balance);

// Recorded weeks
mapping(uint => bytes32) public weekMerkleRoots;
mapping(uint => mapping(address => bool)) public claimed;
// token => week => user
mapping(address => mapping(uint => bytes32)) public weekMerkleRoots;
// token => week => user
mapping(address => mapping(uint => mapping(address => bool))) public claimed;

constructor(
address _token
address[] memory _tokens
) public {
token = IERC20(_token);
// TODO - put these in a set and add a modifier to check token is in contract
//token = IERC20(_token);
}

function disburse(
address _liquidityProvider,
address _erc20,
address _user,
uint _balance
)
private
{
IERC20 token = IERC20(_erc20);
if (_balance > 0) {
emit Claimed(_liquidityProvider, _balance);
require(token.transfer(_liquidityProvider, _balance), "ERR_TRANSFER_FAILED");
emit Claimed(_erc20, _user, _balance);
require(token.transfer(_user, _balance), "ERR_TRANSFER_FAILED");
}
}

// you can trigger a claim for another user
function claimWeek(
address _liquidityProvider,
address _user,
address _erc20,
uint _week,
uint _claimedBalance,
bytes32[] memory _merkleProof
)
public
{
require(!claimed[_week][_liquidityProvider]);
require(verifyClaim(_liquidityProvider, _week, _claimedBalance, _merkleProof), 'Incorrect merkle proof');
require(!claimed[_erc20][_week][_user]);
require(verifyClaim(_user, _erc20, _week, _claimedBalance, _merkleProof), 'Incorrect merkle proof');

claimed[_week][_liquidityProvider] = true;
disburse(_liquidityProvider, _claimedBalance);
claimed[_erc20][_week][_user] = true;
disburse(_erc20, _user, _claimedBalance);
}

struct Claim {
Expand All @@ -55,7 +62,8 @@ contract MerkleRedeem is Ownable {
}

function claimWeeks(
address _liquidityProvider,
address _user,
address _erc20,
Claim[] memory claims
)
public
Expand All @@ -65,17 +73,18 @@ contract MerkleRedeem is Ownable {
for(uint i = 0; i < claims.length; i++) {
claim = claims[i];

require(!claimed[claim.week][_liquidityProvider]);
require(verifyClaim(_liquidityProvider, claim.week, claim.balance, claim.merkleProof), 'Incorrect merkle proof');
require(!claimed[_erc20][claim.week][_user]);
require(verifyClaim(_user,_erc20, claim.week, claim.balance, claim.merkleProof), 'Incorrect merkle proof');

totalBalance += claim.balance;
claimed[claim.week][_liquidityProvider] = true;
claimed[_erc20][claim.week][_user] = true;
}
disburse(_liquidityProvider, totalBalance);
disburse(_erc20, _user, totalBalance);
}

function claimStatus(
address _liquidityProvider,
address _user,
address _erc20,
uint _begin,
uint _end
)
Expand All @@ -86,12 +95,13 @@ contract MerkleRedeem is Ownable {
uint size = 1 + _end - _begin;
bool[] memory arr = new bool[](size);
for(uint i = 0; i < size; i++) {
arr[i] = claimed[_begin + i][_liquidityProvider];
arr[i] = claimed[_erc20][_begin + i][_user];
}
return arr;
}

function merkleRoots(
address _erc20,
uint _begin,
uint _end
)
Expand All @@ -102,13 +112,14 @@ contract MerkleRedeem is Ownable {
uint size = 1 + _end - _begin;
bytes32[] memory arr = new bytes32[](size);
for(uint i = 0; i < size; i++) {
arr[i] = weekMerkleRoots[_begin + i];
arr[i] = weekMerkleRoots[_erc20][_begin + i];
}
return arr;
}

function verifyClaim(
address _liquidityProvider,
address _user,
address _erc20,
uint _week,
uint _claimedBalance,
bytes32[] memory _merkleProof
Expand All @@ -117,21 +128,23 @@ contract MerkleRedeem is Ownable {
view
returns (bool valid)
{
bytes32 leaf = keccak256(abi.encodePacked(_liquidityProvider, _claimedBalance));
return MerkleProof.verify(_merkleProof, weekMerkleRoots[_week], leaf);
bytes32 leaf = keccak256(abi.encodePacked(_user, _claimedBalance));
return MerkleProof.verify(_merkleProof, weekMerkleRoots[_erc20][_week], leaf);
}

function seedAllocations(
address _erc20,
uint _week,
bytes32 _merkleRoot,
uint _totalAllocation
)
external
onlyOwner
{
require(weekMerkleRoots[_week] == bytes32(0), "cannot rewrite merkle root");
weekMerkleRoots[_week] = _merkleRoot;
require(weekMerkleRoots[_erc20][_week] == bytes32(0), "cannot rewrite merkle root");
weekMerkleRoots[_erc20][_week] = _merkleRoot;

IERC20 token = IERC20(_erc20);
require(token.transferFrom(msg.sender, address(this), _totalAllocation), "ERR_TRANSFER_FAILED");
}
}
2 changes: 1 addition & 1 deletion merkle/migrations/2_deploy_redeem.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = (deployer, network, accounts) => {
const token = await TToken.deployed();
await token.mint(admin, utils.toWei("145000"));

await deployer.deploy(Redeem, token.address);
await deployer.deploy(Redeem, [token.address]);
const redeem = await Redeem.deployed();

await token.transfer(redeem.address, utils.toWei("20000"));
Expand Down
17 changes: 10 additions & 7 deletions merkle/test/high-volume-redeem.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract("MerkleRedeem - High Volume", accounts => {
await tbal.mint(admin, utils.toWei("1450000"));
TBAL = tbal.address;

redeem = await Redeem.new(TBAL);
redeem = await Redeem.new([TBAL]);
REDEEM = redeem.address;

await tbal.approve(REDEEM, MAX);
Expand All @@ -42,11 +42,12 @@ contract("MerkleRedeem - High Volume", accounts => {
const merkleTree = new MerkleTree(elements);
const root = merkleTree.getHexRoot();

await redeem.seedAllocations(1, root, utils.toWei("145000"));
await redeem.seedAllocations(TBAL, 1, root, utils.toWei("145000"));

const proof36 = merkleTree.getHexProof(elements[36]);
let result = await redeem.verifyClaim(
addresses[36],
TBAL,
1,
utils.toWei("360"),
proof36
Expand All @@ -56,6 +57,7 @@ contract("MerkleRedeem - High Volume", accounts => {
const proof48 = merkleTree.getHexProof(elements[48]);
result = await redeem.verifyClaim(
addresses[48],
TBAL,
1,
utils.toWei("480"),
proof48
Expand Down Expand Up @@ -97,25 +99,25 @@ contract("MerkleRedeem - High Volume", accounts => {
beforeEach(async () => {
let lastBlock = await web3.eth.getBlock("latest");

await redeem.seedAllocations(1, root1, utils.toWei("145000"));
await redeem.seedAllocations(TBAL, 1, root1, utils.toWei("145000"));

await increaseTime(7);
lastBlock = await web3.eth.getBlock("latest");
let lastBlockHash =
"0xb6801f31f93d990dfe65d67d3479c3853d5fafd7a7f2b8fad9e68084d8d409e0"; // set this manually to simplify testing
await redeem.seedAllocations(2, root2, utils.toWei("145000"));
await redeem.seedAllocations(TBAL, 2, root2, utils.toWei("145000"));

await increaseTime(7);
lastBlock = await web3.eth.getBlock("latest");
await redeem.seedAllocations(3, root3, utils.toWei("145000"));
await redeem.seedAllocations(TBAL, 3, root3, utils.toWei("145000"));

await increaseTime(7);
lastBlock = await web3.eth.getBlock("latest");
await redeem.seedAllocations(4, root4, utils.toWei("145000"));
await redeem.seedAllocations(TBAL, 4, root4, utils.toWei("145000"));

await increaseTime(7);
lastBlock = await web3.eth.getBlock("latest");
await redeem.seedAllocations(5, root5, utils.toWei("145000"));
await redeem.seedAllocations(TBAL, 5, root5, utils.toWei("145000"));
});

it("Allows the user to claim multiple weeks at once", async () => {
Expand All @@ -129,6 +131,7 @@ contract("MerkleRedeem - High Volume", accounts => {

await redeem.claimWeeks(
accounts[1],
TBAL,
[
[1, claimBalance1, proof1],
[2, claimBalance2, proof2],
Expand Down
Loading

1 comment on commit 023a736

@yvettep321
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank You

Please sign in to comment.