Skip to content

Commit

Permalink
fix(kl-factory): base token ether tests (#1746)
Browse files Browse the repository at this point in the history
## What ❔

Adapt `ethers` tests so they work when usyng any token as `base` (using
`kl-factory` base token implementation).

## Why ❔

Improve test coverage.

Fixes: EVM-555

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [x] Tests for the changes have been added / updated.
- [x] Documentation comments have been added / updated.
- [x] Code has been formatted via `zk fmt` and `zk lint`.

---------

Signed-off-by: Danil <[email protected]>
Co-authored-by: Bence Haromi <[email protected]>
Co-authored-by: Lyova Potyomkin <[email protected]>
Co-authored-by: Stanislav Breadless <[email protected]>
Co-authored-by: Bence Haromi <[email protected]>
Co-authored-by: Javier Chatruc <[email protected]>
Co-authored-by: Francisco Krause Arnim <[email protected]>
Co-authored-by: Javier Rodríguez Chatruc <[email protected]>
Co-authored-by: Francisco Krause Arnim <[email protected]>
Co-authored-by: Santiago Pittella <[email protected]>
Co-authored-by: kelemeno <[email protected]>
Co-authored-by: Danil <[email protected]>
Co-authored-by: kelemeno <[email protected]>
Co-authored-by: Leandro Ferrigno <[email protected]>
Co-authored-by: Raid Ateir <[email protected]>
Co-authored-by: fborello-lambda <[email protected]>
Co-authored-by: mm <[email protected]>
Co-authored-by: Marcin M <[email protected]>
Co-authored-by: perekopskiy <[email protected]>
Co-authored-by: Alex Ostrovski <[email protected]>
Co-authored-by: Raid5594 <[email protected]>
  • Loading branch information
21 people authored Apr 24, 2024
1 parent 8848820 commit bf2d17d
Showing 1 changed file with 65 additions and 21 deletions.
86 changes: 65 additions & 21 deletions core/tests/ts-integration/tests/ether.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
*/

import { TestMaster } from '../src/index';
import { shouldChangeETHBalances, shouldOnlyTakeFee } from '../src/modifiers/balance-checker';
import {
shouldChangeETHBalances,
shouldChangeTokenBalances,
shouldOnlyTakeFee
} from '../src/modifiers/balance-checker';
import { checkReceipt } from '../src/modifiers/receipt-check';

import * as zksync from 'zksync-ethers';
import { BigNumber, Overrides } from 'ethers';
import { scaledGasPrice } from '../src/helpers';
import { ETH_ADDRESS_IN_CONTRACTS } from 'zksync-ethers/build/src/utils';

const ETH_ADDRESS = zksync.utils.ETH_ADDRESS;

Expand All @@ -17,37 +22,49 @@ describe('ETH token checks', () => {
let alice: zksync.Wallet;
let bob: zksync.Wallet;
let isETHBasedChain: boolean;
let l2EthTokenAddressNonBase: string; // Used only for base token implementation
let baseTokenAddress: string; // Used only for base token implementation

beforeAll(async () => {
testMaster = TestMaster.getInstance(__filename);
alice = testMaster.mainAccount();
bob = testMaster.newEmptyAccount();
// Get the information about base token address directly from the L2.
const baseTokenAddress = await alice._providerL2().getBaseTokenContractAddress();
baseTokenAddress = await alice._providerL2().getBaseTokenContractAddress();
isETHBasedChain = baseTokenAddress == zksync.utils.ETH_ADDRESS_IN_CONTRACTS;
console.log(`Starting checks for base token: ${baseTokenAddress} isEthBasedChain: ${isETHBasedChain}`);
l2EthTokenAddressNonBase = await alice.l2TokenAddress(zksync.utils.ETH_ADDRESS_IN_CONTRACTS);
});

test('Can perform a deposit', async () => {
if (!isETHBasedChain) {
// TODO(EVM-555): Currently this test is not working for non-eth based chains.
return;
// Approving the needed allowance previously so we don't do it inside of the deposit.
// This prevents the deposit fee from being miscalculated.
const l1MaxBaseTokenBalance = await alice.getBalanceL1(baseTokenAddress);
await (await alice.approveERC20(baseTokenAddress, l1MaxBaseTokenBalance)).wait();
}
const amount = 1; // 1 wei is enough.
const gasPrice = scaledGasPrice(alice);

// Unfortunately, since fee is taken in ETH, we must calculate the L1 ETH balance diff explicitly.
const l1EthBalanceBefore = await alice.getBalanceL1();
const l2ethBalanceChange = await shouldChangeETHBalances([{ wallet: alice, change: amount }], {
l1ToL2: true
});
const l2ethBalanceChange = isETHBasedChain
? await shouldChangeETHBalances([{ wallet: alice, change: amount }], {
l1ToL2: true
})
: await shouldChangeTokenBalances(l2EthTokenAddressNonBase, [{ wallet: alice, change: amount }]);

// Variables used only for base token implementation
const l1BaseTokenBalanceBefore = await alice.getBalanceL1(baseTokenAddress);
const l2BaseTokenBalanceBefore = await alice.getBalance(); // Base token balance on L2

const gasPerPubdataByte = zksync.utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT;
const isBaseToken = isETHBasedChain;

const l2GasLimit = await zksync.utils.estimateDefaultBridgeDepositL2Gas(
alice.providerL1!,
alice.provider,
ETH_ADDRESS,
isETHBasedChain ? ETH_ADDRESS : ETH_ADDRESS_IN_CONTRACTS, // ToDo: fix sdk so if it receives ETH_ADDRESS it should use ETH_ADDRESS_IN_CONTRACTS
amount,
alice.address,
alice.address,
Expand All @@ -65,8 +82,7 @@ describe('ETH token checks', () => {
amount,
gasPerPubdataByte,
l2GasLimit,
approveBaseERC20: true,
approveERC20: true,
approveERC20: isETHBasedChain ? true : false,
approveBaseOverrides: {
gasPrice
},
Expand All @@ -80,10 +96,30 @@ describe('ETH token checks', () => {
.then((op) => op.waitL1Commit())
.then(async (receipt) => {
const l1GasFee = receipt.gasUsed.mul(receipt.effectiveGasPrice);
if (!isETHBasedChain) {
return l1GasFee;
}
return l1GasFee.add(expectedL2Costs);
});

const l1EthBalanceAfter = await alice.getBalanceL1();
expect(l1EthBalanceBefore.sub(depositFee).sub(l1EthBalanceAfter)).bnToBeEq(amount);
if (isETHBasedChain) {
expect(l1EthBalanceBefore.sub(depositFee).sub(l1EthBalanceAfter)).bnToBeEq(amount);
} else {
// Base token checks
const l1BaseTokenBalanceAfter = await alice.getBalanceL1(baseTokenAddress);
expect(l1BaseTokenBalanceBefore).bnToBeEq(l1BaseTokenBalanceAfter.add(expectedL2Costs));

const l2BaseTokenBalanceAfter = await alice.getBalance();
expect(l1EthBalanceBefore).bnToBeEq(l1EthBalanceAfter.add(depositFee).add(amount));

// L2 balance for the base token increases do to some "overminting" of the base token
// We verify that the amount reduced on L1 is greater than the amount increased on L2
// so that we are not generating tokens out of thin air
const l1BaseTokenBalanceDiff = l1BaseTokenBalanceBefore.sub(l1BaseTokenBalanceAfter);
const l2BaseTokenBalanceDiff = l2BaseTokenBalanceAfter.sub(l2BaseTokenBalanceBefore);
expect(l1BaseTokenBalanceDiff).bnToBeGt(l2BaseTokenBalanceDiff);
}
});

test('Can perform a transfer (legacy pre EIP-155)', async () => {
Expand Down Expand Up @@ -215,8 +251,14 @@ describe('ETH token checks', () => {
}
const amount = 1;

const l2ethBalanceChange = await shouldChangeETHBalances([{ wallet: alice, change: -amount }]);
const withdrawalPromise = alice.withdraw({ token: ETH_ADDRESS, amount });
const l2ethBalanceChange = isETHBasedChain
? await shouldChangeETHBalances([{ wallet: alice, change: -amount }])
: await shouldChangeTokenBalances(l2EthTokenAddressNonBase, [{ wallet: alice, change: -amount }]);

const withdrawalPromise = alice.withdraw({
token: isETHBasedChain ? ETH_ADDRESS : l2EthTokenAddressNonBase,
amount
});
await expect(withdrawalPromise).toBeAccepted([l2ethBalanceChange]);
const withdrawalTx = await withdrawalPromise;
await withdrawalTx.waitFinalize();
Expand All @@ -230,24 +272,26 @@ describe('ETH token checks', () => {

test('Can perform a deposit with precalculated max value', async () => {
if (!isETHBasedChain) {
// TODO(EVM-555): Currently this test is not working for non-eth based chains.
return;
const baseTokenDetails = testMaster.environment().baseToken;
const maxAmount = await alice.getBalanceL1(baseTokenDetails.l1Address);
await (await alice.approveERC20(process.env.CONTRACTS_BASE_TOKEN_ADDR!, maxAmount)).wait();
const baseTokenMaxAmount = await alice.getBalanceL1(baseTokenDetails.l1Address);
await (await alice.approveERC20(baseTokenAddress, baseTokenMaxAmount)).wait();
}

const depositFee = await alice.getFullRequiredDepositFee({
token: ETH_ADDRESS
});
const l1Fee = depositFee.l1GasLimit.mul(depositFee.maxFeePerGas! || depositFee.gasPrice!);
const l2Fee = depositFee.baseCost;
const maxAmount = (await alice.getBalanceL1()).sub(l1Fee).sub(l2Fee);
const maxAmount = isETHBasedChain
? (await alice.getBalanceL1()).sub(l1Fee).sub(l2Fee)
: (await alice.getBalanceL1()).sub(l1Fee); // l2Fee is paid in base token

// Approving the needed allowance to ensure that the user has enough funds.
const l2ethBalanceChange = await shouldChangeETHBalances([{ wallet: alice, change: maxAmount }], {
l1ToL2: true
});
const l2ethBalanceChange = isETHBasedChain
? await shouldChangeETHBalances([{ wallet: alice, change: maxAmount }], {
l1ToL2: true
})
: await shouldChangeTokenBalances(l2EthTokenAddressNonBase, [{ wallet: alice, change: maxAmount }]);

const overrides: Overrides = depositFee.gasPrice
? { gasPrice: depositFee.gasPrice }
Expand Down

0 comments on commit bf2d17d

Please sign in to comment.