Skip to content

Commit

Permalink
feat(test-permit): test claim and lock permit
Browse files Browse the repository at this point in the history
  • Loading branch information
0xhafa committed Feb 23, 2023
1 parent 05d814c commit 57ae6c9
Showing 1 changed file with 122 additions and 22 deletions.
144 changes: 122 additions & 22 deletions test/Relocker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import {
callAndReturnEvent,
getPermitSignature,
impersonateAddressAndReturnSigner,
validateEvent,
} from './helpers';
Expand All @@ -24,15 +25,29 @@ type Claims = {
merkleProof: string[];
}[];

describe('Relocker', () => {
type Distribution = {
token: string;
merkleRoot: string;
proof: string;
};

describe('Relocker', function () {
let admin: SignerWithAddress;
let user: SignerWithAddress;
let actualUser: SignerWithAddress;
let mockUser: SignerWithAddress;
let rlBtrfly: RLBTRFLY;
let btrfly: BTRFLYV2;
let rewardDistributor: RewardDistributor;
let btrflyDistribution: Distribution;
let relocker: Relocker;
let userBtrflyClaim: Claims;
let mockUserBtrflyClaim: Claims;
let btrflyAmount: string;
let snapshotId: number;

const arbitraryProof = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes('ARBITRARY_PROOF')
);

before(async function () {
({ admin } = this);
Expand All @@ -51,18 +66,15 @@ describe('Relocker', () => {
'RewardDistributor',
'0xd7807E5752B368A6a64b76828Aaff0750522a76E'
)) as RewardDistributor;

//get latest distribution
const response = await fetch('https://raw.githubusercontent.com/redacted-cartel/distributions/master/protocol-v2/latest/btrfly.json');
const latestDistribution = await response.json();

//get merkle tree from latest distribution
const btrflyTree = new BalanceTree(latestDistribution);

//user as the first account in latestDistribution with no claimed rewards
//actualUser as the first account in latestDistribution with no claimed rewards
for (const item of latestDistribution) {
if ((await rewardDistributor.claimed(btrfly.address, item.account)).eq(0)) {
user = await impersonateAddressAndReturnSigner(
actualUser = await impersonateAddressAndReturnSigner(
admin,
item.account
);
Expand All @@ -71,12 +83,47 @@ describe('Relocker', () => {
}
}

//get user's merkle proof
[mockUser] = await ethers.getSigners();

//append actualUser account to latest distribution
latestDistribution.push({
account: mockUser.address,
amount: btrflyAmount,
});

//get merkle tree from latest distribution
const btrflyTree = new BalanceTree(latestDistribution);

//impersonate reward distributor owner
const rewardDistributorOwner = await impersonateAddressAndReturnSigner(
admin,
await rewardDistributor.owner()
);

btrflyDistribution = {
token: btrfly.address,
merkleRoot: btrflyTree.getHexRoot(),
proof: arbitraryProof,
};

//update reward distributor with latest distribution
await rewardDistributor
.connect(rewardDistributorOwner)
.updateRewardsMetadata([btrflyDistribution]);

//get actualUser's merkle proof
userBtrflyClaim = [{
token: btrfly.address,
account: user.address,
account: actualUser.address,
amount: btrflyAmount,
merkleProof: btrflyTree.getProof(actualUser.address, BigNumber.from(btrflyAmount)),
}];

mockUserBtrflyClaim = [{
token: btrfly.address,
account: mockUser.address,
amount: btrflyAmount,
merkleProof: btrflyTree.getProof(user.address, BigNumber.from(btrflyAmount)),
merkleProof: btrflyTree.getProof(mockUser.address, BigNumber.from(btrflyAmount)),
}];
});

Expand All @@ -90,9 +137,11 @@ describe('Relocker', () => {
rlBtrfly.address,
rewardDistributor.address
);

snapshotId = snapshotId ?? await ethers.provider.send('evm_snapshot', []);
});

describe('constructor', () => {
describe('constructor', function () {
it('Should set up contract state', async () => {
const btrflyAddress = await relocker.btrfly();
const rlBtrflyAddress = await relocker.rlBtrfly();
Expand All @@ -104,37 +153,88 @@ describe('Relocker', () => {
});
});

describe('claimAndLock', () => {
describe('claimAndLock', function () {
it('should revert on zero amount', async () => {
const amount = 0;

await expect(relocker.claimAndLock(userBtrflyClaim, amount)).to.be.revertedWith(
await expect(relocker.claimAndLock(userBtrflyClaim, amount, "0x")).to.be.revertedWith(
'ZeroAmount()'
);
});

it('should claim and lock btrfly', async () => {
const userRLBalanceBefore = await rlBtrfly.lockedBalanceOf(user.address);
it('should revert on invalid permit signature', async () => {
//invalid deadline
const { v, r, s } = await getPermitSignature(
mockUser,
btrfly,
relocker.address,
BigNumber.from(btrflyAmount),
ethers.constants.Zero
);

const permitParams = ethers.utils.defaultAbiCoder.encode(
["address", "address", "uint256", "uint256", "uint8", "bytes32", "bytes32"],
[mockUser.address, relocker.address, btrflyAmount, ethers.constants.Zero, v, r, s]
);

await expect(relocker.claimAndLock(mockUserBtrflyClaim, btrflyAmount, permitParams)).to.be.revertedWith("PermitFailed()");
});

it('should claim and lock btrfly using permit', async () => {
const userRLBalanceBefore = await rlBtrfly.lockedBalanceOf(mockUser.address);
const expectedUserRLBalanceAfter = userRLBalanceBefore.add(btrflyAmount);

await btrfly.connect(user).approve(relocker.address, btrflyAmount);
const { v, r, s } = await getPermitSignature(
mockUser,
btrfly,
relocker.address,
BigNumber.from(btrflyAmount),
ethers.constants.MaxUint256
)

const permitParams = ethers.utils.defaultAbiCoder.encode(
["address", "address", "uint256", "uint256", "uint8", "bytes32", "bytes32"],
[mockUser.address, relocker.address, btrflyAmount, ethers.constants.MaxUint256, v, r, s]
);

const relockEvent = await callAndReturnEvent(
relocker.connect(user).claimAndLock,
[userBtrflyClaim, btrflyAmount]
relocker.connect(mockUser).claimAndLock,
[mockUserBtrflyClaim, btrflyAmount, permitParams]
);

validateEvent(relockEvent, 'Relock(address,uint256)', {
account: user.address,
account: mockUser.address,
amount: btrflyAmount,
});

const userRLBalanceAfter = await rlBtrfly.lockedBalanceOf(user.address);
const userRLBalanceAfter = await rlBtrfly.lockedBalanceOf(mockUser.address);
const userRLBalanceIncrease = userRLBalanceAfter.sub(userRLBalanceBefore);
expect(userRLBalanceAfter).to.equal(expectedUserRLBalanceAfter);
expect(userRLBalanceIncrease).to.equal(btrflyAmount);

await ethers.provider.send('evm_revert', [snapshotId]);
});

it('should claim and lock btrfly using approve', async () => {
const userRLBalanceBefore = await rlBtrfly.lockedBalanceOf(actualUser.address);
const expectedUserRLBalanceAfter = userRLBalanceBefore.add(btrflyAmount);
await btrfly.connect(actualUser).approve(relocker.address, btrflyAmount);

const relockEvent = await callAndReturnEvent(
relocker.connect(actualUser).claimAndLock,
[userBtrflyClaim, btrflyAmount, "0x"],
);

validateEvent(relockEvent, 'Relock(address,uint256)', {
account: actualUser.address,
amount: btrflyAmount,
});

const userRLBalanceAfter = await rlBtrfly.lockedBalanceOf(actualUser.address);
const userRLBalanceIncrease = userRLBalanceAfter.sub(userRLBalanceBefore);
expect(userRLBalanceAfter).to.equal(expectedUserRLBalanceAfter);
expect(userRLBalanceIncrease).to.equal(btrflyAmount);

await ethers.provider.send('evm_revert', [snapshotId]);
});
});
});

0 comments on commit 57ae6c9

Please sign in to comment.