Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions lib/contracts/handlers/mtw-carrot-handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import { Chain } from '../../chains/constants';
import {
setupTestPublicClient,
setupTestWalletClient,
} from '../../../test/setup-test-clients';
import { mockAccount, testingUtils } from '../../../test/setup-tests';
import { MtwCarrotHandler } from './mtw-carrot-handler';
import { mtwCARROT } from '../abis/mainnet/mtwCARROT';
import { TOKENS_ADDRESSES, Token } from '../tokens';
import { isHash, padHex } from 'viem';

describe('MtwCarrotHandler', () => {
const contractTestingUtils = testingUtils.generateContractUtils(
mtwCARROT,
TOKENS_ADDRESSES[Token.mtwCARROT][Chain.Mainnet],
);
let handler: MtwCarrotHandler;

beforeEach(() => {
testingUtils.mockConnectedWallet([mockAccount], { chainId: Chain.Mainnet });
const walletClient = setupTestWalletClient(Chain.Mainnet);
const publicClient = setupTestPublicClient(Chain.Mainnet);

handler = new MtwCarrotHandler(Chain.Mainnet, walletClient, publicClient);
});

it('should get the allowance', async () => {
const mockAllowance = 100n;
contractTestingUtils.mockCall('allowance', [mockAllowance]);

const allowance = await handler.allowance(mockAccount, mockAccount);
expect(allowance).toEqual(mockAllowance);
});

it('should get the balance of the given address', async () => {
const mockBalance = 100n;
contractTestingUtils.mockCall('balanceOf', [mockBalance]);

const balance = await handler.balanceOf(mockAccount);
expect(balance).toEqual(mockBalance);
});

it('should get cliff duration', async () => {
const mockCliffDuration = 100n;
contractTestingUtils.mockCall('cliffDuration', [mockCliffDuration]);

const cliffDuration = await handler.cliffDuration();
expect(cliffDuration).toEqual(Number(mockCliffDuration));
});

it('should get user vestings', async () => {
const mockVestings = {
allVestings: [
{
amount: 100n,
unlockTimestamp: 100n,
},
],
nextClaimIndex: 1n,
};
contractTestingUtils.mockCall('getUserVestings', [
mockVestings.allVestings,
mockVestings.nextClaimIndex,
]);

const vestings = await handler.getUserVestings(mockAccount);
expect(vestings).toEqual(mockVestings);
});

it('should check if token is wrapper', async () => {
const mockIsWrapper = true;
contractTestingUtils.mockCall('isTokenWrapper', [mockIsWrapper]);

const isWrapper = await handler.isTokenWrapper();
expect(isWrapper).toEqual(mockIsWrapper);
});

it('should get the symbol', async () => {
const mockSymbol = 'mtwCARROT';
contractTestingUtils.mockCall('symbol', [mockSymbol]);

const symbol = await handler.symbol();
expect(symbol).toEqual(mockSymbol);
});

it('should get the token address this contract wraps', async () => {
const mockTokenAddress = padHex('0x', { size: 20 });
contractTestingUtils.mockCall('token', [mockTokenAddress]);

const tokenAddress = await handler.token();
expect(tokenAddress).toEqual(mockTokenAddress);
});

it('should get the underlying token', async () => {
const mockUnderlyingToken = padHex('0x', { size: 20 });
contractTestingUtils.mockCall('underlying', [mockUnderlyingToken]);

const underlyingToken = await handler.underlying();
expect(underlyingToken).toEqual(mockUnderlyingToken);
});

it('should get vesting data', async () => {
const mockVestingData = 100n;
contractTestingUtils.mockCall('vestingData', [mockVestingData]);

const vestingData = await handler.vestingData(mockAccount);
expect(vestingData).toEqual(mockVestingData);
});

it('should approve the usage of token for a spender', async () => {
contractTestingUtils.mockTransaction('approve');
const mockSpender = padHex('0x', { size: 20 });

const txHash = await handler.approve(mockAccount, mockSpender, 1n);
expect(isHash(txHash)).toBeTruthy();
});

it('should decrease allowance', async () => {
contractTestingUtils.mockTransaction('decreaseAllowance');
const mockSpender = padHex('0x', { size: 20 });

const txHash = await handler.decreaseAllowance(
mockAccount,
mockSpender,
1n,
);
expect(isHash(txHash)).toBeTruthy();
});

it('should increase allowance', async () => {
contractTestingUtils.mockTransaction('increaseAllowance');
const mockSpender = padHex('0x', { size: 20 });

const txHash = await handler.increaseAllowance(
mockAccount,
mockSpender,
1n,
);
expect(isHash(txHash)).toBeTruthy();
});

it('should recover ERC20 tokens', async () => {
contractTestingUtils.mockTransaction('recoverERC20');
const mockTokenAddress = padHex('0x', { size: 20 });
const mockTo = padHex('0x', { size: 20 });
const mockAmountToRecover = 1n;

const txHash = await handler.recoverERC20(
mockAccount,
mockTokenAddress,
mockTo,
mockAmountToRecover,
);
expect(isHash(txHash)).toBeTruthy();
});

it('should transfer tokens to another address', async () => {
contractTestingUtils.mockTransaction('transfer');
const mockTo = padHex('0x', { size: 20 });
const mockAmount = 1n;

const txHash = await handler.transfer(mockAccount, mockTo, mockAmount);
expect(isHash(txHash)).toBeTruthy();
});

// TODO: Not able to test overloads using `eth-testing`.

// it('should claim tokens', async () => {
// contractTestingUtils.mockTransaction('claim');
// const mockUser = padHex('0x', { size: 20 });
// const mockMaxClaimIndex = 1n;

// const txHash = await handler.claim(
// mockAccount,
// mockUser,
// mockMaxClaimIndex,
// );
// expect(isHash(txHash)).toBeTruthy();
// });

// it('should claim tokens without max claim index', async () => {
// contractTestingUtils.mockTransaction('claim');
// const mockUser = padHex('0x', { size: 20 });

// const txHash = await handler.claim(mockAccount, mockUser);
// expect(isHash(txHash)).toBeTruthy();
// });

// it("should get user's claimable amount", async () => {
// const mockClaimable = 100n;
// contractTestingUtils.mockCall('claimable', [mockClaimable], {
// callValues: [mockAccount],
// });

// const claimable = await handler.claimable(mockAccount);
// expect(claimable).toEqual(mockClaimable);
// });
});
6 changes: 5 additions & 1 deletion lib/contracts/handlers/mtw-carrot-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,16 @@ export class MtwCarrotHandler {
return this.getContract().read.allowance([owner, spender]);
}

// TODO: Not able to test overloads using `eth-testing`.
/* istanbul ignore next */
/**
* Retrieve the claimable amount for a user, optionally at a specific index.
*
* @param user The user's address.
* @param maxClaimIn, '0x123'dex The maximum index to check for claimable amount (optional).
* @returns The claimable amount for the user.
*/
public claimable(user: Address, maxClaimIndex?: bigint) {
public claimable(user: Address, maxClaimIndex?: bigint): Promise<bigint> {
if (maxClaimIndex !== undefined) {
return this.getContract().read.claimable([user, maxClaimIndex]);
}
Expand Down Expand Up @@ -177,6 +179,8 @@ export class MtwCarrotHandler {
});
}

// TODO: Not able to test overloads using `eth-testing`.
/* istanbul ignore next */
/**
* Claim tokens for a user.
*
Expand Down
4 changes: 3 additions & 1 deletion lib/contracts/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ export const TOKENS_ADDRESSES: {
};

export const TOKENS_PERMIT_VERSION: { [key in AnyToken]: string } = {
[Token.USDT]: '2',
// USDC does not support permit signatures (ERC20Permit).
// https://ethereum.stackexchange.com/questions/166254/usdt-contract-dont-have-erc20permit
[Token.USDT]: '',
// USDC does not support permit signatures (ERC20Permit).
[Token.USDC]: '',
// DAI does not support permit signatures (ERC20Permit).
Expand Down